Index: src/arm/simulator-arm.cc |
=================================================================== |
--- src/arm/simulator-arm.cc (revision 2053) |
+++ src/arm/simulator-arm.cc (working copy) |
@@ -1,4 +1,4 @@ |
-// Copyright 2008 the V8 project authors. All rights reserved. |
+// Copyright 2009 the V8 project authors. All rights reserved. |
// Redistribution and use in source and binary forms, with or without |
// modification, are permitted provided that the following conditions are |
// met: |
@@ -30,6 +30,7 @@ |
#include "v8.h" |
#include "disasm.h" |
+#include "assembler.h" |
#include "arm/constants-arm.h" |
#include "arm/simulator-arm.h" |
@@ -380,7 +381,18 @@ |
} |
+bool Simulator::initialized_ = false; |
+ |
+ |
+void Simulator::Initialize() { |
+ if (initialized_) return; |
+ initialized_ = true; |
+ ::v8::internal::ExternalReference::set_redirector(&RedirectExternalReference); |
+} |
+ |
+ |
Simulator::Simulator() { |
+ ASSERT(initialized_); |
// Setup simulator support first. Some of this information is needed to |
// setup the architecture state. |
size_t stack_size = 1 * 1024*1024; // allocate 1MB for stack |
@@ -412,10 +424,69 @@ |
} |
+// 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 swi (software-interrupt) instruction that is handled by |
+// the simulator. We write the original destination of the jump just after the |
iposva
2009/06/08 21:48:41
Please change the comment to say "We write the ori
|
+// swi instruction so the simulator knows what to call. |
+class Redirection { |
+ public: |
+ Redirection(void* external_function, bool fp_return) |
+ : external_function_(external_function), |
+ swi_instruction_((AL << 28) | (0xf << 24) | call_rt_redirected), |
+ fp_return_(fp_return), |
+ next_(list_) { |
+ list_ = this; |
+ } |
+ |
+ void* address_of_swi_instruction() { |
+ return reinterpret_cast<void*>(&swi_instruction_); |
+ } |
+ |
+ void* external_function() { return external_function_; } |
+ bool fp_return() { return fp_return_; } |
+ |
+ static Redirection* Get(void* external_function, bool fp_return) { |
+ Redirection* current; |
+ for (current = list_; current != NULL; current = current->next_) { |
+ if (current->external_function_ == external_function) return current; |
+ } |
+ return new Redirection(external_function, fp_return); |
+ } |
+ |
+ static Redirection* FromSwiInstruction(Instr* swi_instruction) { |
+ char* addr_of_swi = reinterpret_cast<char*>(swi_instruction); |
+ char* addr_of_redirection = |
+ addr_of_swi - OFFSET_OF(Redirection, swi_instruction_); |
+ return reinterpret_cast<Redirection*>(addr_of_redirection); |
+ } |
+ |
+ private: |
+ void* external_function_; |
+ uint32_t swi_instruction_; |
+ bool fp_return_; |
+ Redirection* next_; |
+ static Redirection* list_; |
+}; |
+ |
+ |
+Redirection* Redirection::list_ = NULL; |
+ |
+ |
+void* Simulator::RedirectExternalReference(void* external_function, |
+ bool fp_return) { |
+ Redirection* redirection = Redirection::Get(external_function, fp_return); |
+ return redirection->address_of_swi_instruction(); |
+} |
+ |
+ |
// Create one simulator per thread and keep it in thread local storage. |
static v8::internal::Thread::LocalStorageKey simulator_key = |
v8::internal::Thread::CreateThreadLocalKey(); |
iposva
2009/06/08 21:48:41
Please move this static initializer into the Initi
|
+ |
// Get the active Simulator for the current thread. |
Simulator* Simulator::current() { |
Simulator* sim = reinterpret_cast<Simulator*>( |
@@ -921,7 +992,14 @@ |
// 64-bit value. With the code below we assume that all runtime calls return |
// 64 bits of result. If they don't, the r1 result register contains a bogus |
// value, which is fine because it is caller-saved. |
-typedef int64_t (*SimulatorRuntimeCall)(intptr_t arg0, intptr_t arg1); |
+typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0, |
+ int32_t arg1, |
+ int32_t arg2, |
+ int32_t arg3); |
+typedef double (*SimulatorRuntimeFPCall)(int32_t arg0, |
+ int32_t arg1, |
+ int32_t arg2, |
+ int32_t arg3); |
// Software interrupt instructions are used by the simulator to call into the |
@@ -929,61 +1007,58 @@ |
void Simulator::SoftwareInterrupt(Instr* instr) { |
int swi = instr->SwiField(); |
switch (swi) { |
- case call_rt_r5: { |
- SimulatorRuntimeCall target = |
- reinterpret_cast<SimulatorRuntimeCall>(get_register(r5)); |
- intptr_t arg0 = get_register(r0); |
- intptr_t arg1 = get_register(r1); |
- int64_t result = target(arg0, arg1); |
- int32_t lo_res = static_cast<int32_t>(result); |
- int32_t hi_res = static_cast<int32_t>(result >> 32); |
- set_register(r0, lo_res); |
- set_register(r1, hi_res); |
- set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); |
+ case call_rt_redirected: { |
+ Redirection* redirection = Redirection::FromSwiInstruction(instr); |
+ int32_t arg0 = get_register(r0); |
+ int32_t arg1 = get_register(r1); |
+ int32_t arg2 = get_register(r2); |
+ int32_t arg3 = get_register(r3); |
+ // This is dodgy but it works because the C entry stubs are never moved. |
+ // See comment in codegen-arm.cc and bug 1242173. |
+ int32_t saved_lr = get_register(lr); |
+ if (redirection->fp_return()) { |
+ intptr_t external = |
+ reinterpret_cast<intptr_t>(redirection->external_function()); |
+ SimulatorRuntimeFPCall target = |
+ reinterpret_cast<SimulatorRuntimeFPCall>(external); |
+ if (::v8::internal::FLAG_trace_sim) { |
+ double x, y; |
+ GetFpArgs(&x, &y); |
+ PrintF("Call to host function at %p with args %f, %f\n", |
+ FUNCTION_ADDR(target), x, y); |
+ } |
+ double result = target(arg0, arg1, arg2, arg3); |
+ SetFpResult(result); |
+ } else { |
+ intptr_t external = |
+ reinterpret_cast<int32_t>(redirection->external_function()); |
+ SimulatorRuntimeCall target = |
+ reinterpret_cast<SimulatorRuntimeCall>(external); |
+ if (::v8::internal::FLAG_trace_sim) { |
+ PrintF( |
+ "Call to host function at %p with args %08x, %08x, %08x, %08x\n", |
+ FUNCTION_ADDR(target), |
+ arg0, |
+ arg1, |
+ arg2, |
+ arg3); |
+ } |
+ int64_t result = target(arg0, arg1, arg2, arg3); |
+ int32_t lo_res = static_cast<int32_t>(result); |
+ int32_t hi_res = static_cast<int32_t>(result >> 32); |
+ set_register(r0, lo_res); |
+ set_register(r1, hi_res); |
+ set_register(r0, result); |
iposva
2009/06/08 21:48:41
Isn't the second write to r0 redundant here? Stran
Erik Corry
2009/06/09 09:27:00
Fixed.
|
+ } |
+ set_register(lr, saved_lr); |
+ set_pc(get_register(lr)); |
break; |
} |
- case call_rt_r2: { |
- SimulatorRuntimeCall target = |
- reinterpret_cast<SimulatorRuntimeCall>(get_register(r2)); |
- intptr_t arg0 = get_register(r0); |
- intptr_t arg1 = get_register(r1); |
- int64_t result = target(arg0, arg1); |
- int32_t lo_res = static_cast<int32_t>(result); |
- int32_t hi_res = static_cast<int32_t>(result >> 32); |
- set_register(r0, lo_res); |
- set_register(r1, hi_res); |
- set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); |
- break; |
- } |
case break_point: { |
Debugger dbg(this); |
dbg.Debug(); |
break; |
} |
- { |
- double x, y, z; |
- case simulator_fp_add: |
- GetFpArgs(&x, &y); |
- z = x + y; |
- SetFpResult(z); |
- TrashCallerSaveRegisters(); |
- set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); |
- break; |
- case simulator_fp_sub: |
- GetFpArgs(&x, &y); |
- z = x - y; |
- SetFpResult(z); |
- TrashCallerSaveRegisters(); |
- set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); |
- break; |
- case simulator_fp_mul: |
- GetFpArgs(&x, &y); |
- z = x * y; |
- SetFpResult(z); |
- TrashCallerSaveRegisters(); |
- set_pc(reinterpret_cast<int32_t>(instr) + Instr::kInstrSize); |
- break; |
- } |
default: { |
UNREACHABLE(); |
break; |