Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(579)

Unified Diff: runtime/vm/simulator_mips.cc

Issue 13407003: Third codegen test passing for simulated MIPS. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/simulator_mips.h ('k') | runtime/vm/stack_frame_mips.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/simulator_mips.cc
===================================================================
--- runtime/vm/simulator_mips.cc (revision 20788)
+++ runtime/vm/simulator_mips.cc (working copy)
@@ -2,6 +2,10 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+#include <math.h> // for isnan.
+#include <setjmp.h>
+#include <stdlib.h>
+
#include "vm/globals.h"
#if defined(TARGET_ARCH_MIPS)
@@ -13,9 +17,12 @@
#include "vm/assembler.h"
#include "vm/constants_mips.h"
#include "vm/disassembler.h"
+#include "vm/native_arguments.h"
+#include "vm/thread.h"
namespace dart {
+DEFINE_FLAG(bool, trace_sim, false, "Trace simulator execution.");
DEFINE_FLAG(int, stop_sim_at, 0, "Address to stop simulator at.");
@@ -26,6 +33,46 @@
#define SScanF sscanf // NOLINT
+// SimulatorSetjmpBuffer are linked together, and the last created one
+// is referenced by the Simulator. When an exception is thrown, the exception
+// runtime looks at where to jump and finds the corresponding
+// SimulatorSetjmpBuffer based on the stack pointer of the exception handler.
+// The runtime then does a Longjmp on that buffer to return to the simulator.
+class SimulatorSetjmpBuffer {
+ public:
+ int Setjmp() { return setjmp(buffer_); }
+ void Longjmp() {
+ // "This" is now the last setjmp buffer.
+ simulator_->set_last_setjmp_buffer(this);
+ longjmp(buffer_, 1);
+ }
+
+ explicit SimulatorSetjmpBuffer(Simulator* sim) {
+ simulator_ = sim;
+ link_ = sim->last_setjmp_buffer();
+ sim->set_last_setjmp_buffer(this);
+ sp_ = sim->get_register(SP);
+ }
+
+ ~SimulatorSetjmpBuffer() {
+ ASSERT(simulator_->last_setjmp_buffer() == this);
+ simulator_->set_last_setjmp_buffer(link_);
+ }
+
+ SimulatorSetjmpBuffer* link() { return link_; }
+
+ int32_t sp() { return sp_; }
+
+ private:
+ int32_t sp_;
+ Simulator* simulator_;
+ SimulatorSetjmpBuffer* link_;
+ jmp_buf buffer_;
+
+ friend class Simulator;
+};
+
+
// The SimulatorDebugger class is used by the simulator while debugging
// simulated MIPS code.
class SimulatorDebugger {
@@ -510,6 +557,68 @@
}
+// When the generated code calls an external reference we need to catch that in
+// the simulator. The external reference will be a function compiled for the
+// host architecture. We need to call that function instead of trying to
+// execute it with the simulator. We do that by redirecting the external
+// reference to a break instruction with code 2 that is handled by
+// the simulator. We write the original destination of the jump just at a known
+// offset from the break instruction so the simulator knows what to call.
+class Redirection {
+ public:
+ uword address_of_break_instruction() {
+ return reinterpret_cast<uword>(&break_instruction_);
+ }
+
+ uword external_function() const { return external_function_; }
+
+ Simulator::CallKind call_kind() const { return call_kind_; }
+
+ static Redirection* Get(uword external_function,
+ Simulator::CallKind call_kind) {
+ Redirection* current;
+ for (current = list_; current != NULL; current = current->next_) {
+ if (current->external_function_ == external_function) return current;
+ }
+ return new Redirection(external_function, call_kind);
+ }
+
+ static Redirection* FromBreakInstruction(Instr* break_instruction) {
+ char* addr_of_break = reinterpret_cast<char*>(break_instruction);
+ char* addr_of_redirection =
+ addr_of_break - OFFSET_OF(Redirection, break_instruction_);
+ return reinterpret_cast<Redirection*>(addr_of_redirection);
+ }
+
+ private:
+ static const int32_t kRedirectInstruction =
+ Instr::kBreakPointInstruction | (Instr::kRedirectCode << kBreakCodeShift);
+
+ Redirection(uword external_function, Simulator::CallKind call_kind)
+ : external_function_(external_function),
+ call_kind_(call_kind),
+ break_instruction_(kRedirectInstruction),
+ next_(list_) {
+ list_ = this;
+ }
+
+ uword external_function_;
+ Simulator::CallKind call_kind_;
+ uint32_t break_instruction_;
+ Redirection* next_;
+ static Redirection* list_;
+};
+
+
+Redirection* Redirection::list_ = NULL;
+
+
+uword Simulator::RedirectExternalReference(uword function, CallKind call_kind) {
+ Redirection* redirection = Redirection::Get(function, call_kind);
+ return redirection->address_of_break_instruction();
+}
+
+
// Get the active Simulator for the current isolate.
Simulator* Simulator::Current() {
Simulator* simulator = Isolate::Current()->simulator();
@@ -691,6 +800,102 @@
}
+// Calls into the Dart runtime are based on this interface.
+typedef void (*SimulatorRuntimeCall)(NativeArguments arguments);
+
+// Calls to leaf Dart runtime functions are based on this interface.
+typedef int32_t (*SimulatorLeafRuntimeCall)(
+ int32_t r0, int32_t r1, int32_t r2, int32_t r3);
+
+// Calls to native Dart functions are based on this interface.
+typedef void (*SimulatorNativeCall)(NativeArguments* arguments);
+
+
+void Simulator::DoBreak(Instr *instr) {
+ ASSERT(instr->OpcodeField() == SPECIAL);
+ ASSERT(instr->FunctionField() == BREAK);
+ if (instr->BreakCodeField() == Instr::kStopMessageCode) {
+ SimulatorDebugger dbg(this);
+ const char* message = *reinterpret_cast<const char**>(
+ reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize);
+ set_pc(get_pc() + Instr::kInstrSize);
+ dbg.Stop(instr, message);
+ } else if (instr->BreakCodeField() == Instr::kRedirectCode) {
+ SimulatorSetjmpBuffer buffer(this);
+
+ if (!setjmp(buffer.buffer_)) {
+ int32_t saved_ra = get_register(RA);
+ Redirection* redirection = Redirection::FromBreakInstruction(instr);
+ uword external = redirection->external_function();
+ if (FLAG_trace_sim) {
+ OS::Print("Call to host function at 0x%"Pd"\n", external);
+ }
+ if (redirection->call_kind() == kRuntimeCall) {
+ NativeArguments arguments;
+ ASSERT(sizeof(NativeArguments) == 4*kWordSize);
+ arguments.isolate_ = reinterpret_cast<Isolate*>(get_register(A0));
+ arguments.argc_tag_ = get_register(A1);
+ arguments.argv_ = reinterpret_cast<RawObject*(*)[]>(get_register(A2));
+ arguments.retval_ = reinterpret_cast<RawObject**>(get_register(A3));
+ SimulatorRuntimeCall target =
+ reinterpret_cast<SimulatorRuntimeCall>(external);
+ target(arguments);
+ set_register(V0, icount_); // Zap result register from void function.
+ } else if (redirection->call_kind() == kLeafRuntimeCall) {
+ int32_t a0 = get_register(A0);
+ int32_t a1 = get_register(A1);
+ int32_t a2 = get_register(A2);
+ int32_t a3 = get_register(A3);
+ SimulatorLeafRuntimeCall target =
+ reinterpret_cast<SimulatorLeafRuntimeCall>(external);
+ a0 = target(a0, a1, a2, a3);
+ set_register(V0, a0); // Set returned result from function.
+ } else {
+ ASSERT(redirection->call_kind() == kNativeCall);
+ NativeArguments* arguments;
+ arguments = reinterpret_cast<NativeArguments*>(get_register(A0));
+ SimulatorNativeCall target =
+ reinterpret_cast<SimulatorNativeCall>(external);
+ target(arguments);
+ set_register(V0, icount_); // Zap result register from void function.
+ }
+
+ // Zap caller-saved registers, since the actual runtime call could have
+ // used them.
+ set_register(T0, icount_);
+ set_register(T1, icount_);
+ set_register(T2, icount_);
+ set_register(T3, icount_);
+ set_register(T4, icount_);
+ set_register(T5, icount_);
+ set_register(T6, icount_);
+ set_register(T7, icount_);
+ set_register(T8, icount_);
+ set_register(T9, icount_);
+
+ set_register(A0, icount_);
+ set_register(A1, icount_);
+ set_register(A2, icount_);
+ set_register(A3, icount_);
+ set_register(TMP, icount_);
+ set_register(RA, icount_);
+
+ // Zap floating point registers.
+ double zap_dvalue = static_cast<double>(icount_);
+ for (int i = F0; i <= F31; i++) {
+ set_fregister(static_cast<FRegister>(i), zap_dvalue);
+ }
+
+ // Return.
+ set_pc(saved_ra);
+ }
+ } else {
+ SimulatorDebugger dbg(this);
+ dbg.Stop(instr, "breakpoint");
+ }
+}
+
+
void Simulator::DecodeSpecial(Instr* instr) {
ASSERT(instr->OpcodeField() == SPECIAL);
switch (instr->FunctionField()) {
@@ -711,16 +916,7 @@
break;
}
case BREAK: {
- if (instr->BreakCodeField() == Instr::kStopMessageCode) {
- SimulatorDebugger dbg(this);
- const char* message = *reinterpret_cast<const char**>(
- reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize);
- set_pc(get_pc() + Instr::kInstrSize);
- dbg.Stop(instr, message);
- } else {
- SimulatorDebugger dbg(this);
- dbg.Stop(instr, "breakpoint");
- }
+ DoBreak(instr);
break;
}
case DIV: {
« no previous file with comments | « runtime/vm/simulator_mips.h ('k') | runtime/vm/stack_frame_mips.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698