Commit 19fa6114 authored by Thibaud Michaud's avatar Thibaud Michaud Committed by Commit Bot

[wasm] Support EH in the compile fuzzer

R=ahaas@chromium.org

Bug: v8:8091
Change-Id: Ie3450c2a55d2fd272efc6c69632cf52a9aede597
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2699259
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72817}
parent e7195170
...@@ -248,6 +248,7 @@ WasmModuleBuilder::WasmModuleBuilder(Zone* zone) ...@@ -248,6 +248,7 @@ WasmModuleBuilder::WasmModuleBuilder(Zone* zone)
data_segments_(zone), data_segments_(zone),
indirect_functions_(zone), indirect_functions_(zone),
globals_(zone), globals_(zone),
exceptions_(zone),
signature_map_(zone), signature_map_(zone),
start_function_index_(-1), start_function_index_(-1),
min_memory_size_(16), min_memory_size_(16),
...@@ -280,6 +281,14 @@ uint32_t WasmModuleBuilder::AddSignature(FunctionSig* sig) { ...@@ -280,6 +281,14 @@ uint32_t WasmModuleBuilder::AddSignature(FunctionSig* sig) {
return index; return index;
} }
uint32_t WasmModuleBuilder::AddException(FunctionSig* type) {
DCHECK_EQ(0, type->return_count());
int type_index = AddSignature(type);
uint32_t except_index = static_cast<uint32_t>(exceptions_.size());
exceptions_.push_back(type_index);
return except_index;
}
uint32_t WasmModuleBuilder::AddStructType(StructType* type) { uint32_t WasmModuleBuilder::AddStructType(StructType* type) {
uint32_t index = static_cast<uint32_t>(types_.size()); uint32_t index = static_cast<uint32_t>(types_.size());
types_.push_back(Type(type)); types_.push_back(Type(type));
...@@ -623,6 +632,17 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const { ...@@ -623,6 +632,17 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
FixupSection(buffer, start); FixupSection(buffer, start);
} }
// Emit event section.
if (exceptions_.size() > 0) {
size_t start = EmitSection(kExceptionSectionCode, buffer);
buffer->write_size(exceptions_.size());
for (int type : exceptions_) {
buffer->write_u32v(kExceptionAttribute);
buffer->write_u32v(type);
}
FixupSection(buffer, start);
}
// == Emit globals =========================================================== // == Emit globals ===========================================================
if (globals_.size() > 0) { if (globals_.size() > 0) {
size_t start = EmitSection(kGlobalSectionCode, buffer); size_t start = EmitSection(kGlobalSectionCode, buffer);
......
...@@ -250,6 +250,7 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject { ...@@ -250,6 +250,7 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
bool mutability, Vector<const char> module = {}); bool mutability, Vector<const char> module = {});
void AddDataSegment(const byte* data, uint32_t size, uint32_t dest); void AddDataSegment(const byte* data, uint32_t size, uint32_t dest);
uint32_t AddSignature(FunctionSig* sig); uint32_t AddSignature(FunctionSig* sig);
uint32_t AddException(FunctionSig* type);
uint32_t AddStructType(StructType* type); uint32_t AddStructType(StructType* type);
uint32_t AddArrayType(ArrayType* type); uint32_t AddArrayType(ArrayType* type);
// In the current implementation, it's supported to have uninitialized slots // In the current implementation, it's supported to have uninitialized slots
...@@ -284,6 +285,12 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject { ...@@ -284,6 +285,12 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
return types_[index].sig; return types_[index].sig;
} }
int NumExceptions() { return static_cast<int>(exceptions_.size()); }
FunctionSig* GetExceptionType(int index) {
return types_[exceptions_[index]].sig;
}
private: private:
struct Type { struct Type {
enum Kind { kFunctionSig, kStructType, kArrayType }; enum Kind { kFunctionSig, kStructType, kArrayType };
...@@ -351,6 +358,7 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject { ...@@ -351,6 +358,7 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
ZoneVector<WasmDataSegment> data_segments_; ZoneVector<WasmDataSegment> data_segments_;
ZoneVector<uint32_t> indirect_functions_; ZoneVector<uint32_t> indirect_functions_;
ZoneVector<WasmGlobal> globals_; ZoneVector<WasmGlobal> globals_;
ZoneVector<int> exceptions_;
ZoneUnorderedMap<FunctionSig, uint32_t> signature_map_; ZoneUnorderedMap<FunctionSig, uint32_t> signature_map_;
int start_function_index_; int start_function_index_;
uint32_t max_table_size_ = 0; uint32_t max_table_size_ = 0;
......
...@@ -33,6 +33,7 @@ constexpr int kMaxFunctions = 4; ...@@ -33,6 +33,7 @@ constexpr int kMaxFunctions = 4;
constexpr int kMaxGlobals = 64; constexpr int kMaxGlobals = 64;
constexpr int kMaxParameters = 15; constexpr int kMaxParameters = 15;
constexpr int kMaxReturns = 15; constexpr int kMaxReturns = 15;
constexpr int kMaxExceptions = 4;
class DataRange { class DataRange {
Vector<const uint8_t> data_; Vector<const uint8_t> data_;
...@@ -116,8 +117,8 @@ class WasmGenerator { ...@@ -116,8 +117,8 @@ class WasmGenerator {
BlockScope(WasmGenerator* gen, WasmOpcode block_type, BlockScope(WasmGenerator* gen, WasmOpcode block_type,
Vector<const ValueType> param_types, Vector<const ValueType> param_types,
Vector<const ValueType> result_types, Vector<const ValueType> result_types,
Vector<const ValueType> br_types) Vector<const ValueType> br_types, bool emit_end = true)
: gen_(gen) { : gen_(gen), emit_end_(emit_end) {
gen->blocks_.emplace_back(br_types.begin(), br_types.end()); gen->blocks_.emplace_back(br_types.begin(), br_types.end());
if (param_types.size() == 0 && result_types.size() == 0) { if (param_types.size() == 0 && result_types.size() == 0) {
gen->builder_->EmitWithU8(block_type, kWasmStmt.value_type_code()); gen->builder_->EmitWithU8(block_type, kWasmStmt.value_type_code());
...@@ -146,12 +147,13 @@ class WasmGenerator { ...@@ -146,12 +147,13 @@ class WasmGenerator {
} }
~BlockScope() { ~BlockScope() {
gen_->builder_->Emit(kExprEnd); if (emit_end_) gen_->builder_->Emit(kExprEnd);
gen_->blocks_.pop_back(); gen_->blocks_.pop_back();
} }
private: private:
WasmGenerator* const gen_; WasmGenerator* const gen_;
bool emit_end_;
}; };
void block(Vector<const ValueType> param_types, void block(Vector<const ValueType> param_types,
...@@ -204,6 +206,60 @@ class WasmGenerator { ...@@ -204,6 +206,60 @@ class WasmGenerator {
type, data); type, data);
} }
void try_block_helper(ValueType return_type, DataRange* data) {
bool has_catch_all = data->get<uint8_t>() % 2;
uint8_t num_catch =
data->get<uint8_t>() % (builder_->builder()->NumExceptions() + 1);
bool is_delegate =
num_catch == 0 && !has_catch_all && data->get<uint8_t>() % 2 == 0;
// Allow one more target than there are enclosing try blocks, for delegating
// to the caller.
uint8_t delegate_target = data->get<uint8_t>() % (try_blocks_.size() + 1);
bool is_unwind = num_catch == 0 && !has_catch_all && !is_delegate;
Vector<const ValueType> return_type_vec =
return_type.kind() == ValueType::kStmt ? Vector<ValueType>{}
: VectorOf({return_type});
BlockScope block_scope(this, kExprTry, {}, return_type_vec, return_type_vec,
!is_delegate);
int control_depth = static_cast<int>(blocks_.size()) - 1;
try_blocks_.push_back(control_depth);
Generate(return_type, data);
try_blocks_.pop_back();
catch_blocks_.push_back(control_depth);
for (int i = 0; i < num_catch; ++i) {
const FunctionSig* exception_type =
builder_->builder()->GetExceptionType(i);
auto exception_type_vec = VectorOf(exception_type->parameters().begin(),
exception_type->parameter_count());
builder_->EmitWithU32V(kExprCatch, i);
ConsumeAndGenerate(exception_type_vec, return_type_vec, data);
}
if (has_catch_all) {
builder_->Emit(kExprCatchAll);
Generate(return_type, data);
}
if (is_delegate) {
DCHECK_GT(blocks_.size(), try_blocks_.size());
// If {delegate_target == try_blocks_.size()}, delegate to the caller.
int delegate_depth = delegate_target == try_blocks_.size()
? static_cast<int>(blocks_.size()) - 2
: static_cast<int>(blocks_.size() - 2 -
try_blocks_[delegate_target]);
builder_->EmitWithU32V(kExprDelegate, delegate_depth);
}
catch_blocks_.pop_back();
if (is_unwind) {
builder_->Emit(kExprUnwind);
Generate(return_type, data);
}
}
template <ValueType::Kind T>
void try_block(DataRange* data) {
try_block_helper(ValueType::Primitive(T), data);
}
void any_block(Vector<const ValueType> param_types, void any_block(Vector<const ValueType> param_types,
Vector<const ValueType> return_types, DataRange* data) { Vector<const ValueType> return_types, DataRange* data) {
uint8_t block_type = data->get<uint8_t>() % 4; uint8_t block_type = data->get<uint8_t>() % 4;
...@@ -652,6 +708,25 @@ class WasmGenerator { ...@@ -652,6 +708,25 @@ class WasmGenerator {
void set_global(DataRange* data) { global_op<ValueType::kStmt>(data); } void set_global(DataRange* data) { global_op<ValueType::kStmt>(data); }
void throw_or_rethrow(DataRange* data) {
bool rethrow = data->get<uint8_t>() % 2;
if (rethrow && !catch_blocks_.empty()) {
int control_depth = static_cast<int>(blocks_.size() - 1);
int catch_index =
data->get<uint8_t>() % static_cast<int>(catch_blocks_.size());
builder_->EmitWithU32V(kExprRethrow,
control_depth - catch_blocks_[catch_index]);
} else {
int tag = data->get<uint8_t>() % builder_->builder()->NumExceptions();
FunctionSig* exception_sig = builder_->builder()->GetExceptionType(tag);
Vector<const ValueType> exception_types(
exception_sig->parameters().begin(),
exception_sig->parameter_count());
Generate(exception_types, data);
builder_->EmitWithU32V(kExprThrow, tag);
}
}
template <ValueType::Kind... Types> template <ValueType::Kind... Types>
void sequence(DataRange* data) { void sequence(DataRange* data) {
Generate<Types...>(data); Generate<Types...>(data);
...@@ -736,6 +811,8 @@ class WasmGenerator { ...@@ -736,6 +811,8 @@ class WasmGenerator {
std::vector<ValueType> globals_; std::vector<ValueType> globals_;
std::vector<uint8_t> mutable_globals_; // indexes into {globals_}. std::vector<uint8_t> mutable_globals_; // indexes into {globals_}.
uint32_t recursion_depth = 0; uint32_t recursion_depth = 0;
std::vector<int> try_blocks_;
std::vector<int> catch_blocks_;
static constexpr uint32_t kMaxRecursionDepth = 64; static constexpr uint32_t kMaxRecursionDepth = 64;
...@@ -806,7 +883,9 @@ void WasmGenerator::Generate<ValueType::kStmt>(DataRange* data) { ...@@ -806,7 +883,9 @@ void WasmGenerator::Generate<ValueType::kStmt>(DataRange* data) {
&WasmGenerator::call_indirect<ValueType::kStmt>, &WasmGenerator::call_indirect<ValueType::kStmt>,
&WasmGenerator::set_local, &WasmGenerator::set_local,
&WasmGenerator::set_global}; &WasmGenerator::set_global,
&WasmGenerator::throw_or_rethrow,
&WasmGenerator::try_block<ValueType::kStmt>};
GenerateOneOf(alternatives, data); GenerateOneOf(alternatives, data);
} }
...@@ -977,7 +1056,8 @@ void WasmGenerator::Generate<ValueType::kI32>(DataRange* data) { ...@@ -977,7 +1056,8 @@ void WasmGenerator::Generate<ValueType::kI32>(DataRange* data) {
&WasmGenerator::select_with_type<ValueType::kI32>, &WasmGenerator::select_with_type<ValueType::kI32>,
&WasmGenerator::call<ValueType::kI32>, &WasmGenerator::call<ValueType::kI32>,
&WasmGenerator::call_indirect<ValueType::kI32>}; &WasmGenerator::call_indirect<ValueType::kI32>,
&WasmGenerator::try_block<ValueType::kI32>};
GenerateOneOf(alternatives, data); GenerateOneOf(alternatives, data);
} }
...@@ -1119,7 +1199,8 @@ void WasmGenerator::Generate<ValueType::kI64>(DataRange* data) { ...@@ -1119,7 +1199,8 @@ void WasmGenerator::Generate<ValueType::kI64>(DataRange* data) {
&WasmGenerator::select_with_type<ValueType::kI64>, &WasmGenerator::select_with_type<ValueType::kI64>,
&WasmGenerator::call<ValueType::kI64>, &WasmGenerator::call<ValueType::kI64>,
&WasmGenerator::call_indirect<ValueType::kI64>}; &WasmGenerator::call_indirect<ValueType::kI64>,
&WasmGenerator::try_block<ValueType::kI64>};
GenerateOneOf(alternatives, data); GenerateOneOf(alternatives, data);
} }
...@@ -1177,7 +1258,8 @@ void WasmGenerator::Generate<ValueType::kF32>(DataRange* data) { ...@@ -1177,7 +1258,8 @@ void WasmGenerator::Generate<ValueType::kF32>(DataRange* data) {
&WasmGenerator::select_with_type<ValueType::kF32>, &WasmGenerator::select_with_type<ValueType::kF32>,
&WasmGenerator::call<ValueType::kF32>, &WasmGenerator::call<ValueType::kF32>,
&WasmGenerator::call_indirect<ValueType::kF32>}; &WasmGenerator::call_indirect<ValueType::kF32>,
&WasmGenerator::try_block<ValueType::kF32>};
GenerateOneOf(alternatives, data); GenerateOneOf(alternatives, data);
} }
...@@ -1235,7 +1317,8 @@ void WasmGenerator::Generate<ValueType::kF64>(DataRange* data) { ...@@ -1235,7 +1317,8 @@ void WasmGenerator::Generate<ValueType::kF64>(DataRange* data) {
&WasmGenerator::select_with_type<ValueType::kF64>, &WasmGenerator::select_with_type<ValueType::kF64>,
&WasmGenerator::call<ValueType::kF64>, &WasmGenerator::call<ValueType::kF64>,
&WasmGenerator::call_indirect<ValueType::kF64>}; &WasmGenerator::call_indirect<ValueType::kF64>,
&WasmGenerator::try_block<ValueType::kF64>};
GenerateOneOf(alternatives, data); GenerateOneOf(alternatives, data);
} }
...@@ -1737,10 +1820,14 @@ void WasmGenerator::ConsumeAndGenerate(Vector<const ValueType> param_types, ...@@ -1737,10 +1820,14 @@ void WasmGenerator::ConsumeAndGenerate(Vector<const ValueType> param_types,
} }
} }
FunctionSig* GenerateSig(Zone* zone, DataRange* data) { enum SigKind { kFunctionSig, kExceptionSig };
FunctionSig* GenerateSig(Zone* zone, DataRange* data, SigKind sig_kind) {
// Generate enough parameters to spill some to the stack. // Generate enough parameters to spill some to the stack.
int num_params = int{data->get<uint8_t>()} % (kMaxParameters + 1); int num_params = int{data->get<uint8_t>()} % (kMaxParameters + 1);
int num_returns = int{data->get<uint8_t>()} % (kMaxReturns + 1); int num_returns = sig_kind == kFunctionSig
? int{data->get<uint8_t>()} % (kMaxReturns + 1)
: 0;
FunctionSig::Builder builder(zone, num_returns, num_params); FunctionSig::Builder builder(zone, num_returns, num_params);
for (int i = 0; i < num_returns; ++i) builder.AddReturn(GetValueType(data)); for (int i = 0; i < num_returns; ++i) builder.AddReturn(GetValueType(data));
...@@ -1768,7 +1855,7 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer { ...@@ -1768,7 +1855,7 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer {
int num_functions = 1 + (range.get<uint8_t>() % kMaxFunctions); int num_functions = 1 + (range.get<uint8_t>() % kMaxFunctions);
for (int i = 1; i < num_functions; ++i) { for (int i = 1; i < num_functions; ++i) {
FunctionSig* sig = GenerateSig(zone, &range); FunctionSig* sig = GenerateSig(zone, &range, kFunctionSig);
uint32_t signature_index = builder.AddSignature(sig); uint32_t signature_index = builder.AddSignature(sig);
function_signatures.push_back(signature_index); function_signatures.push_back(signature_index);
} }
...@@ -1779,6 +1866,12 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer { ...@@ -1779,6 +1866,12 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer {
globals.reserve(num_globals); globals.reserve(num_globals);
mutable_globals.reserve(num_globals); mutable_globals.reserve(num_globals);
int num_exceptions = 1 + (range.get<uint8_t>() % kMaxExceptions);
for (int i = 0; i < num_exceptions; ++i) {
FunctionSig* sig = GenerateSig(zone, &range, kExceptionSig);
builder.AddException(sig);
}
for (int i = 0; i < num_globals; ++i) { for (int i = 0; i < num_globals; ++i) {
ValueType type = GetValueType(&range); ValueType type = GetValueType(&range);
// 1/8 of globals are immutable. // 1/8 of globals are immutable.
...@@ -1830,6 +1923,7 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer { ...@@ -1830,6 +1923,7 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
constexpr bool require_valid = true; constexpr bool require_valid = true;
EXPERIMENTAL_FLAG_SCOPE(reftypes); EXPERIMENTAL_FLAG_SCOPE(reftypes);
EXPERIMENTAL_FLAG_SCOPE(eh);
WasmCompileFuzzer().FuzzWasmModule({data, size}, require_valid); WasmCompileFuzzer().FuzzWasmModule({data, size}, require_valid);
return 0; return 0;
} }
......
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