From b5966db69ed201a99c1eecddb3cf5fd22b759af6 Mon Sep 17 00:00:00 2001 From: Florian Schneider Date: Fri, 21 Aug 2015 09:31:36 +0200 Subject: [PATCH] VM: Clean up and fix bugs in instructions patterns Fix bug in DecodeLoadWordFromPool: used Array::element_offset instead of ObjectPool::element_offset. This only worked because they accidentally return the same value. Remove virtual methods from InstructionsPatterns on ia32 and x64. Instead use a template for code reuse. This avoids among others vtables for the *Pattern classes and saves >= 4K in VM binary code size. BUG= R=rmacnak@google.com Review URL: https://codereview.chromium.org//1301963003 . --- runtime/vm/code_patcher_ia32.cc | 4 +- runtime/vm/code_patcher_x64.cc | 14 ++--- runtime/vm/instructions_arm.cc | 4 +- runtime/vm/instructions_arm64.cc | 3 +- runtime/vm/instructions_ia32.cc | 55 ---------------- runtime/vm/instructions_ia32.h | 104 +++++++++++++++++++++---------- runtime/vm/instructions_mips.cc | 4 +- runtime/vm/instructions_x64.cc | 57 +---------------- runtime/vm/instructions_x64.h | 104 +++++++++++++++++++------------ runtime/vm/object.h | 6 ++ runtime/vm/stub_code_ia32.cc | 2 +- runtime/vm/stub_code_x64.cc | 2 +- 12 files changed, 158 insertions(+), 201 deletions(-) diff --git a/runtime/vm/code_patcher_ia32.cc b/runtime/vm/code_patcher_ia32.cc index 08d95b4c849..08c7caf03b2 100644 --- a/runtime/vm/code_patcher_ia32.cc +++ b/runtime/vm/code_patcher_ia32.cc @@ -178,11 +178,11 @@ void CodePatcher::PatchInstanceCallAt(uword return_address, void CodePatcher::InsertCallAt(uword start, uword target) { // The inserted call should not overlap the lazy deopt jump code. - ASSERT(start + CallPattern::InstructionLength() <= target); + ASSERT(start + CallPattern::pattern_length_in_bytes() <= target); *reinterpret_cast(start) = 0xE8; CallPattern call(start); call.SetTargetAddress(target); - CPU::FlushICache(start, CallPattern::InstructionLength()); + CPU::FlushICache(start, CallPattern::pattern_length_in_bytes()); } diff --git a/runtime/vm/code_patcher_x64.cc b/runtime/vm/code_patcher_x64.cc index 1f3f8e18aae..58478bfe09c 100644 --- a/runtime/vm/code_patcher_x64.cc +++ b/runtime/vm/code_patcher_x64.cc @@ -41,17 +41,17 @@ class UnoptimizedCall : public ValueObject { } RawObject* ic_data() const { - intptr_t index = InstructionPattern::IndexFromPPLoad(start_ + 3); + intptr_t index = IndexFromPPLoad(start_ + 3); return object_pool_.ObjectAt(index); } uword target() const { - intptr_t index = InstructionPattern::IndexFromPPLoad(start_ + 10); + intptr_t index = IndexFromPPLoad(start_ + 10); return object_pool_.RawValueAt(index); } void set_target(uword target) const { - intptr_t index = InstructionPattern::IndexFromPPLoad(start_ + 10); + intptr_t index = IndexFromPPLoad(start_ + 10); object_pool_.SetRawValueAt(index, target); // No need to flush the instruction cache, since the code is not modified. } @@ -117,7 +117,7 @@ class PoolPointerCall : public ValueObject { } intptr_t pp_index() const { - return InstructionPattern::IndexFromPPLoad(start_ + 3); + return IndexFromPPLoad(start_ + 3); } uword Target() const { @@ -190,11 +190,11 @@ intptr_t CodePatcher::InstanceCallSizeInBytes() { void CodePatcher::InsertCallAt(uword start, uword target) { // The inserted call should not overlap the lazy deopt jump code. - ASSERT(start + ShortCallPattern::InstructionLength() <= target); + ASSERT(start + ShortCallPattern::pattern_length_in_bytes() <= target); *reinterpret_cast(start) = 0xE8; ShortCallPattern call(start); call.SetTargetAddress(target); - CPU::FlushICache(start, ShortCallPattern::InstructionLength()); + CPU::FlushICache(start, ShortCallPattern::pattern_length_in_bytes()); } @@ -227,7 +227,7 @@ class EdgeCounter : public ValueObject { } RawObject* edge_counter() const { - return object_pool_.ObjectAt(InstructionPattern::IndexFromPPLoad(end_ - 4)); + return object_pool_.ObjectAt(IndexFromPPLoad(end_ - 4)); } private: diff --git a/runtime/vm/instructions_arm.cc b/runtime/vm/instructions_arm.cc index 6709c19c93f..6f52b56d142 100644 --- a/runtime/vm/instructions_arm.cc +++ b/runtime/vm/instructions_arm.cc @@ -150,9 +150,7 @@ uword InstructionPattern::DecodeLoadWordFromPool(uword end, end = DecodeLoadWordImmediate(end, reg, &offset); } } - offset += kHeapObjectTag; - ASSERT(Utils::IsAligned(offset, 4)); - *index = (offset - Array::data_offset()) / 4; + *index = ObjectPool::IndexFromOffset(offset); return start; } diff --git a/runtime/vm/instructions_arm64.cc b/runtime/vm/instructions_arm64.cc index 1690456a34d..99875271262 100644 --- a/runtime/vm/instructions_arm64.cc +++ b/runtime/vm/instructions_arm64.cc @@ -208,8 +208,9 @@ uword InstructionPattern::DecodeLoadWordFromPool(uword end, offset |= instr->Imm16Field(); } } + // PP is untagged on ARM64. ASSERT(Utils::IsAligned(offset, 8)); - *index = (offset - Array::data_offset()) / 8; + *index = ObjectPool::IndexFromOffset(offset - kHeapObjectTag); return start; } diff --git a/runtime/vm/instructions_ia32.cc b/runtime/vm/instructions_ia32.cc index 4093e208ede..84ba433ece3 100644 --- a/runtime/vm/instructions_ia32.cc +++ b/runtime/vm/instructions_ia32.cc @@ -11,61 +11,6 @@ namespace dart { -bool InstructionPattern::TestBytesWith(const int* data, int num_bytes) const { - ASSERT(data != NULL); - const uint8_t* byte_array = reinterpret_cast(start_); - for (int i = 0; i < num_bytes; i++) { - // Skip comparison for data[i] < 0. - if ((data[i] >= 0) && (byte_array[i] != (0xFF & data[i]))) { - return false; - } - } - return true; -} - - -uword CallOrJumpPattern::TargetAddress() const { - ASSERT(IsValid()); - return start() + kLengthInBytes + *reinterpret_cast(start() + 1); -} - - -void CallOrJumpPattern::SetTargetAddress(uword target) const { - ASSERT(IsValid()); - *reinterpret_cast(start() + 1) = target - start() - kLengthInBytes; - CPU::FlushICache(start() + 1, kWordSize); -} - - -const int* CallPattern::pattern() const { - static const int kCallPattern[kLengthInBytes] = {0xE8, -1, -1, -1, -1}; - return kCallPattern; -} - - -const int* JumpPattern::pattern() const { - static const int kJumpPattern[kLengthInBytes] = {0xE9, -1, -1, -1, -1}; - return kJumpPattern; -} - - -const int* ReturnPattern::pattern() const { - static const int kReturnPattern[kLengthInBytes] = { 0xC3 }; - return kReturnPattern; -} - - -const int* ProloguePattern::pattern() const { - static const int kProloguePattern[kLengthInBytes] = { 0x55, 0x89, 0xe5 }; - return kProloguePattern; -} - - -const int* SetFramePointerPattern::pattern() const { - static const int kFramePointerPattern[kLengthInBytes] = { 0x89, 0xe5 }; - return kFramePointerPattern; -} - } // namespace dart #endif // defined TARGET_ARCH_IA32 diff --git a/runtime/vm/instructions_ia32.h b/runtime/vm/instructions_ia32.h index c536124872e..1a839c84dec 100644 --- a/runtime/vm/instructions_ia32.h +++ b/runtime/vm/instructions_ia32.h @@ -11,6 +11,7 @@ #endif #include "vm/allocation.h" +#include "vm/cpu.h" #include "vm/object.h" namespace dart { @@ -20,24 +21,22 @@ class RawClass; class Immediate; class RawObject; -// Abstract class for all instruction pattern classes. -class InstructionPattern : public ValueObject { +// Template class for all instruction pattern classes. +// P has to specify a static pattern and a pattern length method. +template class InstructionPattern : public ValueObject { public: explicit InstructionPattern(uword pc) : start_(pc) { ASSERT(pc != 0); } - virtual ~InstructionPattern() {} // Call to check if the instruction pattern at 'pc' match the instruction. - virtual bool IsValid() const { - return TestBytesWith(pattern(), pattern_length_in_bytes()); + // 'P::pattern()' returns the expected byte pattern in form of an integer + // array with length of 'P::pattern_length_in_bytes()'. A '-1' element means + // 'any byte'. + bool IsValid() const { + return TestBytesWith(P::pattern(), P::pattern_length_in_bytes()); } - // 'pattern' returns the expected byte pattern in form of an integer array - // with length of 'pattern_length_in_bytes'. A '-1' element means 'any byte'. - virtual const int* pattern() const = 0; - virtual int pattern_length_in_bytes() const = 0; - protected: uword start() const { return start_; } @@ -45,7 +44,17 @@ class InstructionPattern : public ValueObject { // Returns true if the 'num_bytes' bytes at 'start_' correspond to // array of integers 'data'. 'data' elements are either a byte or -1, which // represents any byte. - bool TestBytesWith(const int* data, int num_bytes) const; + bool TestBytesWith(const int* data, int num_bytes) const { + ASSERT(data != NULL); + const uint8_t* byte_array = reinterpret_cast(start_); + for (int i = 0; i < num_bytes; i++) { + // Skip comparison for data[i] < 0. + if ((data[i] >= 0) && (byte_array[i] != (0xFF & data[i]))) { + return false; + } + } + return true; + } const uword start_; @@ -53,54 +62,74 @@ class InstructionPattern : public ValueObject { }; -class CallOrJumpPattern : public InstructionPattern { +template +class CallOrJumpPattern : public InstructionPattern

