[fuzzer] Restructure GenerateOptRef
The purpose of this CL is: - To include all the logic of this function within the bit case switch. - To make it more clear what the probabilities for each generated subtype are. - To fix bugs where anyref fell back to unsupported types in interpreter mode. Bug: v8:11954 Change-Id: Ibc2d487c3fd66ec44a2a4f0eee874c8d3591be52 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3220347 Reviewed-by: Thibaud Michaud <thibaudm@chromium.org> Commit-Queue: Manos Koukoutos <manoskouk@chromium.org> Cr-Commit-Position: refs/heads/main@{#77385}
This commit is contained in:
parent
60824aeb0b
commit
1f8f328560
@ -2009,64 +2009,7 @@ void WasmGenerator::GenerateOptRef(HeapType type, DataRange* data) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type.representation()) {
|
constexpr GenerateFnWithHeap alternatives_indexed_type[] = {
|
||||||
// For abstract types, generate one of their subtypes, or fall back to the
|
|
||||||
// default case.
|
|
||||||
case HeapType::kAny: {
|
|
||||||
// Weighed according to the types in the module.
|
|
||||||
uint32_t num_types = builder_->builder()->NumTypes();
|
|
||||||
uint8_t random = data->get<uint8_t>() % (num_types + 3);
|
|
||||||
if (random < num_structs_ + num_arrays_) {
|
|
||||||
GenerateOptRef(HeapType(HeapType::kData), data);
|
|
||||||
return;
|
|
||||||
} else if (random < num_types) {
|
|
||||||
GenerateOptRef(HeapType(HeapType::kFunc), data);
|
|
||||||
return;
|
|
||||||
} else if (random == num_types) {
|
|
||||||
GenerateOptRef(HeapType(HeapType::kExtern), data);
|
|
||||||
return;
|
|
||||||
} else if (random == num_types + 1) {
|
|
||||||
GenerateOptRef(HeapType(HeapType::kI31), data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Else fall back to the default case outside the switch.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case HeapType::kData:
|
|
||||||
case HeapType::kEq: {
|
|
||||||
uint8_t random = data->get<uint8_t>() % (num_structs_ + num_arrays_ + 1);
|
|
||||||
if (random > 0) {
|
|
||||||
GenerateOptRef(HeapType(random - 1), data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Else fall back to the default case outside the switch.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case HeapType::kFunc: {
|
|
||||||
uint32_t random = data->get<uint32_t>() % (functions_.size() + 1);
|
|
||||||
if (random > 0) {
|
|
||||||
uint32_t signature_index = functions_[random - 1];
|
|
||||||
DCHECK(builder_->builder()->IsSignature(signature_index));
|
|
||||||
GenerateOptRef(HeapType(signature_index), data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Else fall back to the default case outside the switch.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case HeapType::kI31: {
|
|
||||||
if (data->get<bool>()) {
|
|
||||||
Generate(kWasmI32, data);
|
|
||||||
builder_->EmitWithPrefix(kExprI31New);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Else fall back to the default case outside the switch.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr GenerateFnWithHeap alternatives_with_index[] = {
|
|
||||||
&WasmGenerator::new_object, &WasmGenerator::get_local_opt_ref,
|
&WasmGenerator::new_object, &WasmGenerator::get_local_opt_ref,
|
||||||
&WasmGenerator::array_get_opt_ref, &WasmGenerator::struct_get_opt_ref,
|
&WasmGenerator::array_get_opt_ref, &WasmGenerator::struct_get_opt_ref,
|
||||||
&WasmGenerator::ref_null};
|
&WasmGenerator::ref_null};
|
||||||
@ -2076,17 +2019,113 @@ void WasmGenerator::GenerateOptRef(HeapType type, DataRange* data) {
|
|||||||
&WasmGenerator::array_get_opt_ref, &WasmGenerator::struct_get_opt_ref,
|
&WasmGenerator::array_get_opt_ref, &WasmGenerator::struct_get_opt_ref,
|
||||||
&WasmGenerator::ref_null};
|
&WasmGenerator::ref_null};
|
||||||
|
|
||||||
constexpr GenerateFnWithHeap alternatives_null[] = {
|
constexpr GenerateFnWithHeap alternatives_other[] = {
|
||||||
&WasmGenerator::array_get_opt_ref, &WasmGenerator::ref_null,
|
&WasmGenerator::array_get_opt_ref, &WasmGenerator::ref_null,
|
||||||
&WasmGenerator::get_local_opt_ref, &WasmGenerator::struct_get_opt_ref};
|
&WasmGenerator::get_local_opt_ref, &WasmGenerator::struct_get_opt_ref};
|
||||||
|
|
||||||
if (liftoff_as_reference_ && type.is_index()) {
|
switch (type.representation()) {
|
||||||
GenerateOneOf(alternatives_with_index, type, data);
|
// For abstract types, sometimes generate one of their subtypes.
|
||||||
} else if (type == HeapType::kFunc || type == HeapType::kExtern) {
|
case HeapType::kAny: {
|
||||||
GenerateOneOf(alternatives_func_extern, type, data);
|
// Note: It is possible we land here even without {liftoff_as_reference_},
|
||||||
} else {
|
// because we use anyref as a supertype of all reference types. Therefore,
|
||||||
GenerateOneOf(alternatives_null, type, data);
|
// we have to generate the correct subtypes based on the value of
|
||||||
|
// {liftoff_as_reference_}.
|
||||||
|
// Weighed according to the types in the module. If there are D data types
|
||||||
|
// and F function types, the relative frequencies for dataref is D, for
|
||||||
|
// funcref F, for externref 1, for i31ref 2 if {liftoff_as_reference_}
|
||||||
|
// otherwise 0, and for falling back to anyref 2 or 0.
|
||||||
|
const uint8_t num_data_types = num_structs_ + num_arrays_;
|
||||||
|
const uint8_t num_function_types = functions_.size();
|
||||||
|
constexpr uint8_t emit_externref = 1;
|
||||||
|
const uint8_t emit_i31ref = liftoff_as_reference_ ? 2 : 0;
|
||||||
|
const uint8_t fallback_to_anyref = liftoff_as_reference_ ? 2 : 0;
|
||||||
|
uint8_t random = data->get<uint8_t>() %
|
||||||
|
(num_data_types + num_function_types + emit_externref +
|
||||||
|
emit_i31ref + fallback_to_anyref);
|
||||||
|
if (random < num_data_types) {
|
||||||
|
DCHECK(liftoff_as_reference_);
|
||||||
|
GenerateOptRef(HeapType(HeapType::kData), data);
|
||||||
|
} else if (random < num_data_types + num_function_types) {
|
||||||
|
GenerateOptRef(HeapType(HeapType::kFunc), data);
|
||||||
|
} else if (random <
|
||||||
|
num_data_types + num_function_types + emit_externref) {
|
||||||
|
GenerateOptRef(HeapType(HeapType::kExtern), data);
|
||||||
|
} else if (random < num_data_types + num_function_types + emit_externref +
|
||||||
|
emit_i31ref) {
|
||||||
|
DCHECK(liftoff_as_reference_);
|
||||||
|
GenerateOptRef(HeapType(HeapType::kI31), data);
|
||||||
|
} else {
|
||||||
|
DCHECK(liftoff_as_reference_);
|
||||||
|
GenerateOneOf(alternatives_other, type, data);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case HeapType::kData: {
|
||||||
|
DCHECK(liftoff_as_reference_);
|
||||||
|
constexpr uint8_t fallback_to_dataref = 2;
|
||||||
|
uint8_t random = data->get<uint8_t>() %
|
||||||
|
(num_arrays_ + num_structs_ + fallback_to_dataref);
|
||||||
|
if (random < num_arrays_ + num_structs_) {
|
||||||
|
GenerateOptRef(HeapType(random), data);
|
||||||
|
} else {
|
||||||
|
GenerateOneOf(alternatives_other, type, data);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case HeapType::kEq: {
|
||||||
|
DCHECK(liftoff_as_reference_);
|
||||||
|
const uint8_t num_types = num_arrays_ + num_structs_;
|
||||||
|
constexpr uint8_t emit_i31ref = 2;
|
||||||
|
constexpr uint8_t fallback_to_eqref = 1;
|
||||||
|
uint8_t random =
|
||||||
|
data->get<uint8_t>() % (num_types + emit_i31ref + fallback_to_eqref);
|
||||||
|
if (random < num_types) {
|
||||||
|
GenerateOptRef(HeapType(random), data);
|
||||||
|
} else if (random < num_types + emit_i31ref) {
|
||||||
|
GenerateOptRef(HeapType(HeapType::kI31), data);
|
||||||
|
} else {
|
||||||
|
GenerateOneOf(alternatives_other, type, data);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case HeapType::kExtern: {
|
||||||
|
GenerateOneOf(alternatives_func_extern, type, data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case HeapType::kFunc: {
|
||||||
|
uint32_t random = data->get<uint32_t>() % (functions_.size() + 1);
|
||||||
|
if (random < functions_.size()) {
|
||||||
|
if (liftoff_as_reference_) {
|
||||||
|
// Only reduce to indexed type with liftoff as reference.
|
||||||
|
uint32_t signature_index = functions_[random];
|
||||||
|
DCHECK(builder_->builder()->IsSignature(signature_index));
|
||||||
|
GenerateOptRef(HeapType(signature_index), data);
|
||||||
|
} else {
|
||||||
|
// If interpreter is used as reference, generate a ref.func directly.
|
||||||
|
builder_->EmitWithU32V(kExprRefFunc, random);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GenerateOneOf(alternatives_func_extern, type, data);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case HeapType::kI31: {
|
||||||
|
DCHECK(liftoff_as_reference_);
|
||||||
|
if (data->get<bool>()) {
|
||||||
|
Generate(kWasmI32, data);
|
||||||
|
builder_->EmitWithPrefix(kExprI31New);
|
||||||
|
} else {
|
||||||
|
GenerateOneOf(alternatives_other, type, data);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// Indexed type.
|
||||||
|
DCHECK(liftoff_as_reference_);
|
||||||
|
GenerateOneOf(alternatives_indexed_type, type, data);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ValueType> WasmGenerator::GenerateTypes(DataRange* data) {
|
std::vector<ValueType> WasmGenerator::GenerateTypes(DataRange* data) {
|
||||||
|
Loading…
Reference in New Issue
Block a user