Commit 1f1fa410 authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[wasm] [fuzzer] Add globals

This adds support for set_global and get_global.

R=ahaas@chromium.org

Change-Id: I08bfa3c23080f473616970e9894cfb6e55a4f76d
Reviewed-on: https://chromium-review.googlesource.com/890744
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50963}
parent 5113f10d
...@@ -31,6 +31,7 @@ namespace fuzzer { ...@@ -31,6 +31,7 @@ namespace fuzzer {
namespace { namespace {
constexpr int kMaxFunctions = 4; constexpr int kMaxFunctions = 4;
constexpr int kMaxGlobals = 64;
class DataRange { class DataRange {
const uint8_t* data_; const uint8_t* data_;
...@@ -298,15 +299,15 @@ class WasmGenerator { ...@@ -298,15 +299,15 @@ class WasmGenerator {
} }
} }
struct Local { struct Var {
uint32_t index; uint32_t index;
ValueType type = kWasmStmt; ValueType type = kWasmStmt;
Local() = default; Var() = default;
Local(uint32_t index, ValueType type) : index(index), type(type) {} Var(uint32_t index, ValueType type) : index(index), type(type) {}
bool is_valid() const { return type != kWasmStmt; } bool is_valid() const { return type != kWasmStmt; }
}; };
Local GetRandomLocal(DataRange& data) { Var GetRandomLocal(DataRange& data) {
uint32_t num_params = uint32_t num_params =
static_cast<uint32_t>(builder_->signature()->parameter_count()); static_cast<uint32_t>(builder_->signature()->parameter_count());
uint32_t num_locals = static_cast<uint32_t>(locals_.size()); uint32_t num_locals = static_cast<uint32_t>(locals_.size());
...@@ -319,7 +320,7 @@ class WasmGenerator { ...@@ -319,7 +320,7 @@ class WasmGenerator {
template <ValueType wanted_type> template <ValueType wanted_type>
void local_op(DataRange& data, WasmOpcode opcode) { 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 // If there are no locals and no parameters, just generate any value (if a
// value is needed), or do nothing. // value is needed), or do nothing.
if (!local.is_valid()) { if (!local.is_valid()) {
...@@ -336,6 +337,7 @@ class WasmGenerator { ...@@ -336,6 +337,7 @@ class WasmGenerator {
template <ValueType wanted_type> template <ValueType wanted_type>
void get_local(DataRange& data) { void get_local(DataRange& data) {
static_assert(wanted_type != kWasmStmt, "illegal type");
local_op<wanted_type>(data, kExprGetLocal); local_op<wanted_type>(data, kExprGetLocal);
} }
...@@ -346,6 +348,46 @@ class WasmGenerator { ...@@ -346,6 +348,46 @@ class WasmGenerator {
local_op<wanted_type>(data, kExprTeeLocal); 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> template <ValueType T1, ValueType T2>
void sequence(DataRange& data) { void sequence(DataRange& data) {
Generate<T1, T2>(data); Generate<T1, T2>(data);
...@@ -383,8 +425,13 @@ class WasmGenerator { ...@@ -383,8 +425,13 @@ class WasmGenerator {
public: public:
WasmGenerator(WasmFunctionBuilder* fn, WasmGenerator(WasmFunctionBuilder* fn,
const std::vector<FunctionSig*>& functions, DataRange& data) const std::vector<FunctionSig*>& functions,
: builder_(fn), functions_(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(); FunctionSig* sig = fn->signature();
DCHECK_GE(1, sig->return_count()); DCHECK_GE(1, sig->return_count());
blocks_.push_back(sig->return_count() == 0 ? kWasmStmt : sig->GetReturn(0)); blocks_.push_back(sig->return_count() == 0 ? kWasmStmt : sig->GetReturn(0));
...@@ -415,6 +462,8 @@ class WasmGenerator { ...@@ -415,6 +462,8 @@ class WasmGenerator {
std::vector<ValueType> blocks_; std::vector<ValueType> blocks_;
const std::vector<FunctionSig*>& functions_; const std::vector<FunctionSig*>& functions_;
std::vector<ValueType> locals_; std::vector<ValueType> locals_;
std::vector<ValueType> globals_;
std::vector<uint8_t> mutable_globals_; // indexes into {globals_}.
uint32_t recursion_depth = 0; uint32_t recursion_depth = 0;
static constexpr uint32_t kMaxRecursionDepth = 64; static constexpr uint32_t kMaxRecursionDepth = 64;
...@@ -451,7 +500,8 @@ void WasmGenerator::Generate<kWasmStmt>(DataRange& data) { ...@@ -451,7 +500,8 @@ void WasmGenerator::Generate<kWasmStmt>(DataRange& data) {
&WasmGenerator::call<kWasmStmt>, &WasmGenerator::call<kWasmStmt>,
&WasmGenerator::set_local}; &WasmGenerator::set_local,
&WasmGenerator::set_global};
GenerateOneOf(alternates, data); GenerateOneOf(alternates, data);
} }
...@@ -538,6 +588,7 @@ void WasmGenerator::Generate<kWasmI32>(DataRange& data) { ...@@ -538,6 +588,7 @@ void WasmGenerator::Generate<kWasmI32>(DataRange& data) {
&WasmGenerator::get_local<kWasmI32>, &WasmGenerator::get_local<kWasmI32>,
&WasmGenerator::tee_local<kWasmI32>, &WasmGenerator::tee_local<kWasmI32>,
&WasmGenerator::get_global<kWasmI32>,
&WasmGenerator::call<kWasmI32>}; &WasmGenerator::call<kWasmI32>};
...@@ -592,6 +643,7 @@ void WasmGenerator::Generate<kWasmI64>(DataRange& data) { ...@@ -592,6 +643,7 @@ void WasmGenerator::Generate<kWasmI64>(DataRange& data) {
&WasmGenerator::get_local<kWasmI64>, &WasmGenerator::get_local<kWasmI64>,
&WasmGenerator::tee_local<kWasmI64>, &WasmGenerator::tee_local<kWasmI64>,
&WasmGenerator::get_global<kWasmI64>,
&WasmGenerator::call<kWasmI64>}; &WasmGenerator::call<kWasmI64>};
...@@ -622,6 +674,7 @@ void WasmGenerator::Generate<kWasmF32>(DataRange& data) { ...@@ -622,6 +674,7 @@ void WasmGenerator::Generate<kWasmF32>(DataRange& data) {
&WasmGenerator::get_local<kWasmF32>, &WasmGenerator::get_local<kWasmF32>,
&WasmGenerator::tee_local<kWasmF32>, &WasmGenerator::tee_local<kWasmF32>,
&WasmGenerator::get_global<kWasmF32>,
&WasmGenerator::call<kWasmF32>}; &WasmGenerator::call<kWasmF32>};
...@@ -652,6 +705,7 @@ void WasmGenerator::Generate<kWasmF64>(DataRange& data) { ...@@ -652,6 +705,7 @@ void WasmGenerator::Generate<kWasmF64>(DataRange& data) {
&WasmGenerator::get_local<kWasmF64>, &WasmGenerator::get_local<kWasmF64>,
&WasmGenerator::tee_local<kWasmF64>, &WasmGenerator::tee_local<kWasmF64>,
&WasmGenerator::get_global<kWasmF64>,
&WasmGenerator::call<kWasmF64>}; &WasmGenerator::call<kWasmF64>};
...@@ -715,6 +769,22 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer { ...@@ -715,6 +769,22 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer {
function_signatures.push_back(GenerateSig(zone, range)); 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) { for (int i = 0; i < num_functions; ++i) {
DataRange function_range = DataRange function_range =
i == num_functions - 1 ? std::move(range) : range.split(); i == num_functions - 1 ? std::move(range) : range.split();
...@@ -722,7 +792,8 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer { ...@@ -722,7 +792,8 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer {
FunctionSig* sig = function_signatures[i]; FunctionSig* sig = function_signatures[i];
WasmFunctionBuilder* f = builder.AddFunction(sig); 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 = ValueType return_type =
sig->return_count() == 0 ? kWasmStmt : sig->GetReturn(0); sig->return_count() == 0 ? kWasmStmt : sig->GetReturn(0);
gen.Generate(return_type, function_range); gen.Generate(return_type, function_range);
......
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