summaryrefslogtreecommitdiff
path: root/deps/v8/test/fuzzer/wasm-compile.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/test/fuzzer/wasm-compile.cc')
-rw-r--r--deps/v8/test/fuzzer/wasm-compile.cc141
1 files changed, 132 insertions, 9 deletions
diff --git a/deps/v8/test/fuzzer/wasm-compile.cc b/deps/v8/test/fuzzer/wasm-compile.cc
index 4192a938e8..f4b2a912c6 100644
--- a/deps/v8/test/fuzzer/wasm-compile.cc
+++ b/deps/v8/test/fuzzer/wasm-compile.cc
@@ -31,6 +31,7 @@ namespace fuzzer {
namespace {
constexpr int kMaxFunctions = 4;
+constexpr int kMaxGlobals = 64;
class DataRange {
const uint8_t* data_;
@@ -137,6 +138,21 @@ class WasmGenerator {
Generate<T>(data);
}
+ enum IfType { kIf, kIfElse };
+
+ template <ValueType T, IfType type>
+ void if_(DataRange& data) {
+ static_assert(T == kWasmStmt || type == kIfElse,
+ "if without else cannot produce a value");
+ Generate<kWasmI32>(data);
+ BlockScope block_scope(this, kExprIf, T, T);
+ Generate<T>(data);
+ if (type == kIfElse) {
+ builder_->Emit(kExprElse);
+ Generate<T>(data);
+ }
+ }
+
void br(DataRange& data) {
// There is always at least the block representing the function body.
DCHECK(!blocks_.empty());
@@ -148,6 +164,20 @@ class WasmGenerator {
kExprBr, static_cast<uint32_t>(blocks_.size()) - 1 - target_block);
}
+ template <ValueType wanted_type>
+ void br_if(DataRange& data) {
+ // There is always at least the block representing the function body.
+ DCHECK(!blocks_.empty());
+ const uint32_t target_block = data.get<uint32_t>() % blocks_.size();
+ const ValueType break_type = blocks_[target_block];
+
+ Generate(break_type, data);
+ Generate(kWasmI32, data);
+ builder_->EmitWithI32V(
+ kExprBrIf, static_cast<uint32_t>(blocks_.size()) - 1 - target_block);
+ ConvertOrGenerate(break_type, wanted_type, data);
+ }
+
// TODO(eholk): make this function constexpr once gcc supports it
static uint8_t max_alignment(WasmOpcode memop) {
switch (memop) {
@@ -234,6 +264,17 @@ class WasmGenerator {
builder_->Emit(kConvertOpcodes[arr_idx]);
}
+ void ConvertOrGenerate(ValueType src, ValueType dst, DataRange& data) {
+ if (src == dst) return;
+ if (src == kWasmStmt && dst != kWasmStmt) {
+ Generate(dst, data);
+ } else if (dst == kWasmStmt && src != kWasmStmt) {
+ builder_->Emit(kExprDrop);
+ } else {
+ Convert(src, dst);
+ }
+ }
+
void call(DataRange& data, ValueType wanted_type) {
int func_index = data.get<uint8_t>() % functions_.size();
FunctionSig* sig = functions_[func_index];
@@ -258,15 +299,15 @@ class WasmGenerator {
}
}
- struct Local {
+ struct Var {
uint32_t index;
ValueType type = kWasmStmt;
- Local() = default;
- Local(uint32_t index, ValueType type) : index(index), type(type) {}
+ Var() = default;
+ Var(uint32_t index, ValueType type) : index(index), type(type) {}
bool is_valid() const { return type != kWasmStmt; }
};
- Local GetRandomLocal(DataRange& data) {
+ Var GetRandomLocal(DataRange& data) {
uint32_t num_params =
static_cast<uint32_t>(builder_->signature()->parameter_count());
uint32_t num_locals = static_cast<uint32_t>(locals_.size());
@@ -279,7 +320,7 @@ class WasmGenerator {
template <ValueType wanted_type>
void local_op(DataRange& data, WasmOpcode opcode) {
- Local local = GetRandomLocal(data);
+ Var local = GetRandomLocal(data);
// If there are no locals and no parameters, just generate any value (if a
// value is needed), or do nothing.
if (!local.is_valid()) {
@@ -296,6 +337,7 @@ class WasmGenerator {
template <ValueType wanted_type>
void get_local(DataRange& data) {
+ static_assert(wanted_type != kWasmStmt, "illegal type");
local_op<wanted_type>(data, kExprGetLocal);
}
@@ -306,6 +348,46 @@ class WasmGenerator {
local_op<wanted_type>(data, kExprTeeLocal);
}
+ Var GetRandomGlobal(DataRange& data, bool ensure_mutable) {
+ uint32_t index;
+ if (ensure_mutable) {
+ if (mutable_globals_.empty()) return {};
+ index = mutable_globals_[data.get<uint8_t>() % mutable_globals_.size()];
+ } else {
+ if (globals_.empty()) return {};
+ index = data.get<uint8_t>() % globals_.size();
+ }
+ ValueType type = globals_[index];
+ return {index, type};
+ }
+
+ template <ValueType wanted_type>
+ void global_op(DataRange& data) {
+ constexpr bool is_set = wanted_type == kWasmStmt;
+ Var global = GetRandomGlobal(data, is_set);
+ // If there are no globals, just generate any value (if a value is needed),
+ // or do nothing.
+ if (!global.is_valid()) {
+ if (wanted_type == kWasmStmt) return;
+ return Generate<wanted_type>(data);
+ }
+
+ if (is_set) Generate(global.type, data);
+ builder_->EmitWithU32V(is_set ? kExprSetGlobal : kExprGetGlobal,
+ global.index);
+ if (!is_set && global.type != wanted_type) {
+ Convert(global.type, wanted_type);
+ }
+ }
+
+ template <ValueType wanted_type>
+ void get_global(DataRange& data) {
+ static_assert(wanted_type != kWasmStmt, "illegal type");
+ global_op<wanted_type>(data);
+ }
+
+ void set_global(DataRange& data) { global_op<kWasmStmt>(data); }
+
template <ValueType T1, ValueType T2>
void sequence(DataRange& data) {
Generate<T1, T2>(data);
@@ -343,8 +425,13 @@ class WasmGenerator {
public:
WasmGenerator(WasmFunctionBuilder* fn,
- const std::vector<FunctionSig*>& functions, DataRange& data)
- : builder_(fn), functions_(functions) {
+ const std::vector<FunctionSig*>& functions,
+ const std::vector<ValueType>& globals,
+ const std::vector<uint8_t>& mutable_globals, DataRange& data)
+ : builder_(fn),
+ functions_(functions),
+ globals_(globals),
+ mutable_globals_(mutable_globals) {
FunctionSig* sig = fn->signature();
DCHECK_GE(1, sig->return_count());
blocks_.push_back(sig->return_count() == 0 ? kWasmStmt : sig->GetReturn(0));
@@ -375,6 +462,8 @@ class WasmGenerator {
std::vector<ValueType> blocks_;
const std::vector<FunctionSig*>& functions_;
std::vector<ValueType> locals_;
+ std::vector<ValueType> globals_;
+ std::vector<uint8_t> mutable_globals_; // indexes into {globals_}.
uint32_t recursion_depth = 0;
static constexpr uint32_t kMaxRecursionDepth = 64;
@@ -390,9 +479,13 @@ void WasmGenerator::Generate<kWasmStmt>(DataRange& data) {
if (recursion_limit_reached() || data.size() == 0) return;
constexpr generate_fn alternates[] = {
+ &WasmGenerator::sequence<kWasmStmt, kWasmStmt>,
&WasmGenerator::block<kWasmStmt>,
&WasmGenerator::loop<kWasmStmt>,
+ &WasmGenerator::if_<kWasmStmt, kIf>,
+ &WasmGenerator::if_<kWasmStmt, kIfElse>,
&WasmGenerator::br,
+ &WasmGenerator::br_if<kWasmStmt>,
&WasmGenerator::memop<kExprI32StoreMem, kWasmI32>,
&WasmGenerator::memop<kExprI32StoreMem8, kWasmI32>,
@@ -408,7 +501,8 @@ void WasmGenerator::Generate<kWasmStmt>(DataRange& data) {
&WasmGenerator::call<kWasmStmt>,
- &WasmGenerator::set_local};
+ &WasmGenerator::set_local,
+ &WasmGenerator::set_global};
GenerateOneOf(alternates, data);
}
@@ -481,6 +575,8 @@ void WasmGenerator::Generate<kWasmI32>(DataRange& data) {
&WasmGenerator::block<kWasmI32>,
&WasmGenerator::loop<kWasmI32>,
+ &WasmGenerator::if_<kWasmI32, kIfElse>,
+ &WasmGenerator::br_if<kWasmI32>,
&WasmGenerator::memop<kExprI32LoadMem>,
&WasmGenerator::memop<kExprI32LoadMem8S>,
@@ -493,6 +589,7 @@ void WasmGenerator::Generate<kWasmI32>(DataRange& data) {
&WasmGenerator::get_local<kWasmI32>,
&WasmGenerator::tee_local<kWasmI32>,
+ &WasmGenerator::get_global<kWasmI32>,
&WasmGenerator::call<kWasmI32>};
@@ -534,6 +631,8 @@ void WasmGenerator::Generate<kWasmI64>(DataRange& data) {
&WasmGenerator::block<kWasmI64>,
&WasmGenerator::loop<kWasmI64>,
+ &WasmGenerator::if_<kWasmI64, kIfElse>,
+ &WasmGenerator::br_if<kWasmI64>,
&WasmGenerator::memop<kExprI64LoadMem>,
&WasmGenerator::memop<kExprI64LoadMem8S>,
@@ -545,6 +644,7 @@ void WasmGenerator::Generate<kWasmI64>(DataRange& data) {
&WasmGenerator::get_local<kWasmI64>,
&WasmGenerator::tee_local<kWasmI64>,
+ &WasmGenerator::get_global<kWasmI64>,
&WasmGenerator::call<kWasmI64>};
@@ -568,11 +668,14 @@ void WasmGenerator::Generate<kWasmF32>(DataRange& data) {
&WasmGenerator::block<kWasmF32>,
&WasmGenerator::loop<kWasmF32>,
+ &WasmGenerator::if_<kWasmF32, kIfElse>,
+ &WasmGenerator::br_if<kWasmF32>,
&WasmGenerator::memop<kExprF32LoadMem>,
&WasmGenerator::get_local<kWasmF32>,
&WasmGenerator::tee_local<kWasmF32>,
+ &WasmGenerator::get_global<kWasmF32>,
&WasmGenerator::call<kWasmF32>};
@@ -596,11 +699,14 @@ void WasmGenerator::Generate<kWasmF64>(DataRange& data) {
&WasmGenerator::block<kWasmF64>,
&WasmGenerator::loop<kWasmF64>,
+ &WasmGenerator::if_<kWasmF64, kIfElse>,
+ &WasmGenerator::br_if<kWasmF64>,
&WasmGenerator::memop<kExprF64LoadMem>,
&WasmGenerator::get_local<kWasmF64>,
&WasmGenerator::tee_local<kWasmF64>,
+ &WasmGenerator::get_global<kWasmF64>,
&WasmGenerator::call<kWasmF64>};
@@ -664,6 +770,22 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer {
function_signatures.push_back(GenerateSig(zone, range));
}
+ int num_globals = range.get<uint8_t>() % (kMaxGlobals + 1);
+ std::vector<ValueType> globals;
+ std::vector<uint8_t> mutable_globals;
+ globals.reserve(num_globals);
+ mutable_globals.reserve(num_globals);
+
+ for (int i = 0; i < num_globals; ++i) {
+ ValueType type = GetValueType(range);
+ const bool exported = range.get<bool>();
+ // 1/8 of globals are immutable.
+ const bool mutability = (range.get<uint8_t>() % 8) != 0;
+ builder.AddGlobal(type, exported, mutability, WasmInitExpr());
+ globals.push_back(type);
+ if (mutability) mutable_globals.push_back(static_cast<uint8_t>(i));
+ }
+
for (int i = 0; i < num_functions; ++i) {
DataRange function_range =
i == num_functions - 1 ? std::move(range) : range.split();
@@ -671,7 +793,8 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer {
FunctionSig* sig = function_signatures[i];
WasmFunctionBuilder* f = builder.AddFunction(sig);
- WasmGenerator gen(f, function_signatures, function_range);
+ WasmGenerator gen(f, function_signatures, globals, mutable_globals,
+ function_range);
ValueType return_type =
sig->return_count() == 0 ? kWasmStmt : sig->GetReturn(0);
gen.Generate(return_type, function_range);