[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:
jgruber 2017-04-24 04:58:50 -07:00 committed by Commit bot
parent 6d9830e41a
commit 3337ccccd9
13 changed files with 137 additions and 58 deletions

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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()) {

View File

@ -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)

View File

@ -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

View File

@ -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));
}

View File

@ -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

View File

@ -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));
}

View File

@ -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()) {

View File

@ -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);