| Index: runtime/vm/code_patcher_x64.cc
|
| diff --git a/runtime/vm/code_patcher_x64.cc b/runtime/vm/code_patcher_x64.cc
|
| index 416e15058160cd48e9b895fd7a2d5d3048dc6a29..e9e678d3321e5ee104ad69bbb3a167bb400babcb 100644
|
| --- a/runtime/vm/code_patcher_x64.cc
|
| +++ b/runtime/vm/code_patcher_x64.cc
|
| @@ -16,44 +16,28 @@
|
|
|
| namespace dart {
|
|
|
| -
|
| -static bool MatchesPattern(uword addr, int16_t* pattern, intptr_t size) {
|
| - uint8_t* bytes = reinterpret_cast<uint8_t*>(addr);
|
| - for (intptr_t i = 0; i < size; i++) {
|
| - int16_t val = pattern[i];
|
| - if ((val >= 0) && (val != bytes[i])) {
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -
|
| -intptr_t IndexFromPPLoad(uword start) {
|
| - int32_t offset = *reinterpret_cast<int32_t*>(start);
|
| - return ObjectPool::IndexFromOffset(offset);
|
| -}
|
| -
|
| -
|
| +// The expected pattern of a Dart unoptimized call (static and instance):
|
| +// 0: 49 8b 9f imm32 mov RBX, [PP + off]
|
| +// 7: 41 ff 97 imm32 call [PP + off]
|
| +// 14 <- return address
|
| class UnoptimizedCall : public ValueObject {
|
| public:
|
| UnoptimizedCall(uword return_address, const Code& code)
|
| : object_pool_(ObjectPool::Handle(code.GetObjectPool())),
|
| start_(return_address - kCallPatternSize) {
|
| + ASSERT(IsValid(return_address));
|
| ASSERT((kCallPatternSize - 7) == Assembler::kCallExternalLabelSize);
|
| - ASSERT(IsValid());
|
| }
|
|
|
| - static const int kCallPatternSize = 22;
|
| + static const int kCallPatternSize = 14;
|
|
|
| - bool IsValid() const {
|
| - static int16_t pattern[kCallPatternSize] = {
|
| - 0x49, 0x8b, 0x9f, -1, -1, -1, -1, // movq RBX, [PP + offs]
|
| - 0x4d, 0x8b, 0xa7, -1, -1, -1, -1, // movq CR, [PP + offs]
|
| - 0x4d, 0x8b, 0x5c, 0x24, 0x07, // movq TMP, [CR + entry_point_offs]
|
| - 0x41, 0xff, 0xd3 // callq TMP
|
| - };
|
| - return MatchesPattern(start_, pattern, kCallPatternSize);
|
| + static bool IsValid(uword return_address) {
|
| + uint8_t* code_bytes =
|
| + reinterpret_cast<uint8_t*>(return_address - kCallPatternSize);
|
| + return (code_bytes[0] == 0x49) && (code_bytes[1] == 0x8B) &&
|
| + (code_bytes[2] == 0x9F) &&
|
| + (code_bytes[7] == 0x41) && (code_bytes[8] == 0xFF) &&
|
| + (code_bytes[9] == 0x97);
|
| }
|
|
|
| intptr_t argument_index() const {
|
| @@ -64,16 +48,14 @@ class UnoptimizedCall : public ValueObject {
|
| return object_pool_.ObjectAt(argument_index());
|
| }
|
|
|
| - RawCode* target() const {
|
| + uword target() const {
|
| intptr_t index = IndexFromPPLoad(start_ + 10);
|
| - Code& code = Code::Handle();
|
| - code ^= object_pool_.ObjectAt(index);
|
| - return code.raw();
|
| + return object_pool_.RawValueAt(index);
|
| }
|
|
|
| - void set_target(const Code& target) const {
|
| + void set_target(uword target) const {
|
| intptr_t index = IndexFromPPLoad(start_ + 10);
|
| - object_pool_.SetObjectAt(index, target);
|
| + object_pool_.SetRawValueAt(index, target);
|
| // No need to flush the instruction cache, since the code is not modified.
|
| }
|
|
|
| @@ -140,38 +122,36 @@ class UnoptimizedStaticCall : public UnoptimizedCall {
|
|
|
|
|
| // The expected pattern of a call where the target is loaded from
|
| -// the object pool.
|
| +// the object pool:
|
| +// 0: 41 ff 97 imm32 call [PP + off]
|
| +// 7: <- return address
|
| class PoolPointerCall : public ValueObject {
|
| public:
|
| explicit PoolPointerCall(uword return_address, const Code& code)
|
| : start_(return_address - kCallPatternSize),
|
| object_pool_(ObjectPool::Handle(code.GetObjectPool())) {
|
| - ASSERT(IsValid());
|
| + ASSERT(IsValid(return_address));
|
| }
|
|
|
| - static const int kCallPatternSize = 15;
|
| + static const int kCallPatternSize = 7;
|
|
|
| - bool IsValid() const {
|
| - static int16_t pattern[kCallPatternSize] = {
|
| - 0x4d, 0x8b, 0xa7, -1, -1, -1, -1, // movq CR, [PP + offs]
|
| - 0x4d, 0x8b, 0x5c, 0x24, 0x07, // movq TMP, [CR + entry_point_off]
|
| - 0x41, 0xff, 0xd3 // callq TMP
|
| - };
|
| - return MatchesPattern(start_, pattern, kCallPatternSize);
|
| + static bool IsValid(uword return_address) {
|
| + uint8_t* code_bytes =
|
| + reinterpret_cast<uint8_t*>(return_address - kCallPatternSize);
|
| + return (code_bytes[0] == 0x41) && (code_bytes[1] == 0xFF) &&
|
| + (code_bytes[2] == 0x97);
|
| }
|
|
|
| intptr_t pp_index() const {
|
| return IndexFromPPLoad(start_ + 3);
|
| }
|
|
|
| - RawCode* Target() const {
|
| - Code& code = Code::Handle();
|
| - code ^= object_pool_.ObjectAt(pp_index());
|
| - return code.raw();
|
| + uword Target() const {
|
| + return object_pool_.RawValueAt(pp_index());
|
| }
|
|
|
| - void SetTarget(const Code& target) const {
|
| - object_pool_.SetObjectAt(pp_index(), target);
|
| + void SetTarget(uword target) const {
|
| + object_pool_.SetRawValueAt(pp_index(), target);
|
| // No need to flush the instruction cache, since the code is not modified.
|
| }
|
|
|
| @@ -184,8 +164,8 @@ class PoolPointerCall : public ValueObject {
|
| };
|
|
|
|
|
| -RawCode* CodePatcher::GetStaticCallTargetAt(uword return_address,
|
| - const Code& code) {
|
| +uword CodePatcher::GetStaticCallTargetAt(uword return_address,
|
| + const Code& code) {
|
| ASSERT(code.ContainsInstructionAt(return_address));
|
| PoolPointerCall call(return_address, code);
|
| return call.Target();
|
| @@ -194,23 +174,32 @@ RawCode* CodePatcher::GetStaticCallTargetAt(uword return_address,
|
|
|
| void CodePatcher::PatchStaticCallAt(uword return_address,
|
| const Code& code,
|
| - const Code& new_target) {
|
| + uword new_target) {
|
| PatchPoolPointerCallAt(return_address, code, new_target);
|
| }
|
|
|
|
|
| void CodePatcher::PatchPoolPointerCallAt(uword return_address,
|
| const Code& code,
|
| - const Code& new_target) {
|
| + uword new_target) {
|
| ASSERT(code.ContainsInstructionAt(return_address));
|
| PoolPointerCall call(return_address, code);
|
| call.SetTarget(new_target);
|
| }
|
|
|
|
|
| -RawCode* CodePatcher::GetInstanceCallAt(uword return_address,
|
| - const Code& code,
|
| - ICData* ic_data) {
|
| +void CodePatcher::PatchInstanceCallAt(uword return_address,
|
| + const Code& code,
|
| + uword new_target) {
|
| + ASSERT(code.ContainsInstructionAt(return_address));
|
| + InstanceCall call(return_address, code);
|
| + call.set_target(new_target);
|
| +}
|
| +
|
| +
|
| +uword CodePatcher::GetInstanceCallAt(uword return_address,
|
| + const Code& code,
|
| + ICData* ic_data) {
|
| ASSERT(code.ContainsInstructionAt(return_address));
|
| InstanceCall call(return_address, code);
|
| if (ic_data != NULL) {
|
| @@ -225,7 +214,7 @@ intptr_t CodePatcher::InstanceCallSizeInBytes() {
|
| }
|
|
|
|
|
| -void CodePatcher::InsertDeoptimizationCallAt(uword start, uword target) {
|
| +void CodePatcher::InsertCallAt(uword start, uword target) {
|
| // The inserted call should not overlap the lazy deopt jump code.
|
| ASSERT(start + ShortCallPattern::pattern_length_in_bytes() <= target);
|
| *reinterpret_cast<uint8_t*>(start) = 0xE8;
|
| @@ -254,14 +243,14 @@ void CodePatcher::PatchNativeCallAt(uword return_address,
|
| const Code& trampoline) {
|
| ASSERT(code.ContainsInstructionAt(return_address));
|
| NativeCall call(return_address, code);
|
| - call.set_target(trampoline);
|
| + call.set_target(trampoline.EntryPoint());
|
| call.set_native_function(target);
|
| }
|
|
|
|
|
| -RawCode* CodePatcher::GetNativeCallAt(uword return_address,
|
| - const Code& code,
|
| - NativeFunction* target) {
|
| +uword CodePatcher::GetNativeCallAt(uword return_address,
|
| + const Code& code,
|
| + NativeFunction* target) {
|
| ASSERT(code.ContainsInstructionAt(return_address));
|
| NativeCall call(return_address, code);
|
| *target = call.native_function();
|
|
|