blob: 2ffe47d77255e674e3a121e51e3d6a5e42ee24e5 [file] [log] [blame] [edit]
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/heap/weak_code.h"
#include "platform/assert.h"
#include "vm/code_patcher.h"
#include "vm/hash_table.h"
#include "vm/object.h"
#include "vm/runtime_entry.h"
#include "vm/stack_frame.h"
namespace dart {
class CodeTraits {
public:
static const char* Name() { return "CodeTraits"; }
static bool ReportStats() { return false; }
static bool IsMatch(const Object& a, const Object& b) {
return a.ptr() == b.ptr();
}
static uword Hash(const Object& key) { return Code::Cast(key).Hash(); }
};
typedef UnorderedHashSet<CodeTraits, WeakArrayStorageTraits> WeakCodeSet;
bool WeakCodeReferences::HasCodes() const {
return !array_.IsNull() && (array_.Length() > 0);
}
void WeakCodeReferences::Register(const Code& value) {
WeakCodeSet set(array_.IsNull() ? HashTables::New<WeakCodeSet>(4, Heap::kOld)
: array_.ptr());
set.Insert(value);
UpdateArrayTo(set.Release());
}
void WeakCodeReferences::DisableCode(bool are_mutators_stopped) {
#if defined(DART_PRECOMPILED_RUNTIME)
ASSERT(array_.IsNull());
return;
#else
// Ensure mutators see empty code_objects only after code was deoptimized.
DEBUG_ASSERT(
IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter());
if (array_.IsNull()) {
return;
}
WeakCodeSet set(array_.ptr());
auto isolate_group = IsolateGroup::Current();
auto disable_code_fun = [&]() {
Code& code = Code::Handle();
isolate_group->ForEachIsolate(
[&](Isolate* isolate) {
auto mutator_thread = isolate->mutator_thread();
if (mutator_thread == nullptr) {
return;
}
DartFrameIterator iterator(
mutator_thread, StackFrameIterator::kAllowCrossThreadIteration);
StackFrame* frame = iterator.NextFrame();
while (frame != nullptr) {
if (!frame->is_interpreted()) {
code = frame->LookupDartCode();
if (set.ContainsKey(code)) {
ReportDeoptimization(code);
DeoptimizeAt(mutator_thread, code, frame);
}
}
frame = iterator.NextFrame();
}
},
/*at_safepoint=*/true);
// Switch functions that use dependent code to unoptimized code.
Object& owner = Object::Handle();
Function& function = Function::Handle();
WeakCodeSet::Iterator it(&set);
while (it.MoveNext()) {
code ^= set.GetKey(it.Current());
if (code.IsNull()) {
// Code was garbage collected already.
continue;
}
owner = code.owner();
if (owner.IsFunction()) {
function ^= owner.ptr();
} else if (owner.IsClass()) {
Class& cls = Class::Handle();
cls ^= owner.ptr();
cls.DisableAllocationStub();
continue;
} else if (owner.IsNull()) {
code.Print();
continue;
}
// Only optimized code can make dependencies (assumptions) about CHA /
// field guards and might need to be deoptimized if those assumptions no
// longer hold.
// See similar assertions when code gets registered in
// `Field::RegisterDependentCode` and `Class::RegisterCHACode`.
ASSERT(code.is_optimized());
ASSERT(function.unoptimized_code() != code.ptr());
// If function uses dependent code switch it to unoptimized.
if (function.CurrentCode() == code.ptr()) {
ReportSwitchingCode(code);
function.SwitchToUnoptimizedCode();
} else {
// Make non-OSR code non-entrant.
if (!code.IsDisabled()) {
ReportSwitchingCode(code);
code.DisableDartCode();
}
}
}
UpdateArrayTo(WeakArray::Handle());
};
// Deoptimize stacks and disable code (with mutators stopped if they are not
// stopped yet).
if (are_mutators_stopped) {
disable_code_fun();
} else {
isolate_group->RunWithStoppedMutators(disable_code_fun);
}
set.Release();
#endif // defined(DART_PRECOMPILED_RUNTIME)
}
} // namespace dart