{ public: - virtual int pattern_length_in_bytes() const { - return kLengthInBytes; + uword TargetAddress() const { + ASSERT(this->IsValid()); + return this->start() + + P::pattern_length_in_bytes() + + *reinterpret_cast(this->start() + 1); + } + + void SetTargetAddress(uword new_target) const { + ASSERT(this->IsValid()); + *reinterpret_cast(this->start() + 1) = + new_target - this->start() - P::pattern_length_in_bytes(); + CPU::FlushICache(this->start() + 1, kWordSize); } - uword TargetAddress() const; - void SetTargetAddress(uword new_target) const; protected: - explicit CallOrJumpPattern(uword pc) : InstructionPattern(pc) {} - static const int kLengthInBytes = 5; + explicit CallOrJumpPattern(uword pc) : InstructionPattern

(pc) {} private: DISALLOW_COPY_AND_ASSIGN(CallOrJumpPattern); }; -class CallPattern : public CallOrJumpPattern { +class CallPattern : public CallOrJumpPattern { public: explicit CallPattern(uword pc) : CallOrJumpPattern(pc) {} - static int InstructionLength() { - return kLengthInBytes; + + static int pattern_length_in_bytes() { return kLengthInBytes; } + static const int* pattern() { + static const int kCallPattern[kLengthInBytes] = {0xE8, -1, -1, -1, -1}; + return kCallPattern; } private: - virtual const int* pattern() const; + static const int kLengthInBytes = 5; DISALLOW_COPY_AND_ASSIGN(CallPattern); }; -class JumpPattern : public CallOrJumpPattern { +class JumpPattern : public CallOrJumpPattern { public: JumpPattern(uword pc, const Code& code) : CallOrJumpPattern(pc) {} + static int pattern_length_in_bytes() { return kLengthInBytes; } + static const int* pattern() { + static const int kJumpPattern[kLengthInBytes] = {0xE9, -1, -1, -1, -1}; + return kJumpPattern; + } + private: - virtual const int* pattern() const; + static const int kLengthInBytes = 5; DISALLOW_COPY_AND_ASSIGN(JumpPattern); }; -class ReturnPattern : public InstructionPattern { +class ReturnPattern : public InstructionPattern { public: explicit ReturnPattern(uword pc) : InstructionPattern(pc) {} - virtual const int* pattern() const; - virtual int pattern_length_in_bytes() const { return kLengthInBytes; } + static const int* pattern() { + static const int kReturnPattern[kLengthInBytes] = { 0xC3 }; + return kReturnPattern; + } + static int pattern_length_in_bytes() { return kLengthInBytes; } private: static const int kLengthInBytes = 1; @@ -109,12 +138,16 @@ class ReturnPattern : public InstructionPattern { // push ebp // mov ebp, esp -class ProloguePattern : public InstructionPattern { +class ProloguePattern : public InstructionPattern { public: explicit ProloguePattern(uword pc) : InstructionPattern(pc) {} - virtual const int* pattern() const; - virtual int pattern_length_in_bytes() const { return kLengthInBytes; } + static const int* pattern() { + static const int kProloguePattern[kLengthInBytes] = { 0x55, 0x89, 0xe5 }; + return kProloguePattern; + } + + static int pattern_length_in_bytes() { return kLengthInBytes; } private: static const int kLengthInBytes = 3; @@ -122,12 +155,17 @@ class ProloguePattern : public InstructionPattern { // mov ebp, esp -class SetFramePointerPattern : public InstructionPattern { +class SetFramePointerPattern : + public InstructionPattern { public: explicit SetFramePointerPattern(uword pc) : InstructionPattern(pc) {} - virtual const int* pattern() const; - virtual int pattern_length_in_bytes() const { return kLengthInBytes; } + static const int* pattern() { + static const int kFramePointerPattern[kLengthInBytes] = { 0x89, 0xe5 }; + return kFramePointerPattern; + } + + static int pattern_length_in_bytes() { return kLengthInBytes; } private: static const int kLengthInBytes = 2; diff --git a/runtime/vm/instructions_mips.cc b/runtime/vm/instructions_mips.cc index 34a5c3a4609..0d118730527 100644 --- a/runtime/vm/instructions_mips.cc +++ b/runtime/vm/instructions_mips.cc @@ -118,9 +118,7 @@ uword InstructionPattern::DecodeLoadWordFromPool(uword end, // Offset is signed, so add the upper 16 bits. offset += (instr->UImmField() << 16); } - offset += kHeapObjectTag; - ASSERT(Utils::IsAligned(offset, 4)); - *index = (offset - Array::data_offset()) / 4; + *index = ObjectPool::IndexFromOffset(offset); return start; } diff --git a/runtime/vm/instructions_x64.cc b/runtime/vm/instructions_x64.cc index 51128dd2390..83f427dbb55 100644 --- a/runtime/vm/instructions_x64.cc +++ b/runtime/vm/instructions_x64.cc @@ -11,54 +11,27 @@ namespace dart { -intptr_t InstructionPattern::IndexFromPPLoad(uword start) { +intptr_t IndexFromPPLoad(uword start) { int32_t offset = *reinterpret_cast(start); return ObjectPool::IndexFromOffset(offset); } -intptr_t InstructionPattern::OffsetFromPPIndex(intptr_t index) { - intptr_t offset = ObjectPool::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(start_); - for (int i = 0; i < num_bytes; i++) { - // Skip comparison for data[i] < 0. - if ((data[i] >= 0) && (byte_array[i] != (0xFF & data[i]))) { - return false; - } - } - return true; -} - - uword JumpPattern::TargetAddress() const { ASSERT(IsValid()); - int index = InstructionPattern::IndexFromPPLoad(start() + 3); + int index = IndexFromPPLoad(start() + 3); return object_pool_.RawValueAt(index); } void JumpPattern::SetTargetAddress(uword target) const { ASSERT(IsValid()); - int index = InstructionPattern::IndexFromPPLoad(start() + 3); + int index = IndexFromPPLoad(start() + 3); object_pool_.SetRawValueAt(index, target); // No need to flush the instruction cache, since the code is not modified. } -const int* JumpPattern::pattern() const { - // 07: 41 ff a7 imm32 jmpq [reg + off] - static const int kJumpPattern[kLengthInBytes] = - {0x41, 0xFF, -1, -1, -1, -1, -1}; - return kJumpPattern; -} - - void ShortCallPattern::SetTargetAddress(uword target) const { ASSERT(IsValid()); *reinterpret_cast(start() + 1) = target - start() - kLengthInBytes; @@ -66,30 +39,6 @@ void ShortCallPattern::SetTargetAddress(uword target) const { } -const int* ShortCallPattern::pattern() const { - static const int kCallPattern[kLengthInBytes] = {0xE8, -1, -1, -1, -1}; - return kCallPattern; -} - - -const int* ReturnPattern::pattern() const { - static const int kReturnPattern[kLengthInBytes] = { 0xC3 }; - return kReturnPattern; -} - - -const int* ProloguePattern::pattern() const { - static const int kProloguePattern[kLengthInBytes] = - { 0x55, 0x48, 0x89, 0xe5 }; - return kProloguePattern; -} - - -const int* SetFramePointerPattern::pattern() const { - static const int kFramePointerPattern[kLengthInBytes] = { 0x48, 0x89, 0xe5 }; - return kFramePointerPattern; -} - } // namespace dart #endif // defined TARGET_ARCH_X64 diff --git a/runtime/vm/instructions_x64.h b/runtime/vm/instructions_x64.h index 8f5cda401c9..4c4aae833de 100644 --- a/runtime/vm/instructions_x64.h +++ b/runtime/vm/instructions_x64.h @@ -20,27 +20,26 @@ class RawClass; class Immediate; class RawObject; -// Abstract class for all instruction pattern classes. -class InstructionPattern : public ValueObject { + +intptr_t IndexFromPPLoad(uword start); + + +// Template class for all instruction pattern classes. +// P has to specify a static pattern and a pattern length method. +template class InstructionPattern : public ValueObject { public: explicit InstructionPattern(uword pc) : start_(pc) { ASSERT(pc != 0); } - virtual ~InstructionPattern() {} // Call to check if the instruction pattern at 'pc' match the instruction. - virtual bool IsValid() const { - return TestBytesWith(pattern(), pattern_length_in_bytes()); + // 'P::pattern()' returns the expected byte pattern in form of an integer + // array with length of 'P::pattern_length_in_bytes()'. A '-1' element means + // 'any byte'. + bool IsValid() const { + return TestBytesWith(P::pattern(), P::pattern_length_in_bytes()); } - // 'pattern' returns the expected byte pattern in form of an integer array - // with length of 'pattern_length_in_bytes'. A '-1' element means 'any byte'. - virtual const int* pattern() const = 0; - 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_; } @@ -48,7 +47,17 @@ class InstructionPattern : public ValueObject { // Returns true if the 'num_bytes' bytes at 'start_' correspond to // array of integers 'data'. 'data' elements are either a byte or -1, which // represents any byte. - bool TestBytesWith(const int* data, int num_bytes) const; + bool TestBytesWith(const int* data, int num_bytes) const { + ASSERT(data != NULL); + const uint8_t* byte_array = reinterpret_cast(start_); + for (int i = 0; i < num_bytes; i++) { + // Skip comparison for data[i] < 0. + if ((data[i] >= 0) && (byte_array[i] != (0xFF & data[i]))) { + return false; + } + } + return true; + } const uword start_; @@ -56,23 +65,24 @@ class InstructionPattern : public ValueObject { }; -class JumpPattern : public InstructionPattern { +class JumpPattern : public InstructionPattern { public: JumpPattern(uword pc, const Code& code) : InstructionPattern(pc), object_pool_(ObjectPool::Handle(code.GetObjectPool())) {} - static int InstructionLength() { - return kLengthInBytes; - } + uword TargetAddress() const; void SetTargetAddress(uword new_target) const; - virtual int pattern_length_in_bytes() const { - return kLengthInBytes; - } static const int kLengthInBytes = 7; + static int pattern_length_in_bytes() { return kLengthInBytes; } + static const int* pattern() { + // 07: 41 ff a7 imm32 jmpq [reg + off] + static const int kJumpPattern[kLengthInBytes] = + {0x41, 0xFF, -1, -1, -1, -1, -1}; + return kJumpPattern; + } private: - virtual const int* pattern() const; const ObjectPool& object_pool_; DISALLOW_COPY_AND_ASSIGN(JumpPattern); @@ -80,33 +90,34 @@ class JumpPattern : public InstructionPattern { // 5 byte call instruction. -class ShortCallPattern : public InstructionPattern { +class ShortCallPattern : public InstructionPattern { public: explicit ShortCallPattern(uword pc) : InstructionPattern(pc) {} - static int InstructionLength() { - return kLengthInBytes; - } - - virtual int pattern_length_in_bytes() const { - return kLengthInBytes; - } void SetTargetAddress(uword new_target) const; + static int pattern_length_in_bytes() { return kLengthInBytes; } + static const int* pattern() { + static const int kCallPattern[kLengthInBytes] = {0xE8, -1, -1, -1, -1}; + return kCallPattern; + } + private: static const int kLengthInBytes = 5; - virtual const int* pattern() const; - DISALLOW_COPY_AND_ASSIGN(ShortCallPattern); }; -class ReturnPattern : public InstructionPattern { +class ReturnPattern : public InstructionPattern { public: explicit ReturnPattern(uword pc) : InstructionPattern(pc) {} - virtual const int* pattern() const; - virtual int pattern_length_in_bytes() const { return kLengthInBytes; } + static const int* pattern() { + static const int kReturnPattern[kLengthInBytes] = { 0xC3 }; + return kReturnPattern; + } + + static int pattern_length_in_bytes() { return kLengthInBytes; } private: static const int kLengthInBytes = 1; @@ -115,12 +126,17 @@ class ReturnPattern : public InstructionPattern { // push rbp // mov rbp, rsp -class ProloguePattern : public InstructionPattern { +class ProloguePattern : public InstructionPattern { public: explicit ProloguePattern(uword pc) : InstructionPattern(pc) {} - virtual const int* pattern() const; - virtual int pattern_length_in_bytes() const { return kLengthInBytes; } + static const int* pattern() { + static const int kProloguePattern[kLengthInBytes] = + { 0x55, 0x48, 0x89, 0xe5 }; + return kProloguePattern; + } + + static int pattern_length_in_bytes() { return kLengthInBytes; } private: static const int kLengthInBytes = 4; @@ -128,12 +144,18 @@ class ProloguePattern : public InstructionPattern { // mov rbp, rsp -class SetFramePointerPattern : public InstructionPattern { +class SetFramePointerPattern : + public InstructionPattern { public: explicit SetFramePointerPattern(uword pc) : InstructionPattern(pc) {} - virtual const int* pattern() const; - virtual int pattern_length_in_bytes() const { return kLengthInBytes; } + static const int* pattern() { + static const int kFramePointerPattern[kLengthInBytes] = + { 0x48, 0x89, 0xe5 }; + return kFramePointerPattern; + } + + static int pattern_length_in_bytes() { return kLengthInBytes; } private: static const int kLengthInBytes = 3; diff --git a/runtime/vm/object.h b/runtime/vm/object.h index bdfab97cd57..8431674cfa1 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -3625,10 +3625,16 @@ class ObjectPool : public Object { static RawObjectPool* New(intptr_t len); + // Returns the pool index from the offset relative to a tagged RawObjectPool*, + // adjusting for the tag-bit. static intptr_t IndexFromOffset(intptr_t offset) { return (offset + kHeapObjectTag - data_offset()) / kBytesPerElement; } + static intptr_t OffsetFromIndex(intptr_t index) { + return element_offset(index) - kHeapObjectTag; + } + void DebugPrint() const; private: diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc index 4dd59c40d19..669c874e84a 100644 --- a/runtime/vm/stub_code_ia32.cc +++ b/runtime/vm/stub_code_ia32.cc @@ -458,7 +458,7 @@ void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) { // Correct return address to point just after the call that is being // deoptimized. __ popl(EBX); - __ subl(EBX, Immediate(CallPattern::InstructionLength())); + __ subl(EBX, Immediate(CallPattern::pattern_length_in_bytes())); __ pushl(EBX); GenerateDeoptimizationSequence(assembler, true); // Preserve EAX. } diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc index efe71166771..ad428ae986e 100644 --- a/runtime/vm/stub_code_x64.cc +++ b/runtime/vm/stub_code_x64.cc @@ -479,7 +479,7 @@ void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) { // Correct return address to point just after the call that is being // deoptimized. __ popq(RBX); - __ subq(RBX, Immediate(ShortCallPattern::InstructionLength())); + __ subq(RBX, Immediate(ShortCallPattern::pattern_length_in_bytes())); __ pushq(RBX); GenerateDeoptimizationSequence(assembler, true); // Preserve RAX. }