Chromium Code Reviews| Index: src/a64/simulator-a64.cc |
| diff --git a/src/a64/simulator-a64.cc b/src/a64/simulator-a64.cc |
| index 3801bf7514f46dfcadf50bb609d31bd32bcdc535..87b8a61e14162fce2cf1bb95258c549fb6f1eda7 100644 |
| --- a/src/a64/simulator-a64.cc |
| +++ b/src/a64/simulator-a64.cc |
| @@ -469,7 +469,8 @@ class Redirection { |
| return reinterpret_cast<void*>(&redirect_call_); |
| } |
| - void* external_function() { return external_function_; } |
| + template <typename T> |
| + T external_function() { return reinterpret_cast<T>(external_function_); } |
|
ulan
2014/03/19 08:53:19
Indentation is off
Alexandre Rames
2014/03/20 09:49:33
Fixing before landing.
|
| ExternalReference::Type type() { return type_; } |
| static Redirection* Get(void* external_function, |
| @@ -495,7 +496,7 @@ class Redirection { |
| static void* ReverseRedirection(int64_t reg) { |
| Redirection* redirection = |
| FromHltInstruction(reinterpret_cast<Instruction*>(reg)); |
| - return redirection->external_function(); |
| + return redirection->external_function<void*>(); |
| } |
| private: |
| @@ -506,6 +507,223 @@ class Redirection { |
| }; |
| +// Calls into the V8 runtime are based on this very simple interface. |
| +// Note: To be able to return two values from some calls the code in runtime.cc |
| +// uses the ObjectPair structure. |
| +// The simulator assumes all runtime calls return two 64-bits values. If they |
| +// don't, register x1 is clobbered. This is fine because x1 is caller-saved. |
| +struct ObjectPair { |
| + int64_t res0; |
| + int64_t res1; |
| +}; |
| + |
| + |
| +typedef ObjectPair (*SimulatorRuntimeCall)(int64_t arg0, |
| + int64_t arg1, |
| + int64_t arg2, |
| + int64_t arg3, |
| + int64_t arg4, |
| + int64_t arg5, |
| + int64_t arg6, |
| + int64_t arg7); |
| + |
| +typedef int64_t (*SimulatorRuntimeCompareCall)(double arg1, double arg2); |
| +typedef double (*SimulatorRuntimeFPFPCall)(double arg1, double arg2); |
| +typedef double (*SimulatorRuntimeFPCall)(double arg1); |
| +typedef double (*SimulatorRuntimeFPIntCall)(double arg1, int32_t arg2); |
| + |
| +// This signature supports direct call in to API function native callback |
| +// (refer to InvocationCallback in v8.h). |
| +typedef void (*SimulatorRuntimeDirectApiCall)(int64_t arg0); |
| +typedef void (*SimulatorRuntimeProfilingApiCall)(int64_t arg0, void* arg1); |
| + |
| +// This signature supports direct call to accessor getter callback. |
| +typedef void (*SimulatorRuntimeDirectGetterCall)(int64_t arg0, int64_t arg1); |
| +typedef void (*SimulatorRuntimeProfilingGetterCall)(int64_t arg0, int64_t arg1, |
| + void* arg2); |
| + |
| +void Simulator::DoRuntimeCall(Instruction* instr) { |
| + Redirection* redirection = Redirection::FromHltInstruction(instr); |
| + |
| + // The called C code might itself call simulated code, so any |
| + // caller-saved registers (including lr) could still be clobbered by a |
| + // redirected call. |
| + Instruction* return_address = lr(); |
| + |
| + int64_t external = redirection->external_function<int64_t>(); |
| + |
| + TraceSim("Call to host function at %p\n", |
| + redirection->external_function<void*>()); |
| + |
| + // SP must be 16-byte-aligned at the call interface. |
| + bool stack_alignment_exception = ((sp() & 0xf) != 0); |
| + if (stack_alignment_exception) { |
| + TraceSim(" with unaligned stack 0x%016" PRIx64 ".\n", sp()); |
| + FATAL("ALIGNMENT EXCEPTION"); |
| + } |
| + |
| + switch (redirection->type()) { |
| + default: |
| + TraceSim("Type: Unknown.\n"); |
| + UNREACHABLE(); |
| + break; |
| + |
| + case ExternalReference::BUILTIN_CALL: { |
| + // MaybeObject* f(v8::internal::Arguments). |
| + TraceSim("Type: BUILTIN_CALL\n"); |
| + SimulatorRuntimeCall target = |
| + reinterpret_cast<SimulatorRuntimeCall>(external); |
| + |
| + // We don't know how many arguments are being passed, but we can |
| + // pass 8 without touching the stack. They will be ignored by the |
| + // host function if they aren't used. |
| + TraceSim("Arguments: " |
| + "0x%016" PRIx64 ", 0x%016" PRIx64 ", " |
| + "0x%016" PRIx64 ", 0x%016" PRIx64 ", " |
| + "0x%016" PRIx64 ", 0x%016" PRIx64 ", " |
| + "0x%016" PRIx64 ", 0x%016" PRIx64, |
| + xreg(0), xreg(1), xreg(2), xreg(3), |
| + xreg(4), xreg(5), xreg(6), xreg(7)); |
| + ObjectPair result = target(xreg(0), xreg(1), xreg(2), xreg(3), |
| + xreg(4), xreg(5), xreg(6), xreg(7)); |
| + TraceSim("Returned: {0x%" PRIx64 ", 0x%" PRIx64 "}\n", |
| + result.res0, result.res1); |
| +#ifdef DEBUG |
| + CorruptAllCallerSavedCPURegisters(); |
| +#endif |
| + set_xreg(0, result.res0); |
| + set_xreg(1, result.res1); |
| + break; |
| + } |
| + |
| + case ExternalReference::DIRECT_API_CALL: { |
| + // void f(v8::FunctionCallbackInfo&) |
| + TraceSim("Type: DIRECT_API_CALL\n"); |
| + SimulatorRuntimeDirectApiCall target = |
| + reinterpret_cast<SimulatorRuntimeDirectApiCall>(external); |
| + TraceSim("Arguments: 0x%016" PRIx64 "\n", xreg(0)); |
| + target(xreg(0)); |
| + TraceSim("No return value."); |
| +#ifdef DEBUG |
| + CorruptAllCallerSavedCPURegisters(); |
| +#endif |
| + break; |
| + } |
| + |
| + case ExternalReference::BUILTIN_COMPARE_CALL: { |
| + // int f(double, double) |
| + TraceSim("Type: BUILTIN_COMPARE_CALL\n"); |
| + SimulatorRuntimeCompareCall target = |
| + reinterpret_cast<SimulatorRuntimeCompareCall>(external); |
| + TraceSim("Arguments: %f, %f\n", dreg(0), dreg(1)); |
| + int64_t result = target(dreg(0), dreg(1)); |
| + TraceSim("Returned: %" PRId64 "\n", result); |
| +#ifdef DEBUG |
| + CorruptAllCallerSavedCPURegisters(); |
| +#endif |
| + set_xreg(0, result); |
| + break; |
| + } |
| + |
| + case ExternalReference::BUILTIN_FP_CALL: { |
| + // double f(double) |
| + TraceSim("Type: BUILTIN_FP_CALL\n"); |
| + SimulatorRuntimeFPCall target = |
| + reinterpret_cast<SimulatorRuntimeFPCall>(external); |
| + TraceSim("Argument: %f\n", dreg(0)); |
| + double result = target(dreg(0)); |
| + TraceSim("Returned: %f\n", result); |
| +#ifdef DEBUG |
| + CorruptAllCallerSavedCPURegisters(); |
| +#endif |
| + set_dreg(0, result); |
| + break; |
| + } |
| + |
| + case ExternalReference::BUILTIN_FP_FP_CALL: { |
| + // double f(double, double) |
| + TraceSim("Type: BUILTIN_FP_FP_CALL\n"); |
| + SimulatorRuntimeFPFPCall target = |
| + reinterpret_cast<SimulatorRuntimeFPFPCall>(external); |
| + TraceSim("Arguments: %f, %f\n", dreg(0), dreg(1)); |
| + double result = target(dreg(0), dreg(1)); |
| + TraceSim("Returned: %f\n", result); |
| +#ifdef DEBUG |
| + CorruptAllCallerSavedCPURegisters(); |
| +#endif |
| + set_dreg(0, result); |
| + break; |
| + } |
| + |
| + case ExternalReference::BUILTIN_FP_INT_CALL: { |
| + // double f(double, int) |
| + TraceSim("Type: BUILTIN_FP_INT_CALL\n"); |
| + SimulatorRuntimeFPIntCall target = |
| + reinterpret_cast<SimulatorRuntimeFPIntCall>(external); |
| + TraceSim("Arguments: %f, %d\n", dreg(0), wreg(0)); |
| + double result = target(dreg(0), wreg(0)); |
| + TraceSim("Returned: %f\n", result); |
| +#ifdef DEBUG |
| + CorruptAllCallerSavedCPURegisters(); |
| +#endif |
| + set_dreg(0, result); |
| + break; |
| + } |
| + |
| + case ExternalReference::DIRECT_GETTER_CALL: { |
| + // void f(Local<String> property, PropertyCallbackInfo& info) |
| + TraceSim("Type: DIRECT_GETTER_CALL\n"); |
| + SimulatorRuntimeDirectGetterCall target = |
| + reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external); |
| + TraceSim("Arguments: 0x%016" PRIx64 ", 0x%016" PRIx64 "\n", |
| + xreg(0), xreg(1)); |
| + target(xreg(0), xreg(1)); |
| + TraceSim("No return value."); |
| +#ifdef DEBUG |
| + CorruptAllCallerSavedCPURegisters(); |
| +#endif |
| + break; |
| + } |
| + |
| + case ExternalReference::PROFILING_API_CALL: { |
| + // void f(v8::FunctionCallbackInfo&, v8::FunctionCallback) |
| + TraceSim("Type: PROFILING_API_CALL\n"); |
| + SimulatorRuntimeProfilingApiCall target = |
| + reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external); |
| + void* arg1 = Redirection::ReverseRedirection(xreg(1)); |
| + TraceSim("Arguments: 0x%016" PRIx64 ", %p\n", xreg(0), arg1); |
| + target(xreg(0), arg1); |
| + TraceSim("No return value."); |
| +#ifdef DEBUG |
| + CorruptAllCallerSavedCPURegisters(); |
| +#endif |
| + break; |
| + } |
| + |
| + case ExternalReference::PROFILING_GETTER_CALL: { |
| + // void f(Local<String> property, PropertyCallbackInfo& info, |
| + // AccessorGetterCallback callback) |
| + TraceSim("Type: PROFILING_GETTER_CALL\n"); |
| + SimulatorRuntimeProfilingGetterCall target = |
| + reinterpret_cast<SimulatorRuntimeProfilingGetterCall>( |
| + external); |
| + void* arg2 = Redirection::ReverseRedirection(xreg(2)); |
| + TraceSim("Arguments: 0x%016" PRIx64 ", 0x%016" PRIx64 ", %p\n", |
| + xreg(0), xreg(1), arg2); |
| + target(xreg(0), xreg(1), arg2); |
| + TraceSim("No return value."); |
| +#ifdef DEBUG |
| + CorruptAllCallerSavedCPURegisters(); |
| +#endif |
| + break; |
| + } |
| + } |
| + |
| + set_lr(return_address); |
| + set_pc(return_address); |
| +} |
| + |
| + |
| void* Simulator::RedirectExternalReference(void* external_function, |
| ExternalReference::Type type) { |
| Redirection* redirection = Redirection::Get(external_function, type); |
| @@ -3299,41 +3517,6 @@ void Simulator::Debug() { |
| } |
| -// Calls into the V8 runtime are based on this very simple interface. |
| -// Note: To be able to return two values from some calls the code in runtime.cc |
| -// uses the ObjectPair structure. |
| -// The simulator assumes all runtime calls return two 64-bits values. If they |
| -// don't, register x1 is clobbered. This is fine because x1 is caller-saved. |
| -struct ObjectPair { |
| - int64_t res0; |
| - int64_t res1; |
| -}; |
| - |
| - |
| -typedef ObjectPair (*SimulatorRuntimeCall)(int64_t arg0, |
| - int64_t arg1, |
| - int64_t arg2, |
| - int64_t arg3, |
| - int64_t arg4, |
| - int64_t arg5, |
| - int64_t arg6, |
| - int64_t arg7); |
| - |
| -typedef int64_t (*SimulatorRuntimeCompareCall)(double arg1, double arg2); |
| -typedef double (*SimulatorRuntimeFPFPCall)(double arg1, double arg2); |
| -typedef double (*SimulatorRuntimeFPCall)(double arg1); |
| -typedef double (*SimulatorRuntimeFPIntCall)(double arg1, int32_t arg2); |
| - |
| -// This signature supports direct call in to API function native callback |
| -// (refer to InvocationCallback in v8.h). |
| -typedef void (*SimulatorRuntimeDirectApiCall)(int64_t arg0); |
| -typedef void (*SimulatorRuntimeProfilingApiCall)(int64_t arg0, void* arg1); |
| - |
| -// This signature supports direct call to accessor getter callback. |
| -typedef void (*SimulatorRuntimeDirectGetterCall)(int64_t arg0, int64_t arg1); |
| -typedef void (*SimulatorRuntimeProfilingGetterCall)(int64_t arg0, int64_t arg1, |
| - void* arg2); |
| - |
| void Simulator::VisitException(Instruction* instr) { |
| // Define some colour codes to use for log messages. |
| // TODO(jbramley): Find a more elegant way of defining these. |
| @@ -3421,190 +3604,7 @@ void Simulator::VisitException(Instruction* instr) { |
| if (parameters & BREAK) Debug(); |
| } else if (instr->ImmException() == kImmExceptionIsRedirectedCall) { |
| - // TODO(all): Extract the call redirection code into a separate |
| - // function. |
| - |
| - Redirection* redirection = Redirection::FromHltInstruction(instr); |
| - |
| - // The called C code might itself call simulated code, so any |
| - // caller-saved registers (including lr) could still be clobbered by a |
| - // redirected call. |
| - Instruction* return_address = lr(); |
| - |
| - // TODO(jbramley): Make external_function() a template so that we don't |
| - // have to explicitly cast the result for each redirection type. |
| - int64_t external = |
| - reinterpret_cast<int64_t>(redirection->external_function()); |
| - |
| - TraceSim("Call to host function at %p\n", |
| - reinterpret_cast<void*>(redirection->external_function())); |
| - |
| - // SP must be 16 bytes aligned at the call interface. |
| - bool stack_alignment_exception = ((sp() & 0xf) != 0); |
| - if (stack_alignment_exception) { |
| - TraceSim(" with unaligned stack 0x%016" PRIx64 ".\n", sp()); |
| - FATAL("ALIGNMENT EXCEPTION"); |
| - } |
| - |
| - switch (redirection->type()) { |
| - default: |
| - TraceSim("Type: Unknown.\n"); |
| - UNREACHABLE(); |
| - break; |
| - |
| - case ExternalReference::BUILTIN_CALL: { |
| - // MaybeObject* f(v8::internal::Arguments). |
| - TraceSim("Type: BUILTIN_CALL\n"); |
| - SimulatorRuntimeCall target = |
| - reinterpret_cast<SimulatorRuntimeCall>(external); |
| - |
| - // We don't know how many arguments are being passed, but we can |
| - // pass 8 without touching the stack. They will be ignored by the |
| - // host function if they aren't used. |
| - TraceSim("Arguments: " |
| - "0x%016" PRIx64 ", 0x%016" PRIx64 ", " |
| - "0x%016" PRIx64 ", 0x%016" PRIx64 ", " |
| - "0x%016" PRIx64 ", 0x%016" PRIx64 ", " |
| - "0x%016" PRIx64 ", 0x%016" PRIx64, |
| - xreg(0), xreg(1), xreg(2), xreg(3), |
| - xreg(4), xreg(5), xreg(6), xreg(7)); |
| - ObjectPair result = target(xreg(0), xreg(1), xreg(2), xreg(3), |
| - xreg(4), xreg(5), xreg(6), xreg(7)); |
| - TraceSim("Returned: {0x%" PRIx64 ", 0x%" PRIx64"}\n", |
| - result.res0, result.res1); |
| -#ifdef DEBUG |
| - CorruptAllCallerSavedCPURegisters(); |
| -#endif |
| - set_xreg(0, result.res0); |
| - set_xreg(1, result.res1); |
| - break; |
| - } |
| - |
| - case ExternalReference::DIRECT_API_CALL: { |
| - // void f(v8::FunctionCallbackInfo&) |
| - TraceSim("Type: DIRECT_API_CALL\n"); |
| - SimulatorRuntimeDirectApiCall target = |
| - reinterpret_cast<SimulatorRuntimeDirectApiCall>(external); |
| - TraceSim("Arguments: 0x%016" PRIx64 "\n", xreg(0)); |
| - target(xreg(0)); |
| - TraceSim("No return value."); |
| -#ifdef DEBUG |
| - CorruptAllCallerSavedCPURegisters(); |
| -#endif |
| - break; |
| - } |
| - |
| - case ExternalReference::BUILTIN_COMPARE_CALL: { |
| - // int f(double, double) |
| - TraceSim("Type: BUILTIN_COMPARE_CALL\n"); |
| - SimulatorRuntimeCompareCall target = |
| - reinterpret_cast<SimulatorRuntimeCompareCall>(external); |
| - TraceSim("Arguments: %f, %f\n", dreg(0), dreg(1)); |
| - int64_t result = target(dreg(0), dreg(1)); |
| - TraceSim("Returned: %" PRId64 "\n", result); |
| -#ifdef DEBUG |
| - CorruptAllCallerSavedCPURegisters(); |
| -#endif |
| - set_xreg(0, result); |
| - break; |
| - } |
| - |
| - case ExternalReference::BUILTIN_FP_CALL: { |
| - // double f(double) |
| - TraceSim("Type: BUILTIN_FP_CALL\n"); |
| - SimulatorRuntimeFPCall target = |
| - reinterpret_cast<SimulatorRuntimeFPCall>(external); |
| - TraceSim("Argument: %f\n", dreg(0)); |
| - double result = target(dreg(0)); |
| - TraceSim("Returned: %f\n", result); |
| -#ifdef DEBUG |
| - CorruptAllCallerSavedCPURegisters(); |
| -#endif |
| - set_dreg(0, result); |
| - break; |
| - } |
| - |
| - case ExternalReference::BUILTIN_FP_FP_CALL: { |
| - // double f(double, double) |
| - TraceSim("Type: BUILTIN_FP_FP_CALL\n"); |
| - SimulatorRuntimeFPFPCall target = |
| - reinterpret_cast<SimulatorRuntimeFPFPCall>(external); |
| - TraceSim("Arguments: %f, %f\n", dreg(0), dreg(1)); |
| - double result = target(dreg(0), dreg(1)); |
| - TraceSim("Returned: %f\n", result); |
| -#ifdef DEBUG |
| - CorruptAllCallerSavedCPURegisters(); |
| -#endif |
| - set_dreg(0, result); |
| - break; |
| - } |
| - |
| - case ExternalReference::BUILTIN_FP_INT_CALL: { |
| - // double f(double, int) |
| - TraceSim("Type: BUILTIN_FP_INT_CALL\n"); |
| - SimulatorRuntimeFPIntCall target = |
| - reinterpret_cast<SimulatorRuntimeFPIntCall>(external); |
| - TraceSim("Arguments: %f, %d\n", dreg(0), wreg(0)); |
| - double result = target(dreg(0), wreg(0)); |
| - TraceSim("Returned: %f\n", result); |
| -#ifdef DEBUG |
| - CorruptAllCallerSavedCPURegisters(); |
| -#endif |
| - set_dreg(0, result); |
| - break; |
| - } |
| - |
| - case ExternalReference::DIRECT_GETTER_CALL: { |
| - // void f(Local<String> property, PropertyCallbackInfo& info) |
| - TraceSim("Type: DIRECT_GETTER_CALL\n"); |
| - SimulatorRuntimeDirectGetterCall target = |
| - reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external); |
| - TraceSim("Arguments: 0x%016" PRIx64 ", 0x%016" PRIx64 "\n", |
| - xreg(0), xreg(1)); |
| - target(xreg(0), xreg(1)); |
| - TraceSim("No return value."); |
| -#ifdef DEBUG |
| - CorruptAllCallerSavedCPURegisters(); |
| -#endif |
| - break; |
| - } |
| - |
| - case ExternalReference::PROFILING_API_CALL: { |
| - // void f(v8::FunctionCallbackInfo&, v8::FunctionCallback) |
| - TraceSim("Type: PROFILING_API_CALL\n"); |
| - SimulatorRuntimeProfilingApiCall target = |
| - reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external); |
| - void* arg1 = Redirection::ReverseRedirection(xreg(1)); |
| - TraceSim("Arguments: 0x%016" PRIx64 ", %p\n", xreg(0), arg1); |
| - target(xreg(0), arg1); |
| - TraceSim("No return value."); |
| -#ifdef DEBUG |
| - CorruptAllCallerSavedCPURegisters(); |
| -#endif |
| - break; |
| - } |
| - |
| - case ExternalReference::PROFILING_GETTER_CALL: { |
| - // void f(Local<String> property, PropertyCallbackInfo& info, |
| - // AccessorGetterCallback callback) |
| - TraceSim("Type: PROFILING_GETTER_CALL\n"); |
| - SimulatorRuntimeProfilingGetterCall target = |
| - reinterpret_cast<SimulatorRuntimeProfilingGetterCall>( |
| - external); |
| - void* arg2 = Redirection::ReverseRedirection(xreg(2)); |
| - TraceSim("Arguments: 0x%016" PRIx64 ", 0x%016" PRIx64 ", %p\n", |
| - xreg(0), xreg(1), arg2); |
| - target(xreg(0), xreg(1), arg2); |
| - TraceSim("No return value."); |
| -#ifdef DEBUG |
| - CorruptAllCallerSavedCPURegisters(); |
| -#endif |
| - break; |
| - } |
| - } |
| - |
| - set_lr(return_address); |
| - set_pc(return_address); |
| + DoRuntimeCall(instr); |
| } else if (instr->ImmException() == kImmExceptionIsPrintf) { |
| // Read the argument encoded inline in the instruction stream. |
| uint32_t type; |