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
This commit is contained in:
@@ -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<int32_t>(object.raw()));
|
||||
} else if (object.InVMHeap()) {
|
||||
|
||||
@@ -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<int32_t>(object.raw()));
|
||||
} else if (object.InVMHeap()) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
+64
-34
@@ -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<ExcpHandler>(
|
||||
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<ErrorHandler>(
|
||||
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<ExcpHandler>(
|
||||
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<uword>(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<ErrorHandler>(
|
||||
StubCode::JumpToErrorHandlerEntryPoint());
|
||||
func(program_counter, stack_pointer, frame_pointer, raw_error);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+36
-10
@@ -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<IncrementCode>(instructions.EntryPoint())());
|
||||
uword entry_point = instructions.EntryPoint();
|
||||
intptr_t retval = 0;
|
||||
#if defined(USING_SIMULATOR)
|
||||
retval = bit_copy<intptr_t, int64_t>(Simulator::Current()->Call(
|
||||
static_cast<int32_t>(entry_point), 0, 0, 0, 0));
|
||||
#else
|
||||
typedef intptr_t (*IncrementCode)();
|
||||
retval = reinterpret_cast<IncrementCode>(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<uword, int64_t>(Simulator::Current()->Call(
|
||||
static_cast<int32_t>(instructions.EntryPoint()), 0, 0, 0, 0));
|
||||
#else
|
||||
typedef uword (*EmbedStringCode)();
|
||||
uword retval = reinterpret_cast<EmbedStringCode>(instructions.EntryPoint())();
|
||||
retval = reinterpret_cast<EmbedStringCode>(instructions.EntryPoint())();
|
||||
#endif
|
||||
EXPECT((retval & kSmiTagMask) == kHeapObjectTag);
|
||||
String& string_object = String::Handle();
|
||||
string_object ^= reinterpret_cast<RawInstructions*>(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<intptr_t, int64_t>(Simulator::Current()->Call(
|
||||
static_cast<int32_t>(instructions.EntryPoint()), 0, 0, 0, 0));
|
||||
#else
|
||||
typedef intptr_t (*EmbedSmiCode)();
|
||||
intptr_t retval =
|
||||
reinterpret_cast<EmbedSmiCode>(instructions.EntryPoint())();
|
||||
retval = reinterpret_cast<EmbedSmiCode>(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<intptr_t, int64_t>(Simulator::Current()->Call(
|
||||
static_cast<int32_t>(instructions.EntryPoint()), 0, 0, 0, 0));
|
||||
#else
|
||||
typedef intptr_t (*EmbedSmiCode)();
|
||||
intptr_t retval =
|
||||
reinterpret_cast<EmbedSmiCode>(instructions.EntryPoint())();
|
||||
retval = reinterpret_cast<EmbedSmiCode>(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
|
||||
|
||||
+32
-13
@@ -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<uword>(sim->get_register(SP));
|
||||
native_sp_ = reinterpret_cast<uword>(&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<int32_t>(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<uword>(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<int32_t>(pc));
|
||||
set_register(SP, static_cast<int32_t>(sp));
|
||||
set_register(FP, static_cast<int32_t>(fp));
|
||||
ASSERT(raw_exception != NULL);
|
||||
set_register(kExceptionObjectReg, bit_cast<int32_t>(raw_exception));
|
||||
if (raw_stacktrace != NULL) {
|
||||
set_register(kStackTraceObjectReg, bit_cast<int32_t>(raw_stacktrace));
|
||||
}
|
||||
buf->Longjmp();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<uword>(sim->get_register(SP));
|
||||
native_sp_ = reinterpret_cast<uword>(&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<uword>(isolate->top_resource()) < native_sp)) {
|
||||
isolate->top_resource()->~StackResource();
|
||||
}
|
||||
|
||||
// Unwind the C++ stack and continue simulation in the target frame.
|
||||
set_pc(static_cast<int32_t>(pc));
|
||||
set_register(SP, static_cast<int32_t>(sp));
|
||||
set_register(FP, static_cast<int32_t>(fp));
|
||||
ASSERT(raw_exception != NULL);
|
||||
set_register(kExceptionObjectReg, bit_cast<int32_t>(raw_exception));
|
||||
if (raw_stacktrace != NULL) {
|
||||
set_register(kStackTraceObjectReg, bit_cast<int32_t>(raw_stacktrace));
|
||||
}
|
||||
buf->Longjmp();
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(HOST_ARCH_MIPS)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user