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 {
}
// 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.
void Simulator::GetFpArgs(double* x, double* y) {
void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
if (!IsMipsSoftFloatABI) {
*x = get_fpu_register_double(12);
*y = get_fpu_register_double(14);
*z = registers_[1];
} else {
// We use a char buffer to get around the strict-aliasing rules which
// otherwise allow the compiler to optimize away the copy.
......@@ -1107,48 +1109,13 @@ void Simulator::GetFpArgs(double* x, double* y) {
reg_buffer[0] = get_register(a0);
reg_buffer[1] = get_register(a1);
memcpy(x, buffer, sizeof(buffer));
// Registers a2 and a3 -> y.
reg_buffer[0] = get_register(a2);
reg_buffer[1] = get_register(a3);
memcpy(y, buffer, sizeof(buffer));
}
}
// 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 -> z.
memcpy(buffer, registers_ + 2, sizeof(*z));
memcpy(z, buffer, sizeof(*z));
// Register 2 -> y.
reg_buffer[0] = get_register(a2);
......@@ -1415,10 +1382,12 @@ typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
int32_t arg3,
int32_t arg4,
int32_t arg5);
typedef double (*SimulatorRuntimeFPCall)(int32_t arg0,
int32_t arg1,
int32_t arg2,
int32_t arg3);
// These prototypes handle the four types of FP calls.
typedef int64_t (*SimulatorRuntimeCompareCall)(double darg0, double darg1);
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
// (refer to InvocationCallback in v8.h).
......@@ -1495,46 +1464,81 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
// simulator. Soft-float has additional abstraction of ExternalReference,
// to support serialization.
if (fp_call) {
SimulatorRuntimeFPCall target =
reinterpret_cast<SimulatorRuntimeFPCall>(external);
double dval0, dval1; // one or two double parameters
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) {
double dval0, dval1;
int32_t ival;
switch (redirection->type()) {
case ExternalReference::BUILTIN_FP_FP_CALL:
case ExternalReference::BUILTIN_COMPARE_CALL:
GetFpArgs(&dval0, &dval1);
PrintF("Call to host function at %p with args %f, %f",
FUNCTION_ADDR(target), dval0, dval1);
FUNCTION_ADDR(generic_target), dval0, dval1);
break;
case ExternalReference::BUILTIN_FP_CALL:
GetFpArgs(&dval0);
PrintF("Call to host function at %p with arg %f",
FUNCTION_ADDR(target), dval0);
FUNCTION_ADDR(generic_target), dval0);
break;
case ExternalReference::BUILTIN_FP_INT_CALL:
GetFpArgs(&dval0, &ival);
PrintF("Call to host function at %p with args %f, %d",
FUNCTION_ADDR(target), dval0, ival);
FUNCTION_ADDR(generic_target), dval0, ival);
break;
default:
UNREACHABLE();
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 =
reinterpret_cast<SimulatorRuntimeFPCall>(external);
double result = target(arg0, arg1, arg2, arg3);
SetFpResult(result);
} else {
SimulatorRuntimeCall target =
reinterpret_cast<SimulatorRuntimeCall>(external);
uint64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
int32_t gpreg_pair[2];
memcpy(&gpreg_pair[0], &result, 2 * sizeof(int32_t));
set_register(v0, gpreg_pair[0]);
set_register(v1, gpreg_pair[1]);
reinterpret_cast<SimulatorRuntimeFPCall>(external);
dresult = target(dval0);
SetFpResult(dresult);
break;
}
case ExternalReference::BUILTIN_FP_INT_CALL: {
SimulatorRuntimeFPIntCall target =
reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
dresult = target(dval0, ival);
SetFpResult(dresult);
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) {
// See DirectCEntryStub::GenerateCall for explanation of register usage.
......
......@@ -351,10 +351,8 @@ class Simulator {
static void* RedirectExternalReference(void* external_function,
ExternalReference::Type type);
// For use in calls that take double value arguments.
void GetFpArgs(double* x, double* y);
void GetFpArgs(double* x);
void GetFpArgs(double* x, int32_t* y);
// Handle arguments and return value for runtime FP functions.
void GetFpArgs(double* x, double* y, int32_t* z);
void SetFpResult(const double& result);
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