Chromium Code Reviews| 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; |