Commit dcd3f06b authored by plind44@gmail.com's avatar plind44@gmail.com

MIPS: Accurate function prototypes for native calls from ARM simulator.

Port r14230 (76c22097)

Original commit message:
Native method invocation from the arm/simulator-arm.cc previously made
non-portable assumptions about calling conventions. This was okay for 32-bit
stack-based machines, where by-value structs are automatically materialized
on the stack, and where both int and double parameters could be passed on the
stack. However they are not okay for x86-64, which has an elaborate scheme
for passing parameters in registers.

This CL replaces the previous non-portable code paths with portable code,
using call-sites that accurately match the prototype of the callee.

BUG=

Review URL: https://codereview.chromium.org/13989008
Patch from Akos Palfi <palfia@homejinni.com>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14239 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent ca3f314f
...@@ -1091,12 +1091,14 @@ double Simulator::get_fpu_register_double(int fpureg) const { ...@@ -1091,12 +1091,14 @@ double Simulator::get_fpu_register_double(int fpureg) const {
} }
// For use in calls that take two double values, constructed either // Runtime FP routines take up to two double arguments and zero
// or one integer arguments. All are constructed here,
// from a0-a3 or f12 and f14. // from a0-a3 or f12 and f14.
void Simulator::GetFpArgs(double* x, double* y) { void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
if (!IsMipsSoftFloatABI) { if (!IsMipsSoftFloatABI) {
*x = get_fpu_register_double(12); *x = get_fpu_register_double(12);
*y = get_fpu_register_double(14); *y = get_fpu_register_double(14);
*z = registers_[1];
} else { } else {
// We use a char buffer to get around the strict-aliasing rules which // We use a char buffer to get around the strict-aliasing rules which
// otherwise allow the compiler to optimize away the copy. // otherwise allow the compiler to optimize away the copy.
...@@ -1107,48 +1109,13 @@ void Simulator::GetFpArgs(double* x, double* y) { ...@@ -1107,48 +1109,13 @@ void Simulator::GetFpArgs(double* x, double* y) {
reg_buffer[0] = get_register(a0); reg_buffer[0] = get_register(a0);
reg_buffer[1] = get_register(a1); reg_buffer[1] = get_register(a1);
memcpy(x, buffer, sizeof(buffer)); memcpy(x, buffer, sizeof(buffer));
// Registers a2 and a3 -> y. // Registers a2 and a3 -> y.
reg_buffer[0] = get_register(a2); reg_buffer[0] = get_register(a2);
reg_buffer[1] = get_register(a3); reg_buffer[1] = get_register(a3);
memcpy(y, buffer, sizeof(buffer)); memcpy(y, buffer, sizeof(buffer));
} // Register 2 -> z.
} memcpy(buffer, registers_ + 2, sizeof(*z));
memcpy(z, buffer, sizeof(*z));
// For use in calls that take one double value, constructed either
// from a0 and a1 or f12.
void Simulator::GetFpArgs(double* x) {
if (!IsMipsSoftFloatABI) {
*x = get_fpu_register_double(12);
} else {
// We use a char buffer to get around the strict-aliasing rules which
// otherwise allow the compiler to optimize away the copy.
char buffer[sizeof(*x)];
int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
// Registers a0 and a1 -> x.
reg_buffer[0] = get_register(a0);
reg_buffer[1] = get_register(a1);
memcpy(x, buffer, sizeof(buffer));
}
}
// For use in calls that take one double value constructed either
// from a0 and a1 or f12 and one integer value.
void Simulator::GetFpArgs(double* x, int32_t* y) {
if (!IsMipsSoftFloatABI) {
*x = get_fpu_register_double(12);
*y = get_register(a2);
} else {
// We use a char buffer to get around the strict-aliasing rules which
// otherwise allow the compiler to optimize away the copy.
char buffer[sizeof(*x)];
int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
// Registers 0 and 1 -> x.
reg_buffer[0] = get_register(a0);
reg_buffer[1] = get_register(a1);
memcpy(x, buffer, sizeof(buffer));
// Register 2 -> y. // Register 2 -> y.
reg_buffer[0] = get_register(a2); reg_buffer[0] = get_register(a2);
...@@ -1415,10 +1382,12 @@ typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0, ...@@ -1415,10 +1382,12 @@ typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
int32_t arg3, int32_t arg3,
int32_t arg4, int32_t arg4,
int32_t arg5); int32_t arg5);
typedef double (*SimulatorRuntimeFPCall)(int32_t arg0,
int32_t arg1, // These prototypes handle the four types of FP calls.
int32_t arg2, typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
int32_t arg3); typedef double (*SimulatorRuntimeFPFPCall)(double darg0, double darg1);
typedef double (*SimulatorRuntimeFPCall)(double darg0);
typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
// This signature supports direct call in to API function native callback // This signature supports direct call in to API function native callback
// (refer to InvocationCallback in v8.h). // (refer to InvocationCallback in v8.h).
...@@ -1495,46 +1464,81 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { ...@@ -1495,46 +1464,81 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
// simulator. Soft-float has additional abstraction of ExternalReference, // simulator. Soft-float has additional abstraction of ExternalReference,
// to support serialization. // to support serialization.
if (fp_call) { if (fp_call) {
SimulatorRuntimeFPCall target = double dval0, dval1; // one or two double parameters
reinterpret_cast<SimulatorRuntimeFPCall>(external); int32_t ival; // zero or one integer parameters
int64_t iresult = 0; // integer return value
double dresult = 0; // double return value
GetFpArgs(&dval0, &dval1, &ival);
SimulatorRuntimeCall generic_target =
reinterpret_cast<SimulatorRuntimeCall>(external);
if (::v8::internal::FLAG_trace_sim) { if (::v8::internal::FLAG_trace_sim) {
double dval0, dval1;
int32_t ival;
switch (redirection->type()) { switch (redirection->type()) {
case ExternalReference::BUILTIN_FP_FP_CALL: case ExternalReference::BUILTIN_FP_FP_CALL:
case ExternalReference::BUILTIN_COMPARE_CALL: case ExternalReference::BUILTIN_COMPARE_CALL:
GetFpArgs(&dval0, &dval1);
PrintF("Call to host function at %p with args %f, %f", PrintF("Call to host function at %p with args %f, %f",
FUNCTION_ADDR(target), dval0, dval1); FUNCTION_ADDR(generic_target), dval0, dval1);
break; break;
case ExternalReference::BUILTIN_FP_CALL: case ExternalReference::BUILTIN_FP_CALL:
GetFpArgs(&dval0);
PrintF("Call to host function at %p with arg %f", PrintF("Call to host function at %p with arg %f",
FUNCTION_ADDR(target), dval0); FUNCTION_ADDR(generic_target), dval0);
break; break;
case ExternalReference::BUILTIN_FP_INT_CALL: case ExternalReference::BUILTIN_FP_INT_CALL:
GetFpArgs(&dval0, &ival);
PrintF("Call to host function at %p with args %f, %d", PrintF("Call to host function at %p with args %f, %d",
FUNCTION_ADDR(target), dval0, ival); FUNCTION_ADDR(generic_target), dval0, ival);
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
break; break;
} }
} }
if (redirection->type() != ExternalReference::BUILTIN_COMPARE_CALL) { switch (redirection->type()) {
case ExternalReference::BUILTIN_COMPARE_CALL: {
SimulatorRuntimeCompareCall target =
reinterpret_cast<SimulatorRuntimeCompareCall>(external);
iresult = target(dval0, dval1);
set_register(v0, static_cast<int32_t>(iresult));
set_register(v1, static_cast<int32_t>(iresult >> 32));
break;
}
case ExternalReference::BUILTIN_FP_FP_CALL: {
SimulatorRuntimeFPFPCall target =
reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
dresult = target(dval0, dval1);
SetFpResult(dresult);
break;
}
case ExternalReference::BUILTIN_FP_CALL: {
SimulatorRuntimeFPCall target = SimulatorRuntimeFPCall target =
reinterpret_cast<SimulatorRuntimeFPCall>(external); reinterpret_cast<SimulatorRuntimeFPCall>(external);
double result = target(arg0, arg1, arg2, arg3); dresult = target(dval0);
SetFpResult(result); SetFpResult(dresult);
} else { break;
SimulatorRuntimeCall target = }
reinterpret_cast<SimulatorRuntimeCall>(external); case ExternalReference::BUILTIN_FP_INT_CALL: {
uint64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5); SimulatorRuntimeFPIntCall target =
int32_t gpreg_pair[2]; reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
memcpy(&gpreg_pair[0], &result, 2 * sizeof(int32_t)); dresult = target(dval0, ival);
set_register(v0, gpreg_pair[0]); SetFpResult(dresult);
set_register(v1, gpreg_pair[1]); break;
}
default:
UNREACHABLE();
break;
}
if (::v8::internal::FLAG_trace_sim) {
switch (redirection->type()) {
case ExternalReference::BUILTIN_COMPARE_CALL:
PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
break;
case ExternalReference::BUILTIN_FP_FP_CALL:
case ExternalReference::BUILTIN_FP_CALL:
case ExternalReference::BUILTIN_FP_INT_CALL:
PrintF("Returned %f\n", dresult);
break;
default:
UNREACHABLE();
break;
}
} }
} else if (redirection->type() == ExternalReference::DIRECT_API_CALL) { } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
// See DirectCEntryStub::GenerateCall for explanation of register usage. // See DirectCEntryStub::GenerateCall for explanation of register usage.
......
...@@ -351,10 +351,8 @@ class Simulator { ...@@ -351,10 +351,8 @@ class Simulator {
static void* RedirectExternalReference(void* external_function, static void* RedirectExternalReference(void* external_function,
ExternalReference::Type type); ExternalReference::Type type);
// For use in calls that take double value arguments. // Handle arguments and return value for runtime FP functions.
void GetFpArgs(double* x, double* y); void GetFpArgs(double* x, double* y, int32_t* z);
void GetFpArgs(double* x);
void GetFpArgs(double* x, int32_t* y);
void SetFpResult(const double& result); void SetFpResult(const double& result);
void CallInternal(byte* entry); void CallInternal(byte* entry);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment