Commit a2a38175 authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

[wasm][multi-return][arm64] Pad parameter slots

Stack parameters on arm64 require padding. Since the stack areas for
parameters and returns should not overlap, we have to pad the parameters
already during the construction of the CallDescriptor so that we can set
the correct stack offset for returns.

R=mstarzinger@chromium.org

Bug: chromium:838098
Change-Id: I23389dc35037054b750e61ea6b1bfdfc4c5bc868
Reviewed-on: https://chromium-review.googlesource.com/1150178Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54716}
parent 57253243
......@@ -5255,7 +5255,11 @@ CallDescriptor* GetWasmCallDescriptor(
// Add return location(s).
LinkageLocationAllocator rets(wasm::kGpReturnRegisters,
wasm::kFpReturnRegisters);
rets.SetStackOffset(params.NumStackSlots());
int parameter_slots = params.NumStackSlots();
if (kPadArguments) parameter_slots = RoundUp(parameter_slots, 2);
rets.SetStackOffset(parameter_slots);
const int return_count = static_cast<int>(locations.return_count_);
for (int i = 0; i < return_count; i++) {
......@@ -5276,19 +5280,19 @@ CallDescriptor* GetWasmCallDescriptor(
CallDescriptor::Flags flags =
use_retpoline ? CallDescriptor::kRetpoline : CallDescriptor::kNoFlags;
return new (zone) CallDescriptor( // --
kind, // kind
target_type, // target MachineType
target_loc, // target location
locations.Build(), // location_sig
params.NumStackSlots(), // stack_parameter_count
compiler::Operator::kNoProperties, // properties
kCalleeSaveRegisters, // callee-saved registers
kCalleeSaveFPRegisters, // callee-saved fp regs
flags, // flags
"wasm-call", // debug name
0, // allocatable registers
rets.NumStackSlots() - params.NumStackSlots()); // stack_return_count
return new (zone) CallDescriptor( // --
kind, // kind
target_type, // target MachineType
target_loc, // target location
locations.Build(), // location_sig
parameter_slots, // stack_parameter_count
compiler::Operator::kNoProperties, // properties
kCalleeSaveRegisters, // callee-saved registers
kCalleeSaveFPRegisters, // callee-saved fp regs
flags, // flags
"wasm-call", // debug name
0, // allocatable registers
rets.NumStackSlots() - parameter_slots); // stack_return_count
}
namespace {
......
......@@ -135,87 +135,98 @@ std::unique_ptr<wasm::NativeModule> AllocateNativeModule(Isolate* isolate,
void TestReturnMultipleValues(MachineType type) {
const int kMaxCount = 20;
for (int count = 0; count < kMaxCount; ++count) {
printf("\n==== type = %s, count = %d ====\n\n\n",
MachineReprToString(type.representation()), count);
v8::internal::AccountingAllocator allocator;
Zone zone(&allocator, ZONE_NAME);
CallDescriptor* desc = CreateCallDescriptor(&zone, count, 2, type);
HandleAndZoneScope handles;
RawMachineAssembler m(handles.main_isolate(),
new (handles.main_zone()) Graph(handles.main_zone()),
desc, MachineType::PointerRepresentation(),
InstructionSelector::SupportedMachineOperatorFlags());
// m.Parameter(0) is the WasmContext.
Node* p0 = m.Parameter(1);
Node* p1 = m.Parameter(2);
typedef Node* Node_ptr;
std::unique_ptr<Node_ptr[]> returns(new Node_ptr[count]);
for (int i = 0; i < count; ++i) {
if (i % 3 == 0) returns[i] = Add(m, type, p0, p1);
if (i % 3 == 1) returns[i] = Sub(m, type, p0, p1);
if (i % 3 == 2) returns[i] = Mul(m, type, p0, p1);
}
m.Return(count, returns.get());
OptimizedCompilationInfo info(ArrayVector("testing"), handles.main_zone(),
Code::WASM_FUNCTION);
Handle<Code> code =
Pipeline::GenerateCodeForTesting(
&info, handles.main_isolate(), desc, m.graph(),
AssemblerOptions::Default(handles.main_isolate()), m.Export())
.ToHandleChecked();
const int kMaxParamCount = 9;
// Use 9 parameters as a regression test or https://crbug.com/838098.
for (int param_count : {2, kMaxParamCount}) {
for (int count = 0; count < kMaxCount; ++count) {
printf("\n==== type = %s, count = %d ====\n\n\n",
MachineReprToString(type.representation()), count);
v8::internal::AccountingAllocator allocator;
Zone zone(&allocator, ZONE_NAME);
CallDescriptor* desc =
CreateCallDescriptor(&zone, count, param_count, type);
HandleAndZoneScope handles;
RawMachineAssembler m(
handles.main_isolate(),
new (handles.main_zone()) Graph(handles.main_zone()), desc,
MachineType::PointerRepresentation(),
InstructionSelector::SupportedMachineOperatorFlags());
// m.Parameter(0) is the WasmContext.
Node* p0 = m.Parameter(1);
Node* p1 = m.Parameter(2);
typedef Node* Node_ptr;
std::unique_ptr<Node_ptr[]> returns(new Node_ptr[count]);
for (int i = 0; i < count; ++i) {
if (i % 3 == 0) returns[i] = Add(m, type, p0, p1);
if (i % 3 == 1) returns[i] = Sub(m, type, p0, p1);
if (i % 3 == 2) returns[i] = Mul(m, type, p0, p1);
}
m.Return(count, returns.get());
OptimizedCompilationInfo info(ArrayVector("testing"), handles.main_zone(),
Code::WASM_FUNCTION);
Handle<Code> code =
Pipeline::GenerateCodeForTesting(
&info, handles.main_isolate(), desc, m.graph(),
AssemblerOptions::Default(handles.main_isolate()), m.Export())
.ToHandleChecked();
#ifdef ENABLE_DISASSEMBLER
if (FLAG_print_code) {
StdoutStream os;
code->Disassemble("multi_value", os);
}
if (FLAG_print_code) {
StdoutStream os;
code->Disassemble("multi_value", os);
}
#endif
const int a = 47, b = 12;
int expect = 0;
for (int i = 0, sign = +1; i < count; ++i) {
if (i % 3 == 0) expect += sign * (a + b);
if (i % 3 == 1) expect += sign * (a - b);
if (i % 3 == 2) expect += sign * (a * b);
if (i % 4 == 0) sign = -sign;
}
std::unique_ptr<wasm::NativeModule> module = AllocateNativeModule(
handles.main_isolate(), code->raw_instruction_size());
byte* code_start = module->AddCodeCopy(code, wasm::WasmCode::kFunction, 0)
->instructions()
.start();
RawMachineAssemblerTester<int32_t> mt;
Node* call_inputs[] = {mt.PointerConstant(code_start),
// WasmContext dummy
mt.PointerConstant(nullptr),
// Inputs
MakeConstant(mt, type, a),
MakeConstant(mt, type, b)};
Node* ret_multi = mt.AddNode(mt.common()->Call(desc),
arraysize(call_inputs), call_inputs);
Node* ret = MakeConstant(mt, type, 0);
bool sign = false;
for (int i = 0; i < count; ++i) {
Node* x = (count == 1)
? ret_multi
: mt.AddNode(mt.common()->Projection(i), ret_multi);
ret = sign ? Sub(mt, type, ret, x) : Add(mt, type, ret, x);
if (i % 4 == 0) sign = !sign;
}
mt.Return(ToInt32(mt, type, ret));
const int a = 47, b = 12;
int expect = 0;
for (int i = 0, sign = +1; i < count; ++i) {
if (i % 3 == 0) expect += sign * (a + b);
if (i % 3 == 1) expect += sign * (a - b);
if (i % 3 == 2) expect += sign * (a * b);
if (i % 4 == 0) sign = -sign;
}
std::unique_ptr<wasm::NativeModule> module = AllocateNativeModule(
handles.main_isolate(), code->raw_instruction_size());
byte* code_start = module->AddCodeCopy(code, wasm::WasmCode::kFunction, 0)
->instructions()
.start();
RawMachineAssemblerTester<int32_t> mt;
const int input_count = 2 + param_count;
Node* call_inputs[2 + kMaxParamCount];
call_inputs[0] = mt.PointerConstant(code_start);
// WasmContext dummy
call_inputs[1] = mt.PointerConstant(nullptr);
// Special inputs for the test.
call_inputs[2] = MakeConstant(mt, type, a);
call_inputs[3] = MakeConstant(mt, type, b);
for (int i = 2; i < param_count; i++) {
call_inputs[2 + i] = MakeConstant(mt, type, i);
}
Node* ret_multi = mt.AddNode(mt.common()->Call(desc),
input_count, call_inputs);
Node* ret = MakeConstant(mt, type, 0);
bool sign = false;
for (int i = 0; i < count; ++i) {
Node* x = (count == 1)
? ret_multi
: mt.AddNode(mt.common()->Projection(i), ret_multi);
ret = sign ? Sub(mt, type, ret, x) : Add(mt, type, ret, x);
if (i % 4 == 0) sign = !sign;
}
mt.Return(ToInt32(mt, type, ret));
#ifdef ENABLE_DISASSEMBLER
Handle<Code> code2 = mt.GetCode();
if (FLAG_print_code) {
StdoutStream os;
code2->Disassemble("multi_value_call", os);
}
Handle<Code> code2 = mt.GetCode();
if (FLAG_print_code) {
StdoutStream os;
code2->Disassemble("multi_value_call", os);
}
#endif
CHECK_EQ(expect, mt.Call());
CHECK_EQ(expect, mt.Call());
}
}
}
......
......@@ -306,6 +306,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
&wrapper_info, i_isolate, wrapper_desc, caller.graph(),
AssemblerOptions::Default(i_isolate), caller.Export())
.ToHandleChecked();
auto fn = GeneratedCode<int32_t>::FromCode(*wrapper_code);
int result = fn.Call();
......
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