From d79c7c19697012cd33ecc48abe73f3a697c2eae5 Mon Sep 17 00:00:00 2001 From: "regis@google.com" Date: Thu, 18 Apr 2013 16:23:25 +0000 Subject: [PATCH] Implement long jump in ARM and MIPS simulators. Implement error and exception handler stubs on ARM. Hook up simulator for object tests. Enable codegen and object tests on ARM. Review URL: https://codereview.chromium.org//14309004 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@21680 260f80e4-7a28-3924-810f-c04153c831b5 --- runtime/vm/assembler_arm.cc | 2 +- runtime/vm/assembler_mips.cc | 2 +- runtime/vm/code_generator_test.cc | 6 +- runtime/vm/constants_arm.h | 7 +- runtime/vm/constants_mips.h | 9 +++ runtime/vm/exceptions.cc | 98 ++++++++++++++++--------- runtime/vm/intermediate_language_arm.cc | 15 +++- runtime/vm/object_arm_test.cc | 23 +++++- runtime/vm/object_test.cc | 46 +++++++++--- runtime/vm/simulator_arm.cc | 45 ++++++++---- runtime/vm/simulator_arm.h | 6 +- runtime/vm/simulator_mips.cc | 45 +++++++++++- runtime/vm/simulator_mips.h | 8 ++ runtime/vm/stub_code_arm.cc | 32 +++++++- runtime/vm/stub_code_ia32.cc | 1 + runtime/vm/stub_code_x64.cc | 1 + 16 files changed, 269 insertions(+), 77 deletions(-) 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.