[sim] Consistent support for C calls with up to 9 args
Consistently support calls to host-C-linkage functions with up to 9 arguments from the simulator, and check that these limits aren't exceeded accidentally. BUG=v8:6281 Review-Url: https://codereview.chromium.org/2825393003 Cr-Commit-Position: refs/heads/master@{#44790}
This commit is contained in:
parent
6d9830e41a
commit
3337ccccd9
@ -3273,6 +3273,7 @@ void MacroAssembler::CallCFunction(Register function,
|
||||
void MacroAssembler::CallCFunctionHelper(Register function,
|
||||
int num_reg_arguments,
|
||||
int num_double_arguments) {
|
||||
DCHECK_LE(num_reg_arguments + num_double_arguments, kMaxCParameters);
|
||||
DCHECK(has_frame());
|
||||
// Make sure that the stack is aligned before calling a C function unless
|
||||
// running in the simulator. The simulator has its own alignment check which
|
||||
|
@ -1706,12 +1706,11 @@ void Simulator::HandleVList(Instruction* instr) {
|
||||
// 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)(int32_t arg0,
|
||||
int32_t arg1,
|
||||
int32_t arg2,
|
||||
int32_t arg3,
|
||||
int32_t arg4,
|
||||
int32_t arg5);
|
||||
typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0, int32_t arg1,
|
||||
int32_t arg2, int32_t arg3,
|
||||
int32_t arg4, int32_t arg5,
|
||||
int32_t arg6, int32_t arg7,
|
||||
int32_t arg8);
|
||||
|
||||
typedef ObjectTriple (*SimulatorRuntimeTripleCall)(int32_t arg0, int32_t arg1,
|
||||
int32_t arg2, int32_t arg3,
|
||||
@ -1752,6 +1751,11 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
|
||||
int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
|
||||
int32_t arg4 = stack_pointer[0];
|
||||
int32_t arg5 = stack_pointer[1];
|
||||
int32_t arg6 = stack_pointer[2];
|
||||
int32_t arg7 = stack_pointer[3];
|
||||
int32_t arg8 = stack_pointer[4];
|
||||
STATIC_ASSERT(kMaxCParameters == 9);
|
||||
|
||||
bool fp_call =
|
||||
(redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
|
||||
(redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
|
||||
@ -1939,16 +1943,17 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
|
||||
if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
|
||||
PrintF(
|
||||
"Call to host function at %p "
|
||||
"args %08x, %08x, %08x, %08x, %08x, %08x",
|
||||
"args %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x",
|
||||
static_cast<void*>(FUNCTION_ADDR(target)), arg0, arg1, arg2, arg3,
|
||||
arg4, arg5);
|
||||
arg4, arg5, arg6, arg7, arg8);
|
||||
if (!stack_aligned) {
|
||||
PrintF(" with unaligned stack %08x\n", get_register(sp));
|
||||
}
|
||||
PrintF("\n");
|
||||
}
|
||||
CHECK(stack_aligned);
|
||||
int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
|
||||
int64_t result =
|
||||
target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
|
||||
int32_t lo_res = static_cast<int32_t>(result);
|
||||
int32_t hi_res = static_cast<int32_t>(result >> 32);
|
||||
if (::v8::internal::FLAG_trace_sim) {
|
||||
|
@ -1796,6 +1796,7 @@ static const int kRegisterPassedArguments = 8;
|
||||
void MacroAssembler::CallCFunction(Register function,
|
||||
int num_of_reg_args,
|
||||
int num_of_double_args) {
|
||||
DCHECK_LE(num_of_reg_args + num_of_double_args, kMaxCParameters);
|
||||
DCHECK(has_frame());
|
||||
|
||||
// If we're passing doubles, we're limited to the following prototypes
|
||||
|
@ -538,14 +538,11 @@ void Simulator::TearDown(base::CustomMatcherHashMap* i_cache,
|
||||
// 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.
|
||||
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 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,
|
||||
int64_t arg8);
|
||||
|
||||
typedef ObjectTriple (*SimulatorRuntimeTripleCall)(int64_t arg0, int64_t arg1,
|
||||
int64_t arg2, int64_t arg3,
|
||||
@ -587,6 +584,19 @@ void Simulator::DoRuntimeCall(Instruction* instr) {
|
||||
FATAL("ALIGNMENT EXCEPTION");
|
||||
}
|
||||
|
||||
int64_t* stack_pointer = reinterpret_cast<int64_t*>(sp());
|
||||
|
||||
const int64_t arg0 = xreg(0);
|
||||
const int64_t arg1 = xreg(1);
|
||||
const int64_t arg2 = xreg(2);
|
||||
const int64_t arg3 = xreg(3);
|
||||
const int64_t arg4 = xreg(4);
|
||||
const int64_t arg5 = xreg(5);
|
||||
const int64_t arg6 = xreg(6);
|
||||
const int64_t arg7 = xreg(7);
|
||||
const int64_t arg8 = stack_pointer[0];
|
||||
STATIC_ASSERT(kMaxCParameters == 9);
|
||||
|
||||
switch (redirection->type()) {
|
||||
default:
|
||||
TraceSim("Type: Unknown.\n");
|
||||
@ -604,15 +614,20 @@ void Simulator::DoRuntimeCall(Instruction* instr) {
|
||||
// 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(
|
||||
"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
|
||||
", "
|
||||
"0x%016" PRIx64,
|
||||
arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
|
||||
ObjectPair result =
|
||||
target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
|
||||
TraceSim("Returned: {%p, %p}\n", static_cast<void*>(result.x),
|
||||
static_cast<void*>(result.y));
|
||||
#ifdef DEBUG
|
||||
@ -634,16 +649,18 @@ void Simulator::DoRuntimeCall(Instruction* instr) {
|
||||
// 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
|
||||
", "
|
||||
"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));
|
||||
arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
|
||||
// Return location passed in x8.
|
||||
ObjectTriple* sim_result = reinterpret_cast<ObjectTriple*>(xreg(8));
|
||||
ObjectTriple result = target(xreg(0), xreg(1), xreg(2), xreg(3), xreg(4),
|
||||
xreg(5), xreg(6), xreg(7));
|
||||
ObjectTriple result =
|
||||
target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
|
||||
TraceSim("Returned: {%p, %p, %p}\n", static_cast<void*>(result.x),
|
||||
static_cast<void*>(result.y), static_cast<void*>(result.z));
|
||||
#ifdef DEBUG
|
||||
|
@ -155,6 +155,8 @@ LinkageLocation regloc(Register reg, MachineType type) {
|
||||
// General code uses the above configuration data.
|
||||
CallDescriptor* Linkage::GetSimplifiedCDescriptor(
|
||||
Zone* zone, const MachineSignature* msig, bool set_initialize_root_flag) {
|
||||
DCHECK_LE(msig->parameter_count(), static_cast<size_t>(kMaxCParameters));
|
||||
|
||||
LocationSignature::Builder locations(zone, msig->return_count(),
|
||||
msig->parameter_count());
|
||||
// Check the types of the signature.
|
||||
|
@ -2480,6 +2480,7 @@ void MacroAssembler::CallCFunction(ExternalReference function,
|
||||
|
||||
void MacroAssembler::CallCFunction(Register function,
|
||||
int num_arguments) {
|
||||
DCHECK_LE(num_arguments, kMaxCParameters);
|
||||
DCHECK(has_frame());
|
||||
// Check stack alignment.
|
||||
if (emit_debug_code()) {
|
||||
|
@ -65,6 +65,9 @@ enum AllocationFlags {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Simulators only support C calls with up to kMaxCParameters parameters.
|
||||
static constexpr int kMaxCParameters = 9;
|
||||
|
||||
class FrameScope {
|
||||
public:
|
||||
explicit FrameScope(MacroAssembler* masm, StackFrame::Type type)
|
||||
|
@ -6074,6 +6074,7 @@ void MacroAssembler::CallCFunction(Register function,
|
||||
void MacroAssembler::CallCFunctionHelper(Register function,
|
||||
int num_reg_arguments,
|
||||
int num_double_arguments) {
|
||||
DCHECK_LE(num_reg_arguments + num_double_arguments, kMaxCParameters);
|
||||
DCHECK(has_frame());
|
||||
// Make sure that the stack is aligned before calling a C function unless
|
||||
// running in the simulator. The simulator has its own alignment check which
|
||||
|
@ -2028,12 +2028,11 @@ void Simulator::Format(Instruction* instr, const char* format) {
|
||||
// 64-bit value. With the code below we assume that all runtime calls return
|
||||
// 64 bits of result. If they don't, the v1 result register contains a bogus
|
||||
// value, which is fine because it is caller-saved.
|
||||
typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0,
|
||||
int32_t arg1,
|
||||
int32_t arg2,
|
||||
int32_t arg3,
|
||||
int32_t arg4,
|
||||
int32_t arg5);
|
||||
typedef int64_t (*SimulatorRuntimeCall)(int32_t arg0, int32_t arg1,
|
||||
int32_t arg2, int32_t arg3,
|
||||
int32_t arg4, int32_t arg5,
|
||||
int32_t arg6, int32_t arg7,
|
||||
int32_t arg8);
|
||||
|
||||
typedef ObjectTriple (*SimulatorRuntimeTripleCall)(int32_t arg0, int32_t arg1,
|
||||
int32_t arg2, int32_t arg3,
|
||||
@ -2076,6 +2075,10 @@ void Simulator::SoftwareInterrupt() {
|
||||
// Args 4 and 5 are on the stack after the reserved space for args 0..3.
|
||||
int32_t arg4 = stack_pointer[4];
|
||||
int32_t arg5 = stack_pointer[5];
|
||||
int32_t arg6 = stack_pointer[6];
|
||||
int32_t arg7 = stack_pointer[7];
|
||||
int32_t arg8 = stack_pointer[8];
|
||||
STATIC_ASSERT(kMaxCParameters == 9);
|
||||
|
||||
bool fp_call =
|
||||
(redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
|
||||
@ -2282,11 +2285,12 @@ void Simulator::SoftwareInterrupt() {
|
||||
if (::v8::internal::FLAG_trace_sim) {
|
||||
PrintF(
|
||||
"Call to host function at %p "
|
||||
"args %08x, %08x, %08x, %08x, %08x, %08x\n",
|
||||
"args %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x\n",
|
||||
static_cast<void*>(FUNCTION_ADDR(target)), arg0, arg1, arg2, arg3,
|
||||
arg4, arg5);
|
||||
arg4, arg5, arg6, arg7, arg8);
|
||||
}
|
||||
int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
|
||||
int64_t result =
|
||||
target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
|
||||
set_register(v0, static_cast<int32_t>(result));
|
||||
set_register(v1, static_cast<int32_t>(result >> 32));
|
||||
}
|
||||
|
@ -6598,6 +6598,7 @@ void MacroAssembler::CallCFunction(Register function,
|
||||
void MacroAssembler::CallCFunctionHelper(Register function,
|
||||
int num_reg_arguments,
|
||||
int num_double_arguments) {
|
||||
DCHECK_LE(num_reg_arguments + num_double_arguments, kMaxCParameters);
|
||||
DCHECK(has_frame());
|
||||
// Make sure that the stack is aligned before calling a C function unless
|
||||
// running in the simulator. The simulator has its own alignment check which
|
||||
|
@ -1984,12 +1984,11 @@ void Simulator::Format(Instruction* instr, const char* format) {
|
||||
// 64 bits of result. If they don't, the v1 result register contains a bogus
|
||||
// value, which is fine because it is caller-saved.
|
||||
|
||||
typedef ObjectPair (*SimulatorRuntimeCall)(int64_t arg0,
|
||||
int64_t arg1,
|
||||
int64_t arg2,
|
||||
int64_t arg3,
|
||||
int64_t arg4,
|
||||
int64_t arg5);
|
||||
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,
|
||||
int64_t arg8);
|
||||
|
||||
typedef ObjectTriple (*SimulatorRuntimeTripleCall)(int64_t arg0, int64_t arg1,
|
||||
int64_t arg2, int64_t arg3,
|
||||
@ -2022,14 +2021,19 @@ void Simulator::SoftwareInterrupt() {
|
||||
// We first check if we met a call_rt_redirected.
|
||||
if (instr_.InstructionBits() == rtCallRedirInstr) {
|
||||
Redirection* redirection = Redirection::FromSwiInstruction(instr_.instr());
|
||||
|
||||
int64_t* stack_pointer = reinterpret_cast<int64_t*>(get_register(sp));
|
||||
|
||||
int64_t arg0 = get_register(a0);
|
||||
int64_t arg1 = get_register(a1);
|
||||
int64_t arg2 = get_register(a2);
|
||||
int64_t arg3 = get_register(a3);
|
||||
int64_t arg4, arg5;
|
||||
|
||||
arg4 = get_register(a4); // Abi n64 register a4.
|
||||
arg5 = get_register(a5); // Abi n64 register a5.
|
||||
int64_t arg4 = get_register(a4);
|
||||
int64_t arg5 = get_register(a5);
|
||||
int64_t arg6 = get_register(a6);
|
||||
int64_t arg7 = get_register(a7);
|
||||
int64_t arg8 = stack_pointer[0];
|
||||
STATIC_ASSERT(kMaxCParameters == 9);
|
||||
|
||||
bool fp_call =
|
||||
(redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
|
||||
@ -2224,14 +2228,13 @@ void Simulator::SoftwareInterrupt() {
|
||||
PrintF(
|
||||
"Call to host function at %p "
|
||||
"args %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64
|
||||
" , %08" PRIx64 " , %08" PRIx64 " \n",
|
||||
" , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64 " , %08" PRIx64
|
||||
" , %08" PRIx64 " \n",
|
||||
static_cast<void*>(FUNCTION_ADDR(target)), arg0, arg1, arg2, arg3,
|
||||
arg4, arg5);
|
||||
arg4, arg5, arg6, arg7, arg8);
|
||||
}
|
||||
// int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
|
||||
// set_register(v0, static_cast<int32_t>(result));
|
||||
// set_register(v1, static_cast<int32_t>(result >> 32));
|
||||
ObjectPair result = target(arg0, arg1, arg2, arg3, arg4, arg5);
|
||||
ObjectPair result =
|
||||
target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
|
||||
set_register(v0, (int64_t)(result.x));
|
||||
set_register(v1, (int64_t)(result.y));
|
||||
}
|
||||
|
@ -4786,6 +4786,7 @@ void MacroAssembler::CallCFunction(ExternalReference function,
|
||||
|
||||
|
||||
void MacroAssembler::CallCFunction(Register function, int num_arguments) {
|
||||
DCHECK_LE(num_arguments, kMaxCParameters);
|
||||
DCHECK(has_frame());
|
||||
// Check stack alignment.
|
||||
if (emit_debug_code()) {
|
||||
|
@ -28,6 +28,45 @@ using compiler::CodeAssemblerVariableList;
|
||||
|
||||
namespace {
|
||||
|
||||
int sum9(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7,
|
||||
int a8) {
|
||||
return a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(CallCFunction9) {
|
||||
Isolate* isolate(CcTest::InitIsolateOnce());
|
||||
|
||||
const int kNumParams = 0;
|
||||
CodeAssemblerTester data(isolate, kNumParams);
|
||||
CodeStubAssembler m(data.state());
|
||||
|
||||
{
|
||||
Node* const fun_constant = m.ExternalConstant(
|
||||
ExternalReference(reinterpret_cast<Address>(sum9), isolate));
|
||||
|
||||
MachineType type_intptr = MachineType::IntPtr();
|
||||
|
||||
Node* const result = m.CallCFunction9(
|
||||
type_intptr, type_intptr, type_intptr, type_intptr, type_intptr,
|
||||
type_intptr, type_intptr, type_intptr, type_intptr, type_intptr,
|
||||
fun_constant, m.IntPtrConstant(0), m.IntPtrConstant(1),
|
||||
m.IntPtrConstant(2), m.IntPtrConstant(3), m.IntPtrConstant(4),
|
||||
m.IntPtrConstant(5), m.IntPtrConstant(6), m.IntPtrConstant(7),
|
||||
m.IntPtrConstant(8));
|
||||
m.Return(m.SmiTag(result));
|
||||
}
|
||||
|
||||
Handle<Code> code = data.GenerateCode();
|
||||
FunctionTester ft(code, kNumParams);
|
||||
|
||||
Handle<Object> result = ft.Call().ToHandleChecked();
|
||||
CHECK_EQ(36, Handle<Smi>::cast(result)->value());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void CheckToUint32Result(uint32_t expected, Handle<Object> result) {
|
||||
const int64_t result_int64 = NumberToInt64(*result);
|
||||
const uint32_t result_uint32 = NumberToUint32(*result);
|
||||
|
Loading…
Reference in New Issue
Block a user