Version 1.1.0-dev.5.11
svn merge -c 31812 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
Review URL: https://codereview.chromium.org//135053007
git-svn-id: http://dart.googlecode.com/svn/trunk@31818 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 980eb89..2adad1e 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -104,6 +104,32 @@
object_pool_.Add(Object::null_object(), Heap::kOld);
patchable_pool_entries_.Add(kNotPatchable);
}
+
+ // Create fixed object pool entries for debugger stubs.
+ if (StubCode::BreakpointStatic_entry() != NULL) {
+ intptr_t index =
+ FindExternalLabel(&StubCode::BreakpointStaticLabel(), kNotPatchable);
+ ASSERT(index == kBreakpointStaticCPIndex);
+ } else {
+ object_pool_.Add(Object::null_object(), Heap::kOld);
+ patchable_pool_entries_.Add(kNotPatchable);
+ }
+ if (StubCode::BreakpointDynamic_entry() != NULL) {
+ intptr_t index =
+ FindExternalLabel(&StubCode::BreakpointDynamicLabel(), kNotPatchable);
+ ASSERT(index == kBreakpointDynamicCPIndex);
+ } else {
+ object_pool_.Add(Object::null_object(), Heap::kOld);
+ patchable_pool_entries_.Add(kNotPatchable);
+ }
+ if (StubCode::BreakpointRuntime_entry() != NULL) {
+ intptr_t index =
+ FindExternalLabel(&StubCode::BreakpointRuntimeLabel(), kNotPatchable);
+ ASSERT(index == kBreakpointRuntimeCPIndex);
+ } else {
+ object_pool_.Add(Object::null_object(), Heap::kOld);
+ patchable_pool_entries_.Add(kNotPatchable);
+ }
}
}
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index eca8d26..d59548a 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -767,6 +767,11 @@
buffer_.FinalizeInstructions(region);
}
+ // Index of constant pool entries pointing to debugger stubs.
+ static const int kBreakpointStaticCPIndex = 5;
+ static const int kBreakpointDynamicCPIndex = 6;
+ static const int kBreakpointRuntimeCPIndex = 7;
+
void LoadPoolPointer(Register pp);
// Set up a Dart frame on entry with a frame pointer and PC information to
diff --git a/runtime/vm/code_patcher.h b/runtime/vm/code_patcher.h
index 4fcc1a4..0a7410f 100644
--- a/runtime/vm/code_patcher.h
+++ b/runtime/vm/code_patcher.h
@@ -76,6 +76,9 @@
static void InsertCallAt(uword start, uword target);
static RawObject* GetEdgeCounterAt(uword pc, const Code& code);
+
+ static int32_t GetPoolOffsetAt(uword return_address);
+ static void SetPoolOffsetAt(uword return_address, int32_t offset);
};
} // namespace dart
diff --git a/runtime/vm/code_patcher_arm.cc b/runtime/vm/code_patcher_arm.cc
index 759bf54..6a769cd 100644
--- a/runtime/vm/code_patcher_arm.cc
+++ b/runtime/vm/code_patcher_arm.cc
@@ -46,6 +46,17 @@
}
+int32_t CodePatcher::GetPoolOffsetAt(uword return_address) {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+
+void CodePatcher::SetPoolOffsetAt(uword return_address, int32_t offset) {
+ UNIMPLEMENTED();
+}
+
+
void CodePatcher::InsertCallAt(uword start, uword target) {
// The inserted call should not overlap the lazy deopt jump code.
ASSERT(start + CallPattern::kFixedLengthInBytes <= target);
diff --git a/runtime/vm/code_patcher_ia32.cc b/runtime/vm/code_patcher_ia32.cc
index 8143d69..bc7ae62 100644
--- a/runtime/vm/code_patcher_ia32.cc
+++ b/runtime/vm/code_patcher_ia32.cc
@@ -220,6 +220,16 @@
}
+int32_t CodePatcher::GetPoolOffsetAt(uword return_address) {
+ UNREACHABLE();
+ return 0;
+}
+
+
+void CodePatcher::SetPoolOffsetAt(uword return_address, int32_t offset) {
+ UNREACHABLE();
+}
+
void CodePatcher::InsertCallAt(uword start, uword target) {
// The inserted call should not overlap the lazy deopt jump code.
diff --git a/runtime/vm/code_patcher_mips.cc b/runtime/vm/code_patcher_mips.cc
index 7a84596..13195e8 100644
--- a/runtime/vm/code_patcher_mips.cc
+++ b/runtime/vm/code_patcher_mips.cc
@@ -46,6 +46,17 @@
}
+int32_t CodePatcher::GetPoolOffsetAt(uword return_address) {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+
+void CodePatcher::SetPoolOffsetAt(uword return_address, int32_t offset) {
+ UNIMPLEMENTED();
+}
+
+
void CodePatcher::InsertCallAt(uword start, uword target) {
// The inserted call should not overlap the lazy deopt jump code.
ASSERT(start + CallPattern::kFixedLengthInBytes <= target);
diff --git a/runtime/vm/code_patcher_x64.cc b/runtime/vm/code_patcher_x64.cc
index 9926411..7311862 100644
--- a/runtime/vm/code_patcher_x64.cc
+++ b/runtime/vm/code_patcher_x64.cc
@@ -142,6 +142,43 @@
};
+// The expected pattern of a call where the target is loaded from
+// the object pool:
+// 00: 4d 8b 9f imm32 mov R11, [PP + off]
+// 07: 41 ff d3 call R11
+// 10 <- return address
+class PoolPointerCall : public ValueObject {
+ public:
+ explicit PoolPointerCall(uword return_address)
+ : start_(return_address - kCallPatternSize) {
+ ASSERT(IsValid(return_address));
+ }
+
+ static bool IsValid(uword return_address) {
+ uint8_t* code_bytes =
+ reinterpret_cast<uint8_t*>(return_address - kCallPatternSize);
+ return (code_bytes[0] == 0x4D) && (code_bytes[1] == 0x8B) &&
+ (code_bytes[2] == 0x9F) &&
+ (code_bytes[7] == 0x41) && (code_bytes[8] == 0xFF) &&
+ (code_bytes[9] == 0xD3);
+ }
+
+ int32_t pp_offset() const {
+ return *reinterpret_cast<int32_t*>(start_ + 3);
+ }
+
+ void set_pp_offset(int32_t offset) const {
+ *reinterpret_cast<int32_t*>(start_ + 3) = offset;
+ CPU::FlushICache(start_, kCallPatternSize);
+ }
+
+ private:
+ static const int kCallPatternSize = 7 + 3;
+ uword start_;
+ DISALLOW_IMPLICIT_CONSTRUCTORS(PoolPointerCall);
+};
+
+
// The expected code pattern of a Dart closure call:
// 00: 49 ba imm64 mov R10, immediate 2 ; 10 bytes
// 10: 4d 8b 9f imm32 mov R11, [PP + off]
@@ -200,6 +237,18 @@
}
+int32_t CodePatcher::GetPoolOffsetAt(uword return_address) {
+ PoolPointerCall call(return_address);
+ return call.pp_offset();
+}
+
+
+void CodePatcher::SetPoolOffsetAt(uword return_address, int32_t offset) {
+ PoolPointerCall call(return_address);
+ call.set_pp_offset(offset);
+}
+
+
void CodePatcher::PatchInstanceCallAt(uword return_address,
const Code& code,
uword new_target) {
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index b765acd..20cb409 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -708,6 +708,7 @@
is_enabled_(false),
src_bpt_(NULL),
next_(NULL) {
+ saved_value_ = 0;
ASSERT(!func.HasOptimizedCode());
Code& code = Code::Handle(func.unoptimized_code());
ASSERT(!code.IsNull()); // Function must be compiled.
@@ -758,72 +759,6 @@
}
-void CodeBreakpoint::PatchCode() {
- ASSERT(!is_enabled_);
- switch (breakpoint_kind_) {
- case PcDescriptors::kIcCall: {
- const Code& code =
- Code::Handle(Function::Handle(function_).unoptimized_code());
- saved_bytes_.target_address_ =
- CodePatcher::GetInstanceCallAt(pc_, code, NULL);
- CodePatcher::PatchInstanceCallAt(pc_, code,
- StubCode::BreakpointDynamicEntryPoint());
- break;
- }
- case PcDescriptors::kUnoptStaticCall: {
- const Code& code =
- Code::Handle(Function::Handle(function_).unoptimized_code());
- saved_bytes_.target_address_ =
- CodePatcher::GetStaticCallTargetAt(pc_, code);
- CodePatcher::PatchStaticCallAt(pc_, code,
- StubCode::BreakpointStaticEntryPoint());
- break;
- }
- case PcDescriptors::kRuntimeCall:
- case PcDescriptors::kClosureCall:
- case PcDescriptors::kReturn: {
- const Code& code =
- Code::Handle(Function::Handle(function_).unoptimized_code());
- saved_bytes_.target_address_ =
- CodePatcher::GetStaticCallTargetAt(pc_, code);
- CodePatcher::PatchStaticCallAt(pc_, code,
- StubCode::BreakpointRuntimeEntryPoint());
- break;
- }
- default:
- UNREACHABLE();
- }
- is_enabled_ = true;
-}
-
-
-void CodeBreakpoint::RestoreCode() {
- ASSERT(is_enabled_);
- switch (breakpoint_kind_) {
- case PcDescriptors::kIcCall: {
- const Code& code =
- Code::Handle(Function::Handle(function_).unoptimized_code());
- CodePatcher::PatchInstanceCallAt(pc_, code,
- saved_bytes_.target_address_);
- break;
- }
- case PcDescriptors::kUnoptStaticCall:
- case PcDescriptors::kClosureCall:
- case PcDescriptors::kRuntimeCall:
- case PcDescriptors::kReturn: {
- const Code& code =
- Code::Handle(Function::Handle(function_).unoptimized_code());
- CodePatcher::PatchStaticCallAt(pc_, code,
- saved_bytes_.target_address_);
- break;
- }
- default:
- UNREACHABLE();
- }
- is_enabled_ = false;
-}
-
-
void CodeBreakpoint::Enable() {
if (!is_enabled_) {
PatchCode();
@@ -1029,14 +964,14 @@
ASSERT(!code.IsNull());
PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
for (intptr_t i = 0; i < desc.Length(); i++) {
- CodeBreakpoint* bpt = GetCodeBreakpoint(desc.PC(i));
- if (bpt != NULL) {
- // There is already a breakpoint for this address. Make sure
- // it is enabled.
- bpt->Enable();
- continue;
- }
if (IsSafePoint(desc.DescriptorKind(i))) {
+ CodeBreakpoint* bpt = GetCodeBreakpoint(desc.PC(i));
+ if (bpt != NULL) {
+ // There is already a breakpoint for this address. Make sure
+ // it is enabled.
+ bpt->Enable();
+ continue;
+ }
bpt = new CodeBreakpoint(target_function, i);
RegisterCodeBreakpoint(bpt);
bpt->Enable();
@@ -2175,7 +2110,7 @@
uword Debugger::GetPatchedStubAddress(uword breakpoint_address) {
CodeBreakpoint* bpt = GetCodeBreakpoint(breakpoint_address);
if (bpt != NULL) {
- return bpt->saved_bytes_.target_address_;
+ return bpt->OrigStubAddress();
}
UNREACHABLE();
return 0L;
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index f7024d3..573ea50 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -90,6 +90,8 @@
void Disable();
bool IsEnabled() const { return is_enabled_; }
+ uword OrigStubAddress() const;
+
private:
void VisitObjectPointers(ObjectPointerVisitor* visitor);
@@ -114,10 +116,7 @@
CodeBreakpoint* next_;
PcDescriptors::Kind breakpoint_kind_;
- union {
- uword target_address_;
- uint8_t raw[2 * sizeof(uword)];
- } saved_bytes_;
+ uword saved_value_;
friend class Debugger;
DISALLOW_COPY_AND_ASSIGN(CodeBreakpoint);
diff --git a/runtime/vm/debugger_arm.cc b/runtime/vm/debugger_arm.cc
index b93f32a..753f781 100644
--- a/runtime/vm/debugger_arm.cc
+++ b/runtime/vm/debugger_arm.cc
@@ -5,6 +5,7 @@
#include "vm/globals.h"
#if defined(TARGET_ARCH_ARM)
+#include "vm/code_patcher.h"
#include "vm/cpu.h"
#include "vm/debugger.h"
#include "vm/instructions.h"
@@ -31,6 +32,72 @@
*reinterpret_cast<uword*>(closure_addr));
}
+
+uword CodeBreakpoint::OrigStubAddress() const {
+ return saved_value_;
+}
+
+
+void CodeBreakpoint::PatchCode() {
+ ASSERT(!is_enabled_);
+ switch (breakpoint_kind_) {
+ case PcDescriptors::kIcCall: {
+ const Code& code =
+ Code::Handle(Function::Handle(function_).unoptimized_code());
+ saved_value_ = CodePatcher::GetInstanceCallAt(pc_, code, NULL);
+ CodePatcher::PatchInstanceCallAt(pc_, code,
+ StubCode::BreakpointDynamicEntryPoint());
+ break;
+ }
+ case PcDescriptors::kUnoptStaticCall: {
+ const Code& code =
+ Code::Handle(Function::Handle(function_).unoptimized_code());
+ saved_value_ = CodePatcher::GetStaticCallTargetAt(pc_, code);
+ CodePatcher::PatchStaticCallAt(pc_, code,
+ StubCode::BreakpointStaticEntryPoint());
+ break;
+ }
+ case PcDescriptors::kRuntimeCall:
+ case PcDescriptors::kClosureCall:
+ case PcDescriptors::kReturn: {
+ const Code& code =
+ Code::Handle(Function::Handle(function_).unoptimized_code());
+ saved_value_ = CodePatcher::GetStaticCallTargetAt(pc_, code);
+ CodePatcher::PatchStaticCallAt(pc_, code,
+ StubCode::BreakpointRuntimeEntryPoint());
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ is_enabled_ = true;
+}
+
+
+void CodeBreakpoint::RestoreCode() {
+ ASSERT(is_enabled_);
+ switch (breakpoint_kind_) {
+ case PcDescriptors::kIcCall: {
+ const Code& code =
+ Code::Handle(Function::Handle(function_).unoptimized_code());
+ CodePatcher::PatchInstanceCallAt(pc_, code, saved_value_);
+ break;
+ }
+ case PcDescriptors::kUnoptStaticCall:
+ case PcDescriptors::kClosureCall:
+ case PcDescriptors::kRuntimeCall:
+ case PcDescriptors::kReturn: {
+ const Code& code =
+ Code::Handle(Function::Handle(function_).unoptimized_code());
+ CodePatcher::PatchStaticCallAt(pc_, code, saved_value_);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ is_enabled_ = false;
+}
+
} // namespace dart
#endif // defined TARGET_ARCH_ARM
diff --git a/runtime/vm/debugger_ia32.cc b/runtime/vm/debugger_ia32.cc
index 1e73de4..810e6a1 100644
--- a/runtime/vm/debugger_ia32.cc
+++ b/runtime/vm/debugger_ia32.cc
@@ -36,6 +36,72 @@
*reinterpret_cast<uword*>(closure_addr));
}
+
+uword CodeBreakpoint::OrigStubAddress() const {
+ return saved_value_;
+}
+
+
+void CodeBreakpoint::PatchCode() {
+ ASSERT(!is_enabled_);
+ switch (breakpoint_kind_) {
+ case PcDescriptors::kIcCall: {
+ const Code& code =
+ Code::Handle(Function::Handle(function_).unoptimized_code());
+ saved_value_ = CodePatcher::GetInstanceCallAt(pc_, code, NULL);
+ CodePatcher::PatchInstanceCallAt(pc_, code,
+ StubCode::BreakpointDynamicEntryPoint());
+ break;
+ }
+ case PcDescriptors::kUnoptStaticCall: {
+ const Code& code =
+ Code::Handle(Function::Handle(function_).unoptimized_code());
+ saved_value_ = CodePatcher::GetStaticCallTargetAt(pc_, code);
+ CodePatcher::PatchStaticCallAt(pc_, code,
+ StubCode::BreakpointStaticEntryPoint());
+ break;
+ }
+ case PcDescriptors::kRuntimeCall:
+ case PcDescriptors::kClosureCall:
+ case PcDescriptors::kReturn: {
+ const Code& code =
+ Code::Handle(Function::Handle(function_).unoptimized_code());
+ saved_value_ = CodePatcher::GetStaticCallTargetAt(pc_, code);
+ CodePatcher::PatchStaticCallAt(pc_, code,
+ StubCode::BreakpointRuntimeEntryPoint());
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ is_enabled_ = true;
+}
+
+
+void CodeBreakpoint::RestoreCode() {
+ ASSERT(is_enabled_);
+ switch (breakpoint_kind_) {
+ case PcDescriptors::kIcCall: {
+ const Code& code =
+ Code::Handle(Function::Handle(function_).unoptimized_code());
+ CodePatcher::PatchInstanceCallAt(pc_, code, saved_value_);
+ break;
+ }
+ case PcDescriptors::kUnoptStaticCall:
+ case PcDescriptors::kClosureCall:
+ case PcDescriptors::kRuntimeCall:
+ case PcDescriptors::kReturn: {
+ const Code& code =
+ Code::Handle(Function::Handle(function_).unoptimized_code());
+ CodePatcher::PatchStaticCallAt(pc_, code, saved_value_);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ is_enabled_ = false;
+}
+
} // namespace dart
#endif // defined TARGET_ARCH_IA32
diff --git a/runtime/vm/debugger_mips.cc b/runtime/vm/debugger_mips.cc
index 992a860..9a170b9 100644
--- a/runtime/vm/debugger_mips.cc
+++ b/runtime/vm/debugger_mips.cc
@@ -5,6 +5,7 @@
#include "vm/globals.h"
#if defined(TARGET_ARCH_MIPS)
+#include "vm/code_patcher.h"
#include "vm/cpu.h"
#include "vm/debugger.h"
#include "vm/instructions.h"
@@ -31,6 +32,72 @@
*reinterpret_cast<uword*>(closure_addr));
}
+
+uword CodeBreakpoint::OrigStubAddress() const {
+ return saved_value_;
+}
+
+
+void CodeBreakpoint::PatchCode() {
+ ASSERT(!is_enabled_);
+ switch (breakpoint_kind_) {
+ case PcDescriptors::kIcCall: {
+ const Code& code =
+ Code::Handle(Function::Handle(function_).unoptimized_code());
+ saved_value_ = CodePatcher::GetInstanceCallAt(pc_, code, NULL);
+ CodePatcher::PatchInstanceCallAt(pc_, code,
+ StubCode::BreakpointDynamicEntryPoint());
+ break;
+ }
+ case PcDescriptors::kUnoptStaticCall: {
+ const Code& code =
+ Code::Handle(Function::Handle(function_).unoptimized_code());
+ saved_value_ = CodePatcher::GetStaticCallTargetAt(pc_, code);
+ CodePatcher::PatchStaticCallAt(pc_, code,
+ StubCode::BreakpointStaticEntryPoint());
+ break;
+ }
+ case PcDescriptors::kRuntimeCall:
+ case PcDescriptors::kClosureCall:
+ case PcDescriptors::kReturn: {
+ const Code& code =
+ Code::Handle(Function::Handle(function_).unoptimized_code());
+ saved_value_ = CodePatcher::GetStaticCallTargetAt(pc_, code);
+ CodePatcher::PatchStaticCallAt(pc_, code,
+ StubCode::BreakpointRuntimeEntryPoint());
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ is_enabled_ = true;
+}
+
+
+void CodeBreakpoint::RestoreCode() {
+ ASSERT(is_enabled_);
+ switch (breakpoint_kind_) {
+ case PcDescriptors::kIcCall: {
+ const Code& code =
+ Code::Handle(Function::Handle(function_).unoptimized_code());
+ CodePatcher::PatchInstanceCallAt(pc_, code, saved_value_);
+ break;
+ }
+ case PcDescriptors::kUnoptStaticCall:
+ case PcDescriptors::kClosureCall:
+ case PcDescriptors::kRuntimeCall:
+ case PcDescriptors::kReturn: {
+ const Code& code =
+ Code::Handle(Function::Handle(function_).unoptimized_code());
+ CodePatcher::PatchStaticCallAt(pc_, code, saved_value_);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ is_enabled_ = false;
+}
+
} // namespace dart
#endif // defined TARGET_ARCH_MIPS
diff --git a/runtime/vm/debugger_x64.cc b/runtime/vm/debugger_x64.cc
index 8dacf61..653e3ec 100644
--- a/runtime/vm/debugger_x64.cc
+++ b/runtime/vm/debugger_x64.cc
@@ -8,7 +8,9 @@
#include "vm/debugger.h"
#include "vm/assembler.h"
+#include "vm/code_patcher.h"
#include "vm/cpu.h"
+#include "vm/instructions.h"
#include "vm/stub_code.h"
namespace dart {
@@ -32,6 +34,80 @@
*reinterpret_cast<uword*>(closure_addr));
}
+
+uword CodeBreakpoint::OrigStubAddress() const {
+ const Code& code =
+ Code::Handle(Function::Handle(function_).unoptimized_code());
+ const Array& object_pool = Array::Handle(code.ObjectPool());
+ uword offset = saved_value_ + kHeapObjectTag;
+ ASSERT((offset % kWordSize) == 0);
+ const intptr_t index = (offset - Array::data_offset()) / kWordSize;
+ const uword stub_address = reinterpret_cast<uword>(object_pool.At(index));
+ ASSERT(stub_address % kWordSize == 0);
+ return stub_address;
+}
+
+
+void CodeBreakpoint::PatchCode() {
+ ASSERT(!is_enabled_);
+ switch (breakpoint_kind_) {
+ case PcDescriptors::kIcCall: {
+ int32_t offset = CodePatcher::GetPoolOffsetAt(pc_);
+ ASSERT((offset > 0) && ((offset % 8) == 7));
+ saved_value_ = static_cast<uword>(offset);
+ const int32_t stub_offset =
+ InstructionPattern::OffsetFromPPIndex(
+ Assembler::kBreakpointDynamicCPIndex);
+ CodePatcher::SetPoolOffsetAt(pc_, stub_offset);
+ break;
+ }
+ case PcDescriptors::kUnoptStaticCall: {
+ int32_t offset = CodePatcher::GetPoolOffsetAt(pc_);
+ ASSERT((offset > 0) && ((offset % 8) == 7));
+ saved_value_ = static_cast<uword>(offset);
+ const uint32_t stub_offset =
+ InstructionPattern::OffsetFromPPIndex(
+ Assembler::kBreakpointStaticCPIndex);
+ CodePatcher::SetPoolOffsetAt(pc_, stub_offset);
+ break;
+ }
+ case PcDescriptors::kRuntimeCall:
+ case PcDescriptors::kClosureCall:
+ case PcDescriptors::kReturn: {
+ int32_t offset = CodePatcher::GetPoolOffsetAt(pc_);
+ ASSERT((offset > 0) && ((offset % 8) == 7));
+ saved_value_ = static_cast<uword>(offset);
+ const uint32_t stub_offset =
+ InstructionPattern::OffsetFromPPIndex(
+ Assembler::kBreakpointRuntimeCPIndex);
+ CodePatcher::SetPoolOffsetAt(pc_, stub_offset);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ is_enabled_ = true;
+}
+
+
+void CodeBreakpoint::RestoreCode() {
+ ASSERT(is_enabled_);
+ switch (breakpoint_kind_) {
+ case PcDescriptors::kIcCall:
+ case PcDescriptors::kUnoptStaticCall:
+ case PcDescriptors::kClosureCall:
+ case PcDescriptors::kRuntimeCall:
+ case PcDescriptors::kReturn: {
+ CodePatcher::SetPoolOffsetAt(pc_, static_cast<int32_t>(saved_value_));
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ is_enabled_ = false;
+}
+
+
} // namespace dart
#endif // defined TARGET_ARCH_X64
diff --git a/runtime/vm/instructions_x64.cc b/runtime/vm/instructions_x64.cc
index 7b0b4ae..f01afbb 100644
--- a/runtime/vm/instructions_x64.cc
+++ b/runtime/vm/instructions_x64.cc
@@ -18,6 +18,12 @@
}
+intptr_t InstructionPattern::OffsetFromPPIndex(intptr_t index) {
+ intptr_t offset = Array::element_offset(index);
+ return offset - kHeapObjectTag;
+}
+
+
bool InstructionPattern::TestBytesWith(const int* data, int num_bytes) const {
ASSERT(data != NULL);
const uint8_t* byte_array = reinterpret_cast<const uint8_t*>(start_);
diff --git a/runtime/vm/instructions_x64.h b/runtime/vm/instructions_x64.h
index 8b91e7d..ced627c 100644
--- a/runtime/vm/instructions_x64.h
+++ b/runtime/vm/instructions_x64.h
@@ -39,6 +39,7 @@
virtual int pattern_length_in_bytes() const = 0;
static intptr_t IndexFromPPLoad(uword start);
+ static intptr_t OffsetFromPPIndex(intptr_t index);
protected:
uword start() const { return start_; }
diff --git a/tools/VERSION b/tools/VERSION
index 6d3ad3b..f4e2ca5 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
MINOR 1
PATCH 0
PRERELEASE 5
-PRERELEASE_PATCH 10
+PRERELEASE_PATCH 11