38c6152884
When installing new code, we need to ensure the mutator is stopped for a variety of reasons. Right now we only need to distuinguish mutator and background compiler when installing code: The mutator can install code without any synchronization whereas the bg compiler needs to get the mutator to a safepoint. Yet once all isolates within one isolate group share a heap, a mutator might need to stop all other mutators before installing code (since they operate on pages on which we flip page protection bits) This CL adds IsolateGroup::RunWithStoppedMutators which will get other mutators to a safepoint (if there are multiple or we are on a bg compiler thread). Along with this we add a read-write lock and use it for the protection of the IsolateGroup::isolate_: While we make assumptions about the number of isolates in a group we force all pending additions of new isolates to wait. Later on this will also be used to allow iterating the list of isolates during GC and prevent new isolates from being added at the same time. Issue https://github.com/dart-lang/sdk/issues/36097 Change-Id: I6e761fa51d36b2f2b4b67995cac954898ce7fd69 Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-product-x64-try,vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-android-release-arm-try,vm-dartkb-linux-release-x64-abi-try,vm-kernel-precomp-bare-linux-release-x64-try,vm-kernel-precomp-mac-debug-simarm_x64-try,vm-kernel-precomp-win-release-x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/116767 Commit-Queue: Martin Kustermann <kustermann@google.com> Reviewed-by: Alexander Aprelev <aam@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com>
110 lines
3.6 KiB
C++
110 lines
3.6 KiB
C++
// Copyright (c) 2016, 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/globals.h"
|
|
#if defined(TARGET_ARCH_DBC)
|
|
|
|
#include "vm/code_patcher.h"
|
|
#include "vm/cpu.h"
|
|
#include "vm/debugger.h"
|
|
#include "vm/instructions.h"
|
|
#include "vm/stub_code.h"
|
|
|
|
namespace dart {
|
|
|
|
#ifndef PRODUCT
|
|
|
|
RawCode* CodeBreakpoint::OrigStubAddress() const {
|
|
return reinterpret_cast<RawCode*>(static_cast<uintptr_t>(saved_value_));
|
|
}
|
|
|
|
static Instr* CallInstructionFromReturnAddress(uword pc) {
|
|
return reinterpret_cast<Instr*>(pc) - 1;
|
|
}
|
|
|
|
static Instr* FastSmiInstructionFromReturnAddress(uword pc) {
|
|
return reinterpret_cast<Instr*>(pc) - 2;
|
|
}
|
|
|
|
void CodeBreakpoint::PatchCode() {
|
|
ASSERT(!is_enabled_);
|
|
auto thread = Thread::Current();
|
|
auto zone = thread->zone();
|
|
const Code& code = Code::Handle(zone, code_);
|
|
const Instructions& instrs = Instructions::Handle(zone, code.instructions());
|
|
thread->isolate_group()->RunWithStoppedMutators([&]() {
|
|
WritableInstructionsScope writable(instrs.PayloadStart(), instrs.Size());
|
|
saved_value_ = *CallInstructionFromReturnAddress(pc_);
|
|
switch (breakpoint_kind_) {
|
|
case RawPcDescriptors::kIcCall:
|
|
case RawPcDescriptors::kUnoptStaticCall: {
|
|
// DebugBreak has an A operand matching the call it replaces.
|
|
// This ensures that Return instructions continue to work - as they
|
|
// look at calls to figure out how many arguments to drop.
|
|
*CallInstructionFromReturnAddress(pc_) = SimulatorBytecode::Encode(
|
|
SimulatorBytecode::kDebugBreak,
|
|
SimulatorBytecode::DecodeArgc(saved_value_), 0, 0);
|
|
break;
|
|
}
|
|
|
|
case RawPcDescriptors::kRuntimeCall: {
|
|
*CallInstructionFromReturnAddress(pc_) = SimulatorBytecode::kDebugBreak;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
|
|
// If this call is the fall-through for a fast Smi op, also disable the fast
|
|
// Smi op.
|
|
if ((SimulatorBytecode::DecodeOpcode(saved_value_) ==
|
|
SimulatorBytecode::kInstanceCall2) &&
|
|
SimulatorBytecode::IsFastSmiOpcode(
|
|
*FastSmiInstructionFromReturnAddress(pc_))) {
|
|
saved_value_fastsmi_ = *FastSmiInstructionFromReturnAddress(pc_);
|
|
*FastSmiInstructionFromReturnAddress(pc_) =
|
|
SimulatorBytecode::Encode(SimulatorBytecode::kNop, 0, 0, 0);
|
|
} else {
|
|
saved_value_fastsmi_ = SimulatorBytecode::kTrap;
|
|
}
|
|
});
|
|
is_enabled_ = true;
|
|
}
|
|
|
|
void CodeBreakpoint::RestoreCode() {
|
|
ASSERT(is_enabled_);
|
|
auto thread = Thread::Current();
|
|
auto zone = thread->zone();
|
|
const Code& code = Code::Handle(zone, code_);
|
|
const Instructions& instrs = Instructions::Handle(zone, code.instructions());
|
|
thread->isolate_group()->RunWithStoppedMutators([&]() {
|
|
WritableInstructionsScope writable(instrs.PayloadStart(), instrs.Size());
|
|
switch (breakpoint_kind_) {
|
|
case RawPcDescriptors::kIcCall:
|
|
case RawPcDescriptors::kUnoptStaticCall:
|
|
case RawPcDescriptors::kRuntimeCall: {
|
|
*CallInstructionFromReturnAddress(pc_) = saved_value_;
|
|
break;
|
|
}
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
|
|
if (saved_value_fastsmi_ != SimulatorBytecode::kTrap) {
|
|
Instr current_instr = *FastSmiInstructionFromReturnAddress(pc_);
|
|
ASSERT(SimulatorBytecode::DecodeOpcode(current_instr) ==
|
|
SimulatorBytecode::kNop);
|
|
*FastSmiInstructionFromReturnAddress(pc_) = saved_value_fastsmi_;
|
|
}
|
|
});
|
|
is_enabled_ = false;
|
|
}
|
|
|
|
#endif // !PRODUCT
|
|
|
|
} // namespace dart
|
|
|
|
#endif // defined TARGET_ARCH_DBC
|