diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc index 3c6f64439f5..0e16de12eec 100644 --- a/runtime/vm/assembler_arm.cc +++ b/runtime/vm/assembler_arm.cc @@ -1262,7 +1262,7 @@ void Assembler::LoadWordFromPoolOffset(Register rd, int32_t offset) { void Assembler::LoadObject(Register rd, const Object& object) { - // Smi's and VM heap objects are never relocated; do not use object pool. + // Smis and VM heap objects are never relocated; do not use object pool. if (object.IsSmi()) { LoadImmediate(rd, reinterpret_cast(object.raw())); } else if (object.InVMHeap()) { diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc index ea9e0996e97..e716dd51cd7 100644 --- a/runtime/vm/assembler_mips.cc +++ b/runtime/vm/assembler_mips.cc @@ -157,7 +157,7 @@ void Assembler::SubuDetectOverflow(Register rd, Register rs, Register rt, void Assembler::LoadObject(Register rd, const Object& object) { - // Smi's and VM heap objects are never relocated; do not use object pool. + // Smis and VM heap objects are never relocated; do not use object pool. if (object.IsSmi()) { LoadImmediate(rd, reinterpret_cast(object.raw())); } else if (object.InVMHeap()) { diff --git a/runtime/vm/code_generator_test.cc b/runtime/vm/code_generator_test.cc index 0f23d54980f..86b5ff93659 100644 --- a/runtime/vm/code_generator_test.cc +++ b/runtime/vm/code_generator_test.cc @@ -43,7 +43,9 @@ CODEGEN_TEST2_GENERATE(SimpleStaticCallCodegen, function, test) { CODEGEN_TEST2_RUN(SimpleStaticCallCodegen, SmiReturnCodegen, Smi::New(3)) -#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) +#if defined(TARGET_ARCH_IA32) || \ + defined(TARGET_ARCH_X64) || \ + defined(TARGET_ARCH_ARM) // Helper to allocate and return a LocalVariable. @@ -561,6 +563,6 @@ CODEGEN_TEST_RAW_RUN(AllocateNewObjectCodegen, function) { EXPECT_EQ(cls.raw(), result.clazz()); } -#endif // defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) +#endif // TARGET_ARCH_IA32 || TARGET_ARCH_X64 || TARGET_ARCH_ARM } // namespace dart diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h index 75edcfdbf6e..2ad1903d2d1 100644 --- a/runtime/vm/constants_arm.h +++ b/runtime/vm/constants_arm.h @@ -143,10 +143,13 @@ const Register PP = R10; // Caches object pool pointer in generated code. const Register SPREG = SP; // Stack pointer register. const Register FPREG = FP; // Frame pointer register. - // Exception object is passed in this register to the catch handlers when an // exception is thrown. -const Register kExceptionObjectReg = R0; // Unimplemented. +const Register kExceptionObjectReg = R0; + +// Stack trace object is passed in this register to the catch handlers when +// an exception is thrown. +const Register kStackTraceObjectReg = R1; // List of registers used in load/store multiple. diff --git a/runtime/vm/constants_mips.h b/runtime/vm/constants_mips.h index 6569503e238..198ab77087c 100644 --- a/runtime/vm/constants_mips.h +++ b/runtime/vm/constants_mips.h @@ -150,6 +150,15 @@ const Register FPREG = FP; // Frame pointer register. // CMPRES is used for the result of the comparison. const Register CMPRES = T8; +// Exception object is passed in this register to the catch handlers when an +// exception is thrown. +const Register kExceptionObjectReg = A0; + +// Stack trace object is passed in this register to the catch handlers when +// an exception is thrown. +const Register kStackTraceObjectReg = A1; + + typedef uint32_t RegList; const RegList kAllCpuRegistersList = 0xFFFFFFFF; diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc index b05dd6d9e39..ef5f1a92e66 100644 --- a/runtime/vm/exceptions.cc +++ b/runtime/vm/exceptions.cc @@ -207,17 +207,22 @@ static void FindErrorHandler(uword* handler_pc, } -void JumpToExceptionHandler(uword program_counter, - uword stack_pointer, - uword frame_pointer, - const Instance& exception_object, - const Instance& stacktrace_object) { - // The no_gc StackResource is unwound through the tear down of - // stack resources below. - NoGCScope no_gc; - RawInstance* exception = exception_object.raw(); - RawInstance* stacktrace = stacktrace_object.raw(); +static void JumpToHandler(uword program_counter, + uword stack_pointer, + uword frame_pointer, + RawObject* raw_exception, + RawObject* raw_stacktrace) { +#if defined(USING_SIMULATOR) + // Unwinding of the C++ frames and destroying of their stack resources is done + // by the simulator, because the target stack_pointer is a simulated stack + // pointer and not the C++ stack pointer. + // Continue simulating at the given pc in the given frame after setting up the + // exception object in the kExceptionObjectReg register and the stacktrace + // object (if not NULL) in the kStackTraceObjectReg register. + Simulator::Current()->Longjmp(program_counter, stack_pointer, frame_pointer, + raw_exception, raw_stacktrace); +#else // Prepare for unwinding frames by destroying all the stack resources // in the previous frames. Isolate* isolate = Isolate::Current(); @@ -226,39 +231,64 @@ void JumpToExceptionHandler(uword program_counter, isolate->top_resource()->~StackResource(); } - // Set up the appropriate register state and jump to the handler. - typedef void (*ExcpHandler)(uword, uword, uword, RawInstance*, RawInstance*); - ExcpHandler func = reinterpret_cast( - StubCode::JumpToExceptionHandlerEntryPoint()); - func(program_counter, stack_pointer, frame_pointer, exception, stacktrace); + // TODO(regis): Can we safely merge both stubs and pass NULL as + // stacktrace_object in the case of an error handler? + + // A NULL raw_stacktrace indicates that we are jumping to an ErrorHandler, + // rather than to an ExceptionHandler. TODO(regis): Merge these two cases. + if (raw_stacktrace == NULL) { + // Call a stub to set up the error object in kExceptionObjectReg and to + // continue execution at the given pc in the given frame. + typedef void (*ErrorHandler)(uword, uword, uword, RawObject*); + ErrorHandler func = reinterpret_cast( + StubCode::JumpToErrorHandlerEntryPoint()); + func(program_counter, stack_pointer, frame_pointer, raw_exception); + } else { + // Call a stub to set up the exception object in kExceptionObjectReg, + // to set up the stacktrace object in kStackTraceObjectReg, and to + // continue execution at the given pc in the given frame. + typedef void (*ExcpHandler)(uword, uword, uword, RawObject*, RawObject*); + ExcpHandler func = reinterpret_cast( + StubCode::JumpToExceptionHandlerEntryPoint()); + func(program_counter, stack_pointer, frame_pointer, + raw_exception, raw_stacktrace); + } +#endif UNREACHABLE(); } -void JumpToErrorHandler(uword program_counter, - uword stack_pointer, - uword frame_pointer, - const Error& error) { +static void JumpToExceptionHandler(uword program_counter, + uword stack_pointer, + uword frame_pointer, + const Instance& exception_object, + const Instance& stacktrace_object) { // The no_gc StackResource is unwound through the tear down of // stack resources below. NoGCScope no_gc; - ASSERT(!error.IsNull()); - RawError* raw_error = error.raw(); + RawObject* raw_exception = exception_object.raw(); + RawObject* raw_stacktrace = stacktrace_object.raw(); - // Prepare for unwinding frames by destroying all the stack resources - // in the previous frames. - Isolate* isolate = Isolate::Current(); - while (isolate->top_resource() != NULL && - (reinterpret_cast(isolate->top_resource()) < stack_pointer)) { - isolate->top_resource()->~StackResource(); - } + JumpToHandler(program_counter, stack_pointer, frame_pointer, + raw_exception, raw_stacktrace); + + UNREACHABLE(); +} + + +static void JumpToErrorHandler(uword program_counter, + uword stack_pointer, + uword frame_pointer, + const Error& error_object) { + // The no_gc StackResource is unwound through the tear down of + // stack resources below. + NoGCScope no_gc; + ASSERT(!error_object.IsNull()); + RawObject* raw_error = error_object.raw(); + + JumpToHandler( + program_counter, stack_pointer, frame_pointer, raw_error, NULL); - // Set up the error object as the return value in EAX and continue - // from the invocation stub. - typedef void (*ErrorHandler)(uword, uword, uword, RawError*); - ErrorHandler func = reinterpret_cast( - StubCode::JumpToErrorHandlerEntryPoint()); - func(program_counter, stack_pointer, frame_pointer, raw_error); UNREACHABLE(); } diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc index 5753cd31abf..c0f904ba149 100644 --- a/runtime/vm/intermediate_language_arm.cc +++ b/runtime/vm/intermediate_language_arm.cc @@ -2243,13 +2243,22 @@ void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, LocationSummary* BooleanNegateInstr::MakeLocationSummary() const { - UNIMPLEMENTED(); - return NULL; + return LocationSummary::Make(1, + Location::RequiresRegister(), + LocationSummary::kNoCall); } void BooleanNegateInstr::EmitNativeCode(FlowGraphCompiler* compiler) { - UNIMPLEMENTED(); + Register value = locs()->in(0).reg(); + Register result = locs()->out().reg(); + + Label done; + __ LoadObject(result, Bool::True()); + __ cmp(result, ShifterOperand(value)); + __ b(&done, NE); + __ LoadObject(result, Bool::False()); + __ Bind(&done); } diff --git a/runtime/vm/object_arm_test.cc b/runtime/vm/object_arm_test.cc index 7056f92dd54..ab6f7917191 100644 --- a/runtime/vm/object_arm_test.cc +++ b/runtime/vm/object_arm_test.cc @@ -18,21 +18,38 @@ namespace dart { // Generate a simple dart code sequence. // This is used to test Code and Instruction object creation. void GenerateIncrement(Assembler* assembler) { - __ Unimplemented("GenerateIncrement"); + __ LoadImmediate(R0, 0); + __ Push(R0); + __ ldr(IP, Address(SP, 0)); + __ add(IP, IP, ShifterOperand(1)); + __ str(IP, Address(SP, 0)); + __ ldr(IP, Address(SP, 0)); + __ add(IP, IP, ShifterOperand(1)); + __ Pop(R0); + __ mov(R0, ShifterOperand(IP)); + __ Ret(); } // Generate a dart code sequence that embeds a string object in it. // This is used to test Embedded String objects in the instructions. void GenerateEmbedStringInCode(Assembler* assembler, const char* str) { - __ Unimplemented("GenerateEmbedStringInCode"); + __ EnterDartFrame(0); // To setup pp. + const String& string_object = + String::ZoneHandle(String::New(str, Heap::kOld)); + __ LoadObject(R0, string_object); + __ LeaveDartFrame(); + __ Ret(); } // Generate a dart code sequence that embeds a smi object in it. // This is used to test Embedded Smi objects in the instructions. void GenerateEmbedSmiInCode(Assembler* assembler, intptr_t value) { - __ Unimplemented("GenerateEmbedSmiInCode"); + // No need to setup pp, since Smis are not stored in the object pool. + const Smi& smi_object = Smi::ZoneHandle(Smi::New(value)); + __ LoadObject(R0, smi_object); + __ Ret(); } } // namespace dart diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc index df54b52f261..7ad93d24066 100644 --- a/runtime/vm/object_test.cc +++ b/runtime/vm/object_test.cc @@ -9,6 +9,7 @@ #include "vm/isolate.h" #include "vm/object.h" #include "vm/object_store.h" +#include "vm/simulator.h" #include "vm/symbols.h" #include "vm/unit_test.h" @@ -2236,8 +2237,10 @@ TEST_CASE(CheckedHandle) { } -// only ia32 and x64 can run execution tests. -#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) +// Only ia32, x64, and arm can run execution tests. +#if defined(TARGET_ARCH_IA32) || \ + defined(TARGET_ARCH_X64) || \ + defined(TARGET_ARCH_ARM) static Function* CreateFunction(const char* name) { const String& class_name = String::Handle(Symbols::New("ownerClass")); @@ -2259,9 +2262,16 @@ TEST_CASE(Code) { Code& code = Code::Handle(Code::FinalizeCode( *CreateFunction("Test_Code"), &_assembler_)); Instructions& instructions = Instructions::Handle(code.instructions()); - typedef int (*IncrementCode)(); - EXPECT_EQ(2, reinterpret_cast(instructions.EntryPoint())()); uword entry_point = instructions.EntryPoint(); + intptr_t retval = 0; +#if defined(USING_SIMULATOR) + retval = bit_copy(Simulator::Current()->Call( + static_cast(entry_point), 0, 0, 0, 0)); +#else + typedef intptr_t (*IncrementCode)(); + retval = reinterpret_cast(entry_point)(); +#endif + EXPECT_EQ(2, retval); EXPECT_EQ(instructions.raw(), Instructions::FromEntryPoint(entry_point)); } @@ -2276,8 +2286,14 @@ TEST_CASE(EmbedStringInCode) { Code& code = Code::Handle(Code::FinalizeCode( *CreateFunction("Test_EmbedStringInCode"), &_assembler_)); Instructions& instructions = Instructions::Handle(code.instructions()); + uword retval = 0; +#if defined(USING_SIMULATOR) + retval = bit_copy(Simulator::Current()->Call( + static_cast(instructions.EntryPoint()), 0, 0, 0, 0)); +#else typedef uword (*EmbedStringCode)(); - uword retval = reinterpret_cast(instructions.EntryPoint())(); + retval = reinterpret_cast(instructions.EntryPoint())(); +#endif EXPECT((retval & kSmiTagMask) == kHeapObjectTag); String& string_object = String::Handle(); string_object ^= reinterpret_cast(retval); @@ -2297,9 +2313,14 @@ TEST_CASE(EmbedSmiInCode) { Code& code = Code::Handle(Code::FinalizeCode( *CreateFunction("Test_EmbedSmiInCode"), &_assembler_)); Instructions& instructions = Instructions::Handle(code.instructions()); + intptr_t retval = 0; +#if defined(USING_SIMULATOR) + retval = bit_copy(Simulator::Current()->Call( + static_cast(instructions.EntryPoint()), 0, 0, 0, 0)); +#else typedef intptr_t (*EmbedSmiCode)(); - intptr_t retval = - reinterpret_cast(instructions.EntryPoint())(); + retval = reinterpret_cast(instructions.EntryPoint())(); +#endif EXPECT((retval >> kSmiTagShift) == kSmiTestValue); } @@ -2314,9 +2335,14 @@ TEST_CASE(EmbedSmiIn64BitCode) { Code& code = Code::Handle(Code::FinalizeCode( *CreateFunction("Test_EmbedSmiIn64BitCode"), &_assembler_)); Instructions& instructions = Instructions::Handle(code.instructions()); + intptr_t retval = 0; +#if defined(USING_SIMULATOR) + retval = bit_copy(Simulator::Current()->Call( + static_cast(instructions.EntryPoint()), 0, 0, 0, 0)); +#else typedef intptr_t (*EmbedSmiCode)(); - intptr_t retval = - reinterpret_cast(instructions.EntryPoint())(); + retval = reinterpret_cast(instructions.EntryPoint())(); +#endif EXPECT((retval >> kSmiTagShift) == kSmiTestValue); } #endif @@ -3182,6 +3208,6 @@ TEST_CASE(FunctionSourceFingerprint) { EXPECT_EQ(test6.SourceFingerprint(), test7.SourceFingerprint()); } -#endif // defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64). +#endif // TARGET_ARCH_IA32 || TARGET_ARCH_X64 || TARGET_ARCH_ARM } // namespace dart diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc index d027df8a4a4..2644d2d7686 100644 --- a/runtime/vm/simulator_arm.cc +++ b/runtime/vm/simulator_arm.cc @@ -64,7 +64,8 @@ class SimulatorSetjmpBuffer { simulator_ = sim; link_ = sim->last_setjmp_buffer(); sim->set_last_setjmp_buffer(this); - sp_ = sim->get_register(SP); + sp_ = static_cast(sim->get_register(SP)); + native_sp_ = reinterpret_cast(&sim); // Current C++ stack pointer. } ~SimulatorSetjmpBuffer() { @@ -74,10 +75,12 @@ class SimulatorSetjmpBuffer { SimulatorSetjmpBuffer* link() { return link_; } - int32_t sp() { return sp_; } + uword sp() { return sp_; } + uword native_sp() { return native_sp_; } private: - int32_t sp_; + uword sp_; + uword native_sp_; Simulator* simulator_; SimulatorSetjmpBuffer* link_; jmp_buf buffer_; @@ -2863,22 +2866,38 @@ int64_t Simulator::Call(int32_t entry, } -void Simulator::Longjmp( - int32_t pc, int32_t sp, int32_t fp, const Instance& object) { - set_register(SP, sp); - set_register(FP, fp); - set_register(PC, pc); - SimulatorSetjmpBuffer* buf = last_setjmp_buffer(); - +void Simulator::Longjmp(uword pc, + uword sp, + uword fp, + RawObject* raw_exception, + RawObject* raw_stacktrace) { // Walk over all setjmp buffers (simulated --> C++ transitions) - // and try to find the setjmp associated with the stack pointer. + // and try to find the setjmp associated with the simulated stack pointer. + SimulatorSetjmpBuffer* buf = last_setjmp_buffer(); while (buf->link() != NULL && buf->link()->sp() <= sp) { buf = buf->link(); } ASSERT(buf != NULL); - // The caller has already cleaned up the stack memory of C++ frames. - set_register(kExceptionObjectReg, bit_cast(object.raw())); + // The C++ caller has not cleaned up the stack memory of C++ frames. + // Prepare for unwinding frames by destroying all the stack resources + // in the previous C++ frames. + uword native_sp = buf->native_sp(); + Isolate* isolate = Isolate::Current(); + while (isolate->top_resource() != NULL && + (reinterpret_cast(isolate->top_resource()) < native_sp)) { + isolate->top_resource()->~StackResource(); + } + + // Unwind the C++ stack and continue simulation in the target frame. + set_register(PC, static_cast(pc)); + set_register(SP, static_cast(sp)); + set_register(FP, static_cast(fp)); + ASSERT(raw_exception != NULL); + set_register(kExceptionObjectReg, bit_cast(raw_exception)); + if (raw_stacktrace != NULL) { + set_register(kStackTraceObjectReg, bit_cast(raw_stacktrace)); + } buf->Longjmp(); } diff --git a/runtime/vm/simulator_arm.h b/runtime/vm/simulator_arm.h index 71ae8d267db..c819d1c7373 100644 --- a/runtime/vm/simulator_arm.h +++ b/runtime/vm/simulator_arm.h @@ -86,7 +86,11 @@ class Simulator { }; static uword RedirectExternalReference(uword function, CallKind call_kind); - void Longjmp(int32_t pc, int32_t sp, int32_t fp, const Instance& object); + void Longjmp(uword pc, + uword sp, + uword fp, + RawObject* raw_exception, + RawObject* raw_stacktrace); private: // Known bad pc value to ensure that the simulator does not execute diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc index e144c8a735b..01cdc547afe 100644 --- a/runtime/vm/simulator_mips.cc +++ b/runtime/vm/simulator_mips.cc @@ -51,7 +51,8 @@ class SimulatorSetjmpBuffer { simulator_ = sim; link_ = sim->last_setjmp_buffer(); sim->set_last_setjmp_buffer(this); - sp_ = sim->get_register(SP); + sp_ = static_cast(sim->get_register(SP)); + native_sp_ = reinterpret_cast(&sim); // Current C++ stack pointer. } ~SimulatorSetjmpBuffer() { @@ -61,10 +62,12 @@ class SimulatorSetjmpBuffer { SimulatorSetjmpBuffer* link() { return link_; } - int32_t sp() { return sp_; } + uword sp() { return sp_; } + uword native_sp() { return native_sp_; } private: - int32_t sp_; + uword sp_; + uword native_sp_; Simulator* simulator_; SimulatorSetjmpBuffer* link_; jmp_buf buffer_; @@ -1829,6 +1832,42 @@ int64_t Simulator::Call(int32_t entry, return Utils::LowHighTo64Bits(get_register(V0), get_register(V1)); } + +void Simulator::Longjmp(uword pc, + uword sp, + uword fp, + RawObject* raw_exception, + RawObject* raw_stacktrace) { + // Walk over all setjmp buffers (simulated --> C++ transitions) + // and try to find the setjmp associated with the simulated stack pointer. + SimulatorSetjmpBuffer* buf = last_setjmp_buffer(); + while (buf->link() != NULL && buf->link()->sp() <= sp) { + buf = buf->link(); + } + ASSERT(buf != NULL); + + // The C++ caller has not cleaned up the stack memory of C++ frames. + // Prepare for unwinding frames by destroying all the stack resources + // in the previous C++ frames. + uword native_sp = buf->native_sp(); + Isolate* isolate = Isolate::Current(); + while (isolate->top_resource() != NULL && + (reinterpret_cast(isolate->top_resource()) < native_sp)) { + isolate->top_resource()->~StackResource(); + } + + // Unwind the C++ stack and continue simulation in the target frame. + set_pc(static_cast(pc)); + set_register(SP, static_cast(sp)); + set_register(FP, static_cast(fp)); + ASSERT(raw_exception != NULL); + set_register(kExceptionObjectReg, bit_cast(raw_exception)); + if (raw_stacktrace != NULL) { + set_register(kStackTraceObjectReg, bit_cast(raw_stacktrace)); + } + buf->Longjmp(); +} + } // namespace dart #endif // !defined(HOST_ARCH_MIPS) diff --git a/runtime/vm/simulator_mips.h b/runtime/vm/simulator_mips.h index a3bd6c7b5d5..5cee1820159 100644 --- a/runtime/vm/simulator_mips.h +++ b/runtime/vm/simulator_mips.h @@ -17,6 +17,7 @@ #endif #include "vm/constants_mips.h" +#include "vm/object.h" namespace dart { @@ -89,6 +90,12 @@ class Simulator { }; static uword RedirectExternalReference(uword function, CallKind call_kind); + void Longjmp(uword pc, + uword sp, + uword fp, + RawObject* raw_exception, + RawObject* raw_stacktrace); + private: // A pc value used to signal the simulator to stop execution. Generally // the ra is set to this value on transition from native C code to @@ -171,6 +178,7 @@ class Simulator { friend class SimulatorDebugger; friend class SimulatorSetjmpBuffer; + DISALLOW_COPY_AND_ASSIGN(Simulator); }; } // namespace dart diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc index a623acddb32..8369a58f545 100644 --- a/runtime/vm/stub_code_arm.cc +++ b/runtime/vm/stub_code_arm.cc @@ -1474,16 +1474,40 @@ void StubCode::GenerateGetStackPointerStub(Assembler* assembler) { // Jump to the exception handler. -// No Result. +// LR: return address. +// R0: program_counter. +// R1: stack_pointer. +// R2: frame_pointer. +// R3: error object. +// SP: address of stacktrace object. +// Does not return. void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) { - __ Unimplemented("JumpToExceptionHandler Stub"); + ASSERT(kExceptionObjectReg == R0); + ASSERT(kStackTraceObjectReg == R1); + __ mov(IP, ShifterOperand(R1)); // Stack pointer. + __ mov(LR, ShifterOperand(R0)); // Program counter. + __ mov(R0, ShifterOperand(R3)); // Exception object. + __ ldr(R1, Address(SP, 0)); // StackTrace object. + __ mov(FP, ShifterOperand(R2)); // Frame_pointer. + __ mov(SP, ShifterOperand(IP)); // Stack pointer. + __ bx(LR); // Jump to the exception handler code. } // Jump to the error handler. -// No Result. +// LR: return address. +// R0: program_counter. +// R1: stack_pointer. +// R2: frame_pointer. +// R3: error object. +// Does not return. void StubCode::GenerateJumpToErrorHandlerStub(Assembler* assembler) { - __ Unimplemented("JumpToErrorHandler Stub"); + ASSERT(kExceptionObjectReg == R0); + __ mov(LR, ShifterOperand(R0)); // Program counter. + __ mov(R0, ShifterOperand(R3)); // Error object. + __ mov(FP, ShifterOperand(R2)); // Frame_pointer. + __ mov(SP, ShifterOperand(R1)); // Stack pointer. + __ bx(LR); // Jump to the exception handler code. } diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc index ef0eda6ce4e..f6b577c8dd3 100644 --- a/runtime/vm/stub_code_ia32.cc +++ b/runtime/vm/stub_code_ia32.cc @@ -1907,6 +1907,7 @@ void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) { // TOS + 4: error object // No Result. void StubCode::GenerateJumpToErrorHandlerStub(Assembler* assembler) { + ASSERT(kExceptionObjectReg == EAX); __ movl(EAX, Address(ESP, 4 * kWordSize)); // Load error object. __ movl(EBP, Address(ESP, 3 * kWordSize)); // Load target frame_pointer. __ movl(EBX, Address(ESP, 1 * kWordSize)); // Load target PC into EBX. diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc index b6a38cdf51d..e346f620cc1 100644 --- a/runtime/vm/stub_code_x64.cc +++ b/runtime/vm/stub_code_x64.cc @@ -1874,6 +1874,7 @@ void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) { // RCX: error object // No Result. void StubCode::GenerateJumpToErrorHandlerStub(Assembler* assembler) { + ASSERT(kExceptionObjectReg == RAX); __ movq(RAX, RCX); // error object. __ movq(RBP, RDX); // target frame_pointer. __ movq(RSP, RSI); // target stack_pointer.