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

[wasm] Make multi-return tests wasm-specific

The multi-return tests and fuzzer used a custom call descriptor which
was based on the default RegisterConfiguration. This meant that for the
tests, all available registers could be used to pass parameters and to
return values. This caused a problem, because in some cases we need a
scratch register in the frame deconstruction.

With this CL I change both the tests and the fuzzer to use the
WebAssembly call descriptor. Thereby we only use 2 registers for
returns, and one of the other registers can be used as scratch
register.

WebAssembly is the only use case at the moment which wants to return
values not only through registers but also over the stack. Therefore
I think it's acceptable to only test the WebAssembly usecase.

R=mstarzinger@chromium.org

Bug: chromium:813288
Change-Id: I31bed757af5f3e8589d2b3dfb6f0112ddecd1a20
Reviewed-on: https://chromium-review.googlesource.com/970656Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52099}
parent 3ba29d55
...@@ -12,9 +12,13 @@ ...@@ -12,9 +12,13 @@
#include "src/codegen.h" #include "src/codegen.h"
#include "src/compiler.h" #include "src/compiler.h"
#include "src/compiler/linkage.h" #include "src/compiler/linkage.h"
#include "src/compiler/wasm-compiler.h"
#include "src/machine-type.h" #include "src/machine-type.h"
#include "src/macro-assembler.h" #include "src/macro-assembler.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
#include "src/wasm/wasm-engine.h"
#include "src/wasm/wasm-objects-inl.h"
#include "src/wasm/wasm-opcodes.h"
#include "test/cctest/cctest.h" #include "test/cctest/cctest.h"
#include "test/cctest/compiler/codegen-tester.h" #include "test/cctest/compiler/codegen-tester.h"
#include "test/cctest/compiler/value-helper.h" #include "test/cctest/compiler/value-helper.h"
...@@ -25,89 +29,18 @@ namespace compiler { ...@@ -25,89 +29,18 @@ namespace compiler {
namespace { namespace {
int size(MachineType type) { CallDescriptor* CreateCallDescriptor(Zone* zone, int return_count,
return 1 << ElementSizeLog2Of(type.representation());
}
int num_registers(MachineType type) {
const RegisterConfiguration* config = RegisterConfiguration::Default();
switch (type.representation()) {
case MachineRepresentation::kWord32:
case MachineRepresentation::kWord64:
return config->num_allocatable_general_registers();
case MachineRepresentation::kFloat32:
return config->num_allocatable_float_registers();
case MachineRepresentation::kFloat64:
return config->num_allocatable_double_registers();
default:
UNREACHABLE();
}
}
const int* codes(MachineType type) {
const RegisterConfiguration* config = RegisterConfiguration::Default();
switch (type.representation()) {
case MachineRepresentation::kWord32:
case MachineRepresentation::kWord64:
return config->allocatable_general_codes();
case MachineRepresentation::kFloat32:
return config->allocatable_float_codes();
case MachineRepresentation::kFloat64:
return config->allocatable_double_codes();
default:
UNREACHABLE();
}
}
CallDescriptor* CreateMonoCallDescriptor(Zone* zone, int return_count,
int param_count, MachineType type) { int param_count, MachineType type) {
LocationSignature::Builder locations(zone, return_count, param_count); wasm::FunctionSig::Builder builder(zone, return_count, param_count);
int span = std::max(1, size(type) / kPointerSize);
int stack_params = 0;
for (int i = 0; i < param_count; i++) { for (int i = 0; i < param_count; i++) {
LinkageLocation location = LinkageLocation::ForAnyRegister(); builder.AddParam(type.representation());
if (i < num_registers(type)) {
location = LinkageLocation::ForRegister(codes(type)[i], type);
} else {
int slot = span * (i - param_count);
location = LinkageLocation::ForCallerFrameSlot(slot, type);
stack_params += span;
}
locations.AddParam(location);
} }
int stack_returns = 0;
for (int i = 0; i < return_count; i++) { for (int i = 0; i < return_count; i++) {
LinkageLocation location = LinkageLocation::ForAnyRegister(); builder.AddReturn(type.representation());
if (i < num_registers(type)) {
location = LinkageLocation::ForRegister(codes(type)[i], type);
} else {
int slot = span * (num_registers(type) - i) - stack_params - 1;
location = LinkageLocation::ForCallerFrameSlot(slot, type);
stack_returns += span;
} }
locations.AddReturn(location); return compiler::GetWasmCallDescriptor(zone, builder.Build());
}
const RegList kCalleeSaveRegisters = 0;
const RegList kCalleeSaveFPRegisters = 0;
MachineType target_type = MachineType::AnyTagged();
LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type);
return new (zone) CallDescriptor( // --
CallDescriptor::kCallCodeObject, // kind
target_type, // target MachineType
target_loc, // target location
locations.Build(), // location_sig
stack_params, // on-stack parameter count
compiler::Operator::kNoProperties, // properties
kCalleeSaveRegisters, // callee-saved registers
kCalleeSaveFPRegisters, // callee-saved fp regs
CallDescriptor::kNoFlags, // flags
"c-call", // debug name
0, // allocatable registers
stack_returns); // on-stack return count
} }
} // namespace } // namespace
...@@ -187,6 +120,26 @@ Node* ToInt32(RawMachineAssembler& m, MachineType type, Node* a) { ...@@ -187,6 +120,26 @@ Node* ToInt32(RawMachineAssembler& m, MachineType type, Node* a) {
} }
} }
std::unique_ptr<wasm::NativeModule> AllocateNativeModule(Isolate* isolate,
size_t code_size) {
// We have to add the code object to a NativeModule, because the
// WasmCallDescriptor assumes that code is on the native heap and not
// within a code object.
std::unique_ptr<wasm::NativeModule> module =
isolate->wasm_engine()->code_manager()->NewNativeModule(code_size, 1, 0,
false);
// TODO(mstarzinger): Remove the WasmCompiledModule here as soon as source
// positions are stored in the WasmCode directly.
Handle<WasmCompiledModule> compiled_module = Handle<WasmCompiledModule>::cast(
isolate->factory()->NewStruct(WASM_COMPILED_MODULE_TYPE, TENURED));
Handle<FixedArray> source_positions =
isolate->factory()->NewFixedArray(1, TENURED);
compiled_module->set_source_positions(*source_positions);
module->SetCompiledModule(compiled_module);
return module;
}
void TestReturnMultipleValues(MachineType type) { void TestReturnMultipleValues(MachineType type) {
const int kMaxCount = 20; const int kMaxCount = 20;
for (int count = 0; count < kMaxCount; ++count) { for (int count = 0; count < kMaxCount; ++count) {
...@@ -194,15 +147,16 @@ void TestReturnMultipleValues(MachineType type) { ...@@ -194,15 +147,16 @@ void TestReturnMultipleValues(MachineType type) {
MachineReprToString(type.representation()), count); MachineReprToString(type.representation()), count);
v8::internal::AccountingAllocator allocator; v8::internal::AccountingAllocator allocator;
Zone zone(&allocator, ZONE_NAME); Zone zone(&allocator, ZONE_NAME);
CallDescriptor* desc = CreateMonoCallDescriptor(&zone, count, 2, type); CallDescriptor* desc = CreateCallDescriptor(&zone, count, 2, type);
HandleAndZoneScope handles; HandleAndZoneScope handles;
RawMachineAssembler m(handles.main_isolate(), RawMachineAssembler m(handles.main_isolate(),
new (handles.main_zone()) Graph(handles.main_zone()), new (handles.main_zone()) Graph(handles.main_zone()),
desc, MachineType::PointerRepresentation(), desc, MachineType::PointerRepresentation(),
InstructionSelector::SupportedMachineOperatorFlags()); InstructionSelector::SupportedMachineOperatorFlags());
Node* p0 = m.Parameter(0); // m.Parameter(0) is the WasmContext.
Node* p1 = m.Parameter(1); Node* p0 = m.Parameter(1);
Node* p1 = m.Parameter(2);
typedef Node* Node_ptr; typedef Node* Node_ptr;
std::unique_ptr<Node_ptr[]> returns(new Node_ptr[count]); std::unique_ptr<Node_ptr[]> returns(new Node_ptr[count]);
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
...@@ -232,11 +186,21 @@ void TestReturnMultipleValues(MachineType type) { ...@@ -232,11 +186,21 @@ void TestReturnMultipleValues(MachineType type) {
if (i % 4 == 0) sign = -sign; if (i % 4 == 0) sign = -sign;
} }
std::unique_ptr<wasm::NativeModule> module =
AllocateNativeModule(handles.main_isolate(), code->instruction_size());
byte* code_start = module->AddCodeCopy(code, wasm::WasmCode::kFunction, 0)
->instructions()
.start();
RawMachineAssemblerTester<int32_t> mt; RawMachineAssemblerTester<int32_t> mt;
Node* na = Constant(mt, type, a); Node* call_inputs[] = {mt.PointerConstant(code_start),
Node* nb = Constant(mt, type, b); // WasmContext dummy
Node* ret_multi = mt.PointerConstant(nullptr),
mt.AddNode(mt.common()->Call(desc), mt.HeapConstant(code), na, nb); // Inputs
Constant(mt, type, a), Constant(mt, type, b)};
Node* ret_multi = mt.AddNode(mt.common()->Call(desc),
arraysize(call_inputs), call_inputs);
Node* ret = Constant(mt, type, 0); Node* ret = Constant(mt, type, 0);
bool sign = false; bool sign = false;
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
...@@ -275,10 +239,11 @@ void ReturnLastValue(MachineType type) { ...@@ -275,10 +239,11 @@ void ReturnLastValue(MachineType type) {
for (auto slot_count : slot_counts) { for (auto slot_count : slot_counts) {
v8::internal::AccountingAllocator allocator; v8::internal::AccountingAllocator allocator;
Zone zone(&allocator, ZONE_NAME); Zone zone(&allocator, ZONE_NAME);
const int return_count = num_registers(type) + slot_count; // The wasm-linkage provides 2 return registers at the moment, on all
// platforms.
const int return_count = 2 + slot_count;
CallDescriptor* desc = CallDescriptor* desc = CreateCallDescriptor(&zone, return_count, 0, type);
CreateMonoCallDescriptor(&zone, return_count, 0, type);
HandleAndZoneScope handles; HandleAndZoneScope handles;
RawMachineAssembler m(handles.main_isolate(), RawMachineAssembler m(handles.main_isolate(),
...@@ -299,12 +264,20 @@ void ReturnLastValue(MachineType type) { ...@@ -299,12 +264,20 @@ void ReturnLastValue(MachineType type) {
Handle<Code> code = Pipeline::GenerateCodeForTesting( Handle<Code> code = Pipeline::GenerateCodeForTesting(
&info, handles.main_isolate(), desc, m.graph(), m.Export()); &info, handles.main_isolate(), desc, m.graph(), m.Export());
std::unique_ptr<wasm::NativeModule> module =
AllocateNativeModule(handles.main_isolate(), code->instruction_size());
byte* code_start = module->AddCodeCopy(code, wasm::WasmCode::kFunction, 0)
->instructions()
.start();
// Generate caller. // Generate caller.
int expect = return_count - 1; int expect = return_count - 1;
RawMachineAssemblerTester<int32_t> mt; RawMachineAssemblerTester<int32_t> mt;
Node* code_node = mt.HeapConstant(code); Node* inputs[] = {mt.PointerConstant(code_start),
// WasmContext dummy
mt.PointerConstant(nullptr)};
Node* call = mt.AddNode(mt.common()->Call(desc), 1, &code_node); Node* call = mt.AddNode(mt.common()->Call(desc), 2, inputs);
mt.Return(ToInt32( mt.Return(ToInt32(
mt, type, mt.AddNode(mt.common()->Projection(return_count - 1), call))); mt, type, mt.AddNode(mt.common()->Projection(return_count - 1), call)));
...@@ -326,10 +299,11 @@ void ReturnSumOfReturns(MachineType type) { ...@@ -326,10 +299,11 @@ void ReturnSumOfReturns(MachineType type) {
v8::internal::AccountingAllocator allocator; v8::internal::AccountingAllocator allocator;
Zone zone(&allocator, ZONE_NAME); Zone zone(&allocator, ZONE_NAME);
// Let {unused_stack_slots + 1} returns be on the stack. // Let {unused_stack_slots + 1} returns be on the stack.
const int return_count = num_registers(type) + unused_stack_slots + 1; // The wasm-linkage provides 2 return registers at the moment, on all
// platforms.
const int return_count = 2 + unused_stack_slots + 1;
CallDescriptor* desc = CallDescriptor* desc = CreateCallDescriptor(&zone, return_count, 0, type);
CreateMonoCallDescriptor(&zone, return_count, 0, type);
HandleAndZoneScope handles; HandleAndZoneScope handles;
RawMachineAssembler m(handles.main_isolate(), RawMachineAssembler m(handles.main_isolate(),
...@@ -350,11 +324,19 @@ void ReturnSumOfReturns(MachineType type) { ...@@ -350,11 +324,19 @@ void ReturnSumOfReturns(MachineType type) {
Handle<Code> code = Pipeline::GenerateCodeForTesting( Handle<Code> code = Pipeline::GenerateCodeForTesting(
&info, handles.main_isolate(), desc, m.graph(), m.Export()); &info, handles.main_isolate(), desc, m.graph(), m.Export());
std::unique_ptr<wasm::NativeModule> module =
AllocateNativeModule(handles.main_isolate(), code->instruction_size());
byte* code_start = module->AddCodeCopy(code, wasm::WasmCode::kFunction, 0)
->instructions()
.start();
// Generate caller. // Generate caller.
RawMachineAssemblerTester<int32_t> mt; RawMachineAssemblerTester<int32_t> mt;
Node* code_node = mt.HeapConstant(code); Node* call_inputs[] = {mt.PointerConstant(code_start),
// WasmContext dummy
mt.PointerConstant(nullptr)};
Node* call = mt.AddNode(mt.common()->Call(desc), 1, &code_node); Node* call = mt.AddNode(mt.common()->Call(desc), 2, call_inputs);
uint32_t expect = 0; uint32_t expect = 0;
Node* result = mt.Int32Constant(0); Node* result = mt.Int32Constant(0);
......
...@@ -13,11 +13,16 @@ ...@@ -13,11 +13,16 @@
#include "src/compiler/operator.h" #include "src/compiler/operator.h"
#include "src/compiler/pipeline.h" #include "src/compiler/pipeline.h"
#include "src/compiler/raw-machine-assembler.h" #include "src/compiler/raw-machine-assembler.h"
#include "src/compiler/wasm-compiler.h"
#include "src/machine-type.h" #include "src/machine-type.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
#include "src/objects.h" #include "src/objects.h"
#include "src/simulator.h" #include "src/simulator.h"
#include "src/wasm/wasm-engine.h"
#include "src/wasm/wasm-limits.h" #include "src/wasm/wasm-limits.h"
#include "src/wasm/wasm-objects-inl.h"
#include "src/wasm/wasm-objects.h"
#include "src/wasm/wasm-opcodes.h"
#include "src/zone/accounting-allocator.h" #include "src/zone/accounting-allocator.h"
#include "src/zone/zone.h" #include "src/zone/zone.h"
#include "test/fuzzer/fuzzer-support.h" #include "test/fuzzer/fuzzer-support.h"
...@@ -91,49 +96,8 @@ int num_registers(MachineType type) { ...@@ -91,49 +96,8 @@ int num_registers(MachineType type) {
} }
} }
int size(MachineType type) {
return 1 << ElementSizeLog2Of(type.representation());
}
int index(MachineType type) { return static_cast<int>(type.representation()); } int index(MachineType type) { return static_cast<int>(type.representation()); }
const int* codes(MachineType type) {
const RegisterConfiguration* config = RegisterConfiguration::Default();
switch (type.representation()) {
case MachineRepresentation::kWord32:
case MachineRepresentation::kWord64:
return config->allocatable_general_codes();
case MachineRepresentation::kFloat32:
return config->allocatable_float_codes();
case MachineRepresentation::kFloat64:
return config->allocatable_double_codes();
default:
UNREACHABLE();
}
}
LinkageLocation AllocateLocation(MachineType type, int* int_count,
int* float_count, int* stack_slots) {
int* count = IsFloatingPoint(type.representation()) ? float_count : int_count;
int reg_code = *count;
#if V8_TARGET_ARCH_ARM
// Allocate floats using a double register, but modify the code to
// reflect how ARM FP registers alias.
if (type == MachineType::Float32()) {
reg_code *= 2;
}
#endif
LinkageLocation location = LinkageLocation::ForAnyRegister(); // Dummy.
if (reg_code < num_registers(type)) {
location = LinkageLocation::ForRegister(codes(type)[reg_code], type);
} else {
location = LinkageLocation::ForCallerFrameSlot(-*stack_slots - 1, type);
*stack_slots += std::max(1, size(type) / kPointerSize);
}
++*count;
return location;
}
Node* Constant(RawMachineAssembler& m, MachineType type, int value) { Node* Constant(RawMachineAssembler& m, MachineType type, int value) {
switch (type.representation()) { switch (type.representation()) {
case MachineRepresentation::kWord32: case MachineRepresentation::kWord32:
...@@ -167,51 +131,40 @@ Node* ToInt32(RawMachineAssembler& m, MachineType type, Node* a) { ...@@ -167,51 +131,40 @@ Node* ToInt32(RawMachineAssembler& m, MachineType type, Node* a) {
CallDescriptor* CreateRandomCallDescriptor(Zone* zone, size_t return_count, CallDescriptor* CreateRandomCallDescriptor(Zone* zone, size_t return_count,
size_t param_count, size_t param_count,
InputProvider* input) { InputProvider* input) {
LocationSignature::Builder locations(zone, return_count, param_count); wasm::FunctionSig::Builder builder(zone, return_count, param_count);
int stack_slots = 0;
int int_params = 0;
int float_params = 0;
for (size_t i = 0; i < param_count; i++) { for (size_t i = 0; i < param_count; i++) {
MachineType type = RandomType(input); MachineType type = RandomType(input);
LinkageLocation location = builder.AddParam(type.representation());
AllocateLocation(type, &int_params, &float_params, &stack_slots);
locations.AddParam(location);
} }
// Read the end byte of the parameters. // Read the end byte of the parameters.
input->NextInt8(1); input->NextInt8(1);
int stack_params = stack_slots;
#if V8_TARGET_ARCH_ARM64
// Align the stack slots.
stack_slots = stack_slots + (stack_slots % 2);
#endif
int aligned_stack_params = stack_slots;
int int_returns = 0;
int float_returns = 0;
for (size_t i = 0; i < return_count; i++) { for (size_t i = 0; i < return_count; i++) {
MachineType type = RandomType(input); MachineType type = RandomType(input);
LinkageLocation location = builder.AddReturn(type.representation());
AllocateLocation(type, &int_returns, &float_returns, &stack_slots);
locations.AddReturn(location);
} }
int stack_returns = stack_slots - aligned_stack_params;
return compiler::GetWasmCallDescriptor(zone, builder.Build());
MachineType target_type = MachineType::AnyTagged(); }
LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type);
return new (zone) CallDescriptor( // -- std::unique_ptr<wasm::NativeModule> AllocateNativeModule(i::Isolate* isolate,
CallDescriptor::kCallCodeObject, // kind size_t code_size) {
target_type, // target MachineType // We have to add the code object to a NativeModule, because the
target_loc, // target location // WasmCallDescriptor assumes that code is on the native heap and not
locations.Build(), // location_sig // within a code object.
stack_params, // on-stack parameter count std::unique_ptr<wasm::NativeModule> module =
compiler::Operator::kNoProperties, // properties isolate->wasm_engine()->code_manager()->NewNativeModule(code_size, 1, 0,
0, // callee-saved registers false);
0, // callee-saved fp regs
CallDescriptor::kNoFlags, // flags // TODO(mstarzinger): Remove the WasmCompiledModule here as soon as source
"c-call", // debug name // positions are stored in the WasmCode directly.
0, // allocatable registers Handle<WasmCompiledModule> compiled_module = Handle<WasmCompiledModule>::cast(
stack_returns); // on-stack return count isolate->factory()->NewStruct(WASM_COMPILED_MODULE_TYPE, TENURED));
Handle<FixedArray> source_positions =
isolate->factory()->NewFixedArray(1, TENURED);
compiled_module->set_source_positions(*source_positions);
module->SetCompiledModule(compiled_module);
return module;
} }
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
...@@ -239,9 +192,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { ...@@ -239,9 +192,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (FLAG_wasm_fuzzer_gen_test) { if (FLAG_wasm_fuzzer_gen_test) {
// Print some debugging output which describes the produced signature. // Print some debugging output which describes the produced signature.
printf("["); printf("[");
for (size_t j = 0; j < desc->ParameterCount(); ++j) { for (size_t j = 0; j < param_count; ++j) {
printf(" %s", // Parameter 0 is the WasmContext.
MachineReprToString(desc->GetParameterType(j).representation())); printf(" %s", MachineReprToString(
desc->GetParameterType(j + 1).representation()));
} }
printf(" ] -> ["); printf(" ] -> [");
for (size_t j = 0; j < desc->ReturnCount(); ++j) { for (size_t j = 0; j < desc->ReturnCount(); ++j) {
...@@ -258,14 +212,15 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { ...@@ -258,14 +212,15 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Trivial hash table for the number of occurrences of parameter types. The // Trivial hash table for the number of occurrences of parameter types. The
// MachineRepresentation of the parameter types is used as hash code. // MachineRepresentation of the parameter types is used as hash code.
int counts[kNumMachineRepresentations] = {0}; int counts[kNumMachineRepresentations] = {0};
for (size_t i = 0; i < desc->ParameterCount(); ++i) { for (size_t i = 0; i < param_count; ++i) {
++counts[index(desc->GetParameterType(i))]; // Parameter 0 is the WasmContext.
++counts[index(desc->GetParameterType(i + 1))];
} }
// Generate random inputs. // Generate random inputs.
std::unique_ptr<int[]> inputs(new int[desc->ParameterCount()]); std::unique_ptr<int[]> inputs(new int[param_count]);
std::unique_ptr<int[]> outputs(new int[desc->ReturnCount()]); std::unique_ptr<int[]> outputs(new int[desc->ReturnCount()]);
for (size_t i = 0; i < desc->ParameterCount(); ++i) { for (size_t i = 0; i < param_count; ++i) {
inputs[i] = input.NextInt32(10000); inputs[i] = input.NextInt32(10000);
} }
...@@ -275,11 +230,15 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { ...@@ -275,11 +230,15 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
InstructionSelector::SupportedMachineOperatorFlags()); InstructionSelector::SupportedMachineOperatorFlags());
// Generate callee, returning random picks of its parameters. // Generate callee, returning random picks of its parameters.
std::unique_ptr<Node* []> params(new Node*[desc->ParameterCount() + 1]); std::unique_ptr<Node* []> params(new Node*[desc->ParameterCount() + 2]);
std::unique_ptr<Node* []> returns(new Node*[desc->ReturnCount()]); // The first input of a return is the number of stack slots that should be
for (size_t i = 0; i < desc->ParameterCount(); ++i) { // popped before returning.
params[i] = callee.Parameter(i); std::unique_ptr<Node* []> returns(new Node*[desc->ReturnCount() + 1]);
for (size_t i = 0; i < param_count; ++i) {
// Parameter(0) is the WasmContext.
params[i] = callee.Parameter(i + 1);
} }
for (size_t i = 0; i < desc->ReturnCount(); ++i) { for (size_t i = 0; i < desc->ReturnCount(); ++i) {
MachineType type = desc->GetReturnType(i); MachineType type = desc->GetReturnType(i);
// Find a random same-type parameter to return. Use a constant if none. // Find a random same-type parameter to return. Use a constant if none.
...@@ -289,7 +248,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { ...@@ -289,7 +248,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
} else { } else {
int n = input.NextInt32(counts[index(type)]); int n = input.NextInt32(counts[index(type)]);
int k = 0; int k = 0;
while (desc->GetParameterType(k) != desc->GetReturnType(i) || --n > 0) { while (desc->GetParameterType(k + 1) != desc->GetReturnType(i) ||
--n > 0) {
++k; ++k;
} }
returns[i] = params[k]; returns[i] = params[k];
...@@ -302,6 +262,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { ...@@ -302,6 +262,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
Handle<Code> code = Pipeline::GenerateCodeForTesting( Handle<Code> code = Pipeline::GenerateCodeForTesting(
&info, i_isolate, desc, callee.graph(), callee.Export()); &info, i_isolate, desc, callee.graph(), callee.Export());
std::unique_ptr<wasm::NativeModule> module =
AllocateNativeModule(i_isolate, code->instruction_size());
byte* code_start = module->AddCodeCopy(code, wasm::WasmCode::kFunction, 0)
->instructions()
.start();
// Generate wrapper. // Generate wrapper.
int expect = 0; int expect = 0;
...@@ -315,13 +280,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { ...@@ -315,13 +280,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
MachineType::PointerRepresentation(), MachineType::PointerRepresentation(),
InstructionSelector::SupportedMachineOperatorFlags()); InstructionSelector::SupportedMachineOperatorFlags());
params[0] = caller.HeapConstant(code); params[0] = caller.PointerConstant(code_start);
for (size_t i = 0; i < desc->ParameterCount(); ++i) { // WasmContext dummy.
params[i + 1] = Constant(caller, desc->GetParameterType(i), inputs[i]); params[1] = caller.PointerConstant(nullptr);
for (size_t i = 0; i < param_count; ++i) {
params[i + 2] = Constant(caller, desc->GetParameterType(i + 1), inputs[i]);
} }
Node* call = caller.AddNode(caller.common()->Call(desc), Node* call = caller.AddNode(caller.common()->Call(desc),
static_cast<int>(desc->ParameterCount() + 1), static_cast<int>(param_count + 2), params.get());
params.get());
Node* ret = Constant(caller, MachineType::Int32(), 0); Node* ret = Constant(caller, MachineType::Int32(), 0);
for (size_t i = 0; i < desc->ReturnCount(); ++i) { for (size_t i = 0; i < desc->ReturnCount(); ++i) {
// Skip roughly one third of the outputs. // Skip roughly one third of the outputs.
......
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