[wasm][fuzzer] Complex init. expressions in JS testcase
We enable struct.new and array.init initializer expressions in the JS testcase generated by --wasm-fuzzer-gen-test. We needed to make some changes in the WasmInitExpr class, and to implement a new interface for the WasmFullDecoder, which constructs a WasmInitExpr. Changes: - Make WasmInitExpr a ZoneObject. Use a pointer for its operands_ field. This is needed so WasmInitExpr is trivially copiable, and thus usable as a Value type in WasmFullDecoder. - Implement a WasmFullDecoder interface in wasm-fuzzer-common that constructs a WasmInitExpr. Use it to decode initializers in the module generated by the fuzzer. - Change AppendInitExpr to take a WasmInitExpr as argument. - Fix an issue with printing of struct definitions. - Change initializer expression used for structs to struct.new_with_rtt. This is consistent with the currently used structural types. Bug: v8:11954 Change-Id: I65a87cc98701a54f32500be192b3b6eef2ff6c8c Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3257712 Reviewed-by: Andreas Haas <ahaas@chromium.org> Reviewed-by: Thibaud Michaud <thibaudm@chromium.org> Commit-Queue: Manos Koukoutos <manoskouk@chromium.org> Cr-Commit-Position: refs/heads/main@{#77730}
This commit is contained in:
parent
d65a8d6cf5
commit
74d9a7642d
@ -239,7 +239,7 @@ void AsmJsParser::DeclareGlobal(VarInfo* info, bool mutable_variable,
|
||||
WasmInitExpr init) {
|
||||
info->kind = VarKind::kGlobal;
|
||||
info->type = type;
|
||||
info->index = module_builder_->AddGlobal(vtype, true, std::move(init));
|
||||
info->index = module_builder_->AddGlobal(vtype, true, init);
|
||||
info->mutable_variable = mutable_variable;
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,10 @@ class InitExprInterface {
|
||||
#define EMPTY_INTERFACE_FUNCTION(name, ...) \
|
||||
V8_INLINE void name(FullDecoder* decoder, ##__VA_ARGS__) {}
|
||||
INTERFACE_META_FUNCTIONS(EMPTY_INTERFACE_FUNCTION)
|
||||
INTERFACE_NON_CONSTANT_FUNCTIONS(EMPTY_INTERFACE_FUNCTION)
|
||||
#undef EMPTY_INTERFACE_FUNCTION
|
||||
#define UNREACHABLE_INTERFACE_FUNCTION(name, ...) \
|
||||
V8_INLINE void name(FullDecoder* decoder, ##__VA_ARGS__) { UNREACHABLE(); }
|
||||
INTERFACE_NON_CONSTANT_FUNCTIONS(UNREACHABLE_INTERFACE_FUNCTION)
|
||||
#undef EMPTY_INTERFACE_FUNCTION
|
||||
|
||||
#define DECLARE_INTERFACE_FUNCTION(name, ...) \
|
||||
|
@ -49,7 +49,7 @@ ValueType WasmInitExpr::type(const WasmModule* module,
|
||||
return ValueType::Rtt(immediate().heap_type, 0);
|
||||
case kRttSub:
|
||||
case kRttFreshSub: {
|
||||
ValueType operand_type = operands()[0].type(module, enabled_features);
|
||||
ValueType operand_type = (*operands())[0].type(module, enabled_features);
|
||||
if (!operand_type.is_rtt()) return kWasmBottom;
|
||||
if (operand_type.has_depth()) {
|
||||
return ValueType::Rtt(immediate().heap_type, operand_type.depth() + 1);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "src/wasm/value-type.h"
|
||||
#include "src/zone/zone-containers.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -21,7 +22,7 @@ struct WasmModule;
|
||||
class WasmFeatures;
|
||||
|
||||
// Representation of an initializer expression.
|
||||
class WasmInitExpr {
|
||||
class WasmInitExpr : public ZoneObject {
|
||||
public:
|
||||
enum Operator {
|
||||
kNone,
|
||||
@ -54,25 +55,26 @@ class WasmInitExpr {
|
||||
HeapType::Representation heap_type;
|
||||
};
|
||||
|
||||
WasmInitExpr() : kind_(kNone) { immediate_.i32_const = 0; }
|
||||
explicit WasmInitExpr(int32_t v) : kind_(kI32Const) {
|
||||
WasmInitExpr() : kind_(kNone), operands_(nullptr) {
|
||||
immediate_.i32_const = 0;
|
||||
}
|
||||
explicit WasmInitExpr(int32_t v) : kind_(kI32Const), operands_(nullptr) {
|
||||
immediate_.i32_const = v;
|
||||
}
|
||||
explicit WasmInitExpr(int64_t v) : kind_(kI64Const) {
|
||||
explicit WasmInitExpr(int64_t v) : kind_(kI64Const), operands_(nullptr) {
|
||||
immediate_.i64_const = v;
|
||||
}
|
||||
explicit WasmInitExpr(float v) : kind_(kF32Const) {
|
||||
explicit WasmInitExpr(float v) : kind_(kF32Const), operands_(nullptr) {
|
||||
immediate_.f32_const = v;
|
||||
}
|
||||
explicit WasmInitExpr(double v) : kind_(kF64Const) {
|
||||
explicit WasmInitExpr(double v) : kind_(kF64Const), operands_(nullptr) {
|
||||
immediate_.f64_const = v;
|
||||
}
|
||||
explicit WasmInitExpr(uint8_t v[kSimd128Size]) : kind_(kS128Const) {
|
||||
explicit WasmInitExpr(uint8_t v[kSimd128Size])
|
||||
: kind_(kS128Const), operands_(nullptr) {
|
||||
memcpy(immediate_.s128_const.data(), v, kSimd128Size);
|
||||
}
|
||||
|
||||
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(WasmInitExpr);
|
||||
|
||||
static WasmInitExpr GlobalGet(uint32_t index) {
|
||||
WasmInitExpr expr;
|
||||
expr.kind_ = kGlobalGet;
|
||||
@ -95,29 +97,25 @@ class WasmInitExpr {
|
||||
}
|
||||
|
||||
static WasmInitExpr StructNewWithRtt(uint32_t index,
|
||||
std::vector<WasmInitExpr> elements) {
|
||||
WasmInitExpr expr;
|
||||
expr.kind_ = kStructNewWithRtt;
|
||||
ZoneVector<WasmInitExpr>* elements) {
|
||||
WasmInitExpr expr(kStructNewWithRtt, elements);
|
||||
expr.immediate_.index = index;
|
||||
expr.operands_ = std::move(elements);
|
||||
return expr;
|
||||
}
|
||||
|
||||
static WasmInitExpr StructNew(uint32_t index,
|
||||
std::vector<WasmInitExpr> elements) {
|
||||
WasmInitExpr expr;
|
||||
expr.kind_ = kStructNew;
|
||||
ZoneVector<WasmInitExpr>* elements) {
|
||||
WasmInitExpr expr(kStructNew, elements);
|
||||
expr.immediate_.index = index;
|
||||
expr.operands_ = std::move(elements);
|
||||
return expr;
|
||||
}
|
||||
|
||||
static WasmInitExpr StructNewDefaultWithRtt(uint32_t index,
|
||||
static WasmInitExpr StructNewDefaultWithRtt(Zone* zone, uint32_t index,
|
||||
WasmInitExpr rtt) {
|
||||
WasmInitExpr expr;
|
||||
expr.kind_ = kStructNewDefaultWithRtt;
|
||||
WasmInitExpr expr(kStructNewDefaultWithRtt,
|
||||
zone->New<ZoneVector<WasmInitExpr>>(
|
||||
std::initializer_list<WasmInitExpr>{rtt}, zone));
|
||||
expr.immediate_.index = index;
|
||||
expr.operands_.push_back(std::move(rtt));
|
||||
return expr;
|
||||
}
|
||||
|
||||
@ -129,20 +127,16 @@ class WasmInitExpr {
|
||||
}
|
||||
|
||||
static WasmInitExpr ArrayInit(uint32_t index,
|
||||
std::vector<WasmInitExpr> elements) {
|
||||
WasmInitExpr expr;
|
||||
expr.kind_ = kArrayInit;
|
||||
ZoneVector<WasmInitExpr>* elements) {
|
||||
WasmInitExpr expr(kArrayInit, elements);
|
||||
expr.immediate_.index = index;
|
||||
expr.operands_ = std::move(elements);
|
||||
return expr;
|
||||
}
|
||||
|
||||
static WasmInitExpr ArrayInitStatic(uint32_t index,
|
||||
std::vector<WasmInitExpr> elements) {
|
||||
WasmInitExpr expr;
|
||||
expr.kind_ = kArrayInitStatic;
|
||||
ZoneVector<WasmInitExpr>* elements) {
|
||||
WasmInitExpr expr(kArrayInitStatic, elements);
|
||||
expr.immediate_.index = index;
|
||||
expr.operands_ = std::move(elements);
|
||||
return expr;
|
||||
}
|
||||
|
||||
@ -153,25 +147,28 @@ class WasmInitExpr {
|
||||
return expr;
|
||||
}
|
||||
|
||||
static WasmInitExpr RttSub(uint32_t index, WasmInitExpr supertype) {
|
||||
WasmInitExpr expr;
|
||||
expr.kind_ = kRttSub;
|
||||
static WasmInitExpr RttSub(Zone* zone, uint32_t index,
|
||||
WasmInitExpr supertype) {
|
||||
WasmInitExpr expr(
|
||||
kRttSub, zone->New<ZoneVector<WasmInitExpr>>(
|
||||
std::initializer_list<WasmInitExpr>{supertype}, zone));
|
||||
expr.immediate_.index = index;
|
||||
expr.operands_.push_back(std::move(supertype));
|
||||
return expr;
|
||||
}
|
||||
|
||||
static WasmInitExpr RttFreshSub(uint32_t index, WasmInitExpr supertype) {
|
||||
WasmInitExpr expr;
|
||||
expr.kind_ = kRttFreshSub;
|
||||
static WasmInitExpr RttFreshSub(Zone* zone, uint32_t index,
|
||||
WasmInitExpr supertype) {
|
||||
WasmInitExpr expr(
|
||||
kRttFreshSub,
|
||||
zone->New<ZoneVector<WasmInitExpr>>(
|
||||
std::initializer_list<WasmInitExpr>{supertype}, zone));
|
||||
expr.immediate_.index = index;
|
||||
expr.operands_.push_back(std::move(supertype));
|
||||
return expr;
|
||||
}
|
||||
|
||||
Immediate immediate() const { return immediate_; }
|
||||
Operator kind() const { return kind_; }
|
||||
const std::vector<WasmInitExpr>& operands() const { return operands_; }
|
||||
const ZoneVector<WasmInitExpr>* operands() const { return operands_; }
|
||||
|
||||
bool operator==(const WasmInitExpr& other) const {
|
||||
if (kind() != other.kind()) return false;
|
||||
@ -199,16 +196,16 @@ class WasmInitExpr {
|
||||
case kStructNewDefaultWithRtt:
|
||||
case kStructNewDefault:
|
||||
if (immediate().index != other.immediate().index) return false;
|
||||
DCHECK_EQ(operands().size(), other.operands().size());
|
||||
for (uint32_t i = 0; i < operands().size(); i++) {
|
||||
DCHECK_EQ(operands()->size(), other.operands()->size());
|
||||
for (uint32_t i = 0; i < operands()->size(); i++) {
|
||||
if (operands()[i] != other.operands()[i]) return false;
|
||||
}
|
||||
return true;
|
||||
case kArrayInit:
|
||||
case kArrayInitStatic:
|
||||
if (immediate().index != other.immediate().index) return false;
|
||||
if (operands().size() != other.operands().size()) return false;
|
||||
for (uint32_t i = 0; i < operands().size(); i++) {
|
||||
if (operands()->size() != other.operands()->size()) return false;
|
||||
for (uint32_t i = 0; i < operands()->size(); i++) {
|
||||
if (operands()[i] != other.operands()[i]) return false;
|
||||
}
|
||||
return true;
|
||||
@ -227,11 +224,15 @@ class WasmInitExpr {
|
||||
const WasmFeatures& enabled_features) const;
|
||||
|
||||
private:
|
||||
WasmInitExpr(Operator kind, const ZoneVector<WasmInitExpr>* operands)
|
||||
: kind_(kind), operands_(operands) {}
|
||||
Immediate immediate_;
|
||||
Operator kind_;
|
||||
std::vector<WasmInitExpr> operands_;
|
||||
const ZoneVector<WasmInitExpr>* operands_;
|
||||
};
|
||||
|
||||
ASSERT_TRIVIALLY_COPYABLE(WasmInitExpr);
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -355,7 +355,7 @@ uint32_t WasmModuleBuilder::AddTable(ValueType type, uint32_t min_size,
|
||||
|
||||
uint32_t WasmModuleBuilder::AddTable(ValueType type, uint32_t min_size,
|
||||
uint32_t max_size, WasmInitExpr init) {
|
||||
tables_.push_back({type, min_size, max_size, true, std::move(init)});
|
||||
tables_.push_back({type, min_size, max_size, true, init});
|
||||
return static_cast<uint32_t>(tables_.size() - 1);
|
||||
}
|
||||
|
||||
@ -403,7 +403,7 @@ void WasmModuleBuilder::AddExport(base::Vector<const char> name,
|
||||
uint32_t WasmModuleBuilder::AddExportedGlobal(ValueType type, bool mutability,
|
||||
WasmInitExpr init,
|
||||
base::Vector<const char> name) {
|
||||
uint32_t index = AddGlobal(type, mutability, std::move(init));
|
||||
uint32_t index = AddGlobal(type, mutability, init);
|
||||
AddExport(name, kExternalGlobal, index);
|
||||
return index;
|
||||
}
|
||||
@ -421,7 +421,7 @@ void WasmModuleBuilder::ExportImportedFunction(base::Vector<const char> name,
|
||||
|
||||
uint32_t WasmModuleBuilder::AddGlobal(ValueType type, bool mutability,
|
||||
WasmInitExpr init) {
|
||||
globals_.push_back({type, mutability, std::move(init)});
|
||||
globals_.push_back({type, mutability, init});
|
||||
return static_cast<uint32_t>(globals_.size() - 1);
|
||||
}
|
||||
|
||||
@ -523,7 +523,7 @@ void WriteInitializerExpressionWithEnd(ZoneBuffer* buffer,
|
||||
STATIC_ASSERT((kExprStructNewWithRtt >> 8) == kGCPrefix);
|
||||
STATIC_ASSERT((kExprStructNewDefault >> 8) == kGCPrefix);
|
||||
STATIC_ASSERT((kExprStructNewDefaultWithRtt >> 8) == kGCPrefix);
|
||||
for (const WasmInitExpr& operand : init.operands()) {
|
||||
for (const WasmInitExpr& operand : *init.operands()) {
|
||||
WriteInitializerExpressionWithEnd(buffer, operand, kWasmBottom);
|
||||
}
|
||||
buffer->write_u8(kGCPrefix);
|
||||
@ -551,7 +551,7 @@ void WriteInitializerExpressionWithEnd(ZoneBuffer* buffer,
|
||||
case WasmInitExpr::kArrayInitStatic:
|
||||
STATIC_ASSERT((kExprArrayInit >> 8) == kGCPrefix);
|
||||
STATIC_ASSERT((kExprArrayInitStatic >> 8) == kGCPrefix);
|
||||
for (const WasmInitExpr& operand : init.operands()) {
|
||||
for (const WasmInitExpr& operand : *init.operands()) {
|
||||
WriteInitializerExpressionWithEnd(buffer, operand, kWasmBottom);
|
||||
}
|
||||
buffer->write_u8(kGCPrefix);
|
||||
@ -559,7 +559,7 @@ void WriteInitializerExpressionWithEnd(ZoneBuffer* buffer,
|
||||
init.kind() == WasmInitExpr::kArrayInit ? kExprArrayInit
|
||||
: kExprArrayInitStatic));
|
||||
buffer->write_u32v(init.immediate().index);
|
||||
buffer->write_u32v(static_cast<uint32_t>(init.operands().size() - 1));
|
||||
buffer->write_u32v(static_cast<uint32_t>(init.operands()->size() - 1));
|
||||
break;
|
||||
case WasmInitExpr::kRttCanon:
|
||||
STATIC_ASSERT((kExprRttCanon >> 8) == kGCPrefix);
|
||||
@ -570,7 +570,7 @@ void WriteInitializerExpressionWithEnd(ZoneBuffer* buffer,
|
||||
case WasmInitExpr::kRttSub:
|
||||
case WasmInitExpr::kRttFreshSub:
|
||||
// The operand to rtt.sub must be emitted first.
|
||||
WriteInitializerExpressionWithEnd(buffer, init.operands()[0],
|
||||
WriteInitializerExpressionWithEnd(buffer, (*init.operands())[0],
|
||||
kWasmBottom);
|
||||
STATIC_ASSERT((kExprRttSub >> 8) == kGCPrefix);
|
||||
STATIC_ASSERT((kExprRttFreshSub >> 8) == kGCPrefix);
|
||||
|
@ -273,7 +273,7 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
|
||||
WasmInitExpr offset)
|
||||
: type(type),
|
||||
table_index(table_index),
|
||||
offset(std::move(offset)),
|
||||
offset(offset),
|
||||
entries(zone),
|
||||
status(kStatusActive) {
|
||||
DCHECK(IsValidOffsetKind(offset.kind()));
|
||||
|
@ -462,7 +462,8 @@ int GetNearestWasmFunction(const WasmModule* module, uint32_t byte_offset);
|
||||
// Returns 0 if the type has no explicit supertype.
|
||||
// The result is capped to {kV8MaxRttSubtypingDepth + 1}.
|
||||
// Invalid cyclic hierarchies will return -1.
|
||||
int GetSubtypingDepth(const WasmModule* module, uint32_t type_index);
|
||||
V8_EXPORT_PRIVATE int GetSubtypingDepth(const WasmModule* module,
|
||||
uint32_t type_index);
|
||||
|
||||
// Interface to the storage (wire bytes) of a wasm module.
|
||||
// It is illegal for anyone receiving a ModuleWireBytes to store pointers based
|
||||
|
@ -50,7 +50,7 @@ class WasmGCTester {
|
||||
}
|
||||
|
||||
byte AddGlobal(ValueType type, bool mutability, WasmInitExpr init) {
|
||||
return builder_.AddGlobal(type, mutability, std::move(init));
|
||||
return builder_.AddGlobal(type, mutability, init);
|
||||
}
|
||||
|
||||
byte DefineFunction(FunctionSig* sig, std::initializer_list<ValueType> locals,
|
||||
@ -1425,7 +1425,8 @@ WASM_COMPILED_EXEC_TEST(RttFreshSub) {
|
||||
|
||||
const byte kRtt = tester.AddGlobal(
|
||||
ValueType::Rtt(kType, 1), false,
|
||||
WasmInitExpr::RttFreshSub(type_repr, WasmInitExpr::RttCanon(type_repr)));
|
||||
WasmInitExpr::RttFreshSub(tester.zone(), type_repr,
|
||||
WasmInitExpr::RttCanon(type_repr)));
|
||||
|
||||
// A struct allocated with a fresh RTT does not match other fresh RTTs
|
||||
// created for the same type.
|
||||
@ -2082,7 +2083,8 @@ WASM_COMPILED_EXEC_TEST(CastsBenchmark) {
|
||||
WasmInitExpr::RttCanon(static_cast<HeapType::Representation>(SuperType)));
|
||||
const byte RttSub = tester.AddGlobal(
|
||||
ValueType::Rtt(SubType, 1), false,
|
||||
WasmInitExpr::RttSub(static_cast<HeapType::Representation>(SubType),
|
||||
WasmInitExpr::RttSub(tester.zone(),
|
||||
static_cast<HeapType::Representation>(SubType),
|
||||
WasmInitExpr::GlobalGet(RttSuper)));
|
||||
const byte RttList = tester.AddGlobal(
|
||||
ValueType::Rtt(ListType, 0), false,
|
||||
|
@ -2297,7 +2297,8 @@ FunctionSig* GenerateSig(Zone* zone, DataRange* data, SigKind sig_kind,
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
WasmInitExpr GenerateInitExpr(WasmModuleBuilder* builder, ValueType type,
|
||||
WasmInitExpr GenerateInitExpr(Zone* zone, WasmModuleBuilder* builder,
|
||||
ValueType type,
|
||||
uint32_t num_struct_and_array_types) {
|
||||
switch (type.kind()) {
|
||||
case kOptRef:
|
||||
@ -2329,26 +2330,29 @@ WasmInitExpr GenerateInitExpr(WasmModuleBuilder* builder, ValueType type,
|
||||
// We materialize all these types with a struct because they are all its
|
||||
// supertypes.
|
||||
DCHECK(builder->IsStructType(index));
|
||||
std::vector<WasmInitExpr> elements;
|
||||
ZoneVector<WasmInitExpr>* elements =
|
||||
zone->New<ZoneVector<WasmInitExpr>>(zone);
|
||||
int field_count = builder->GetStructType(index)->field_count();
|
||||
for (int field_index = 0; field_index < field_count; field_index++) {
|
||||
elements.push_back(GenerateInitExpr(
|
||||
builder, builder->GetStructType(index)->field(field_index),
|
||||
elements->push_back(GenerateInitExpr(
|
||||
zone, builder, builder->GetStructType(index)->field(field_index),
|
||||
num_struct_and_array_types));
|
||||
}
|
||||
return WasmInitExpr::StructNew(index, std::move(elements));
|
||||
elements->push_back(WasmInitExpr::RttCanon(index));
|
||||
return WasmInitExpr::StructNewWithRtt(index, elements);
|
||||
}
|
||||
DCHECK(type.has_index());
|
||||
if (representation == HeapType::kFunc) {
|
||||
return WasmInitExpr::RefFuncConst(index);
|
||||
}
|
||||
if (builder->IsArrayType(index)) {
|
||||
std::vector<WasmInitExpr> elements;
|
||||
elements.push_back(GenerateInitExpr(
|
||||
builder, builder->GetArrayType(index)->element_type(),
|
||||
ZoneVector<WasmInitExpr>* elements =
|
||||
zone->New<ZoneVector<WasmInitExpr>>(zone);
|
||||
elements->push_back(GenerateInitExpr(
|
||||
zone, builder, builder->GetArrayType(index)->element_type(),
|
||||
num_struct_and_array_types));
|
||||
elements.push_back(WasmInitExpr::RttCanon(index));
|
||||
return WasmInitExpr::ArrayInit(index, std::move(elements));
|
||||
elements->push_back(WasmInitExpr::RttCanon(index));
|
||||
return WasmInitExpr::ArrayInit(index, elements);
|
||||
}
|
||||
if (builder->IsSignature(index)) {
|
||||
// Transform from signature index to function specific index.
|
||||
@ -2460,7 +2464,7 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer {
|
||||
|
||||
builder.AddGlobal(
|
||||
type, mutability,
|
||||
GenerateInitExpr(&builder, type,
|
||||
GenerateInitExpr(zone, &builder, type,
|
||||
static_cast<uint32_t>(num_structs + num_arrays)));
|
||||
globals.push_back(type);
|
||||
if (mutability) mutable_globals.push_back(static_cast<uint8_t>(i));
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "src/wasm/wasm-module-builder.h"
|
||||
#include "src/wasm/wasm-module.h"
|
||||
#include "src/wasm/wasm-objects-inl.h"
|
||||
#include "src/wasm/wasm-opcodes-inl.h"
|
||||
#include "src/zone/accounting-allocator.h"
|
||||
#include "src/zone/zone.h"
|
||||
#include "test/common/wasm/flag-utils.h"
|
||||
@ -313,68 +314,234 @@ std::ostream& operator<<(std::ostream& os, WasmElemSegment::Entry entry) {
|
||||
return os << ")";
|
||||
}
|
||||
|
||||
// An interface for WasmFullDecoder used to decode initializer expressions. As
|
||||
// opposed to the one in src/wasm/, this emits {WasmInitExpr} as opposed to a
|
||||
// {WasmValue}.
|
||||
class InitExprInterface {
|
||||
public:
|
||||
static constexpr Decoder::ValidateFlag validate = Decoder::kFullValidation;
|
||||
static constexpr DecodingMode decoding_mode = kInitExpression;
|
||||
|
||||
struct Value : public ValueBase<validate> {
|
||||
WasmInitExpr init_expr;
|
||||
|
||||
template <typename... Args>
|
||||
explicit Value(Args&&... args) V8_NOEXCEPT
|
||||
: ValueBase(std::forward<Args>(args)...) {}
|
||||
};
|
||||
|
||||
using Control = ControlBase<Value, validate>;
|
||||
using FullDecoder =
|
||||
WasmFullDecoder<validate, InitExprInterface, decoding_mode>;
|
||||
|
||||
explicit InitExprInterface(Zone* zone) : zone_(zone) {}
|
||||
|
||||
#define EMPTY_INTERFACE_FUNCTION(name, ...) \
|
||||
V8_INLINE void name(FullDecoder* decoder, ##__VA_ARGS__) {}
|
||||
INTERFACE_META_FUNCTIONS(EMPTY_INTERFACE_FUNCTION)
|
||||
#undef EMPTY_INTERFACE_FUNCTION
|
||||
#define UNREACHABLE_INTERFACE_FUNCTION(name, ...) \
|
||||
V8_INLINE void name(FullDecoder* decoder, ##__VA_ARGS__) { UNREACHABLE(); }
|
||||
INTERFACE_NON_CONSTANT_FUNCTIONS(UNREACHABLE_INTERFACE_FUNCTION)
|
||||
#undef UNREACHABLE_INTERFACE_FUNCTION
|
||||
|
||||
void I32Const(FullDecoder* decoder, Value* result, int32_t value) {
|
||||
result->init_expr = WasmInitExpr(value);
|
||||
}
|
||||
|
||||
void I64Const(FullDecoder* decoder, Value* result, int64_t value) {
|
||||
result->init_expr = WasmInitExpr(value);
|
||||
}
|
||||
|
||||
void F32Const(FullDecoder* decoder, Value* result, float value) {
|
||||
result->init_expr = WasmInitExpr(value);
|
||||
}
|
||||
|
||||
void F64Const(FullDecoder* decoder, Value* result, double value) {
|
||||
result->init_expr = WasmInitExpr(value);
|
||||
}
|
||||
|
||||
void S128Const(FullDecoder* decoder, Simd128Immediate<validate>& imm,
|
||||
Value* result) {
|
||||
result->init_expr = WasmInitExpr(imm.value);
|
||||
}
|
||||
|
||||
void RefNull(FullDecoder* decoder, ValueType type, Value* result) {
|
||||
result->init_expr = WasmInitExpr::RefNullConst(type.heap_representation());
|
||||
}
|
||||
|
||||
void RefFunc(FullDecoder* decoder, uint32_t function_index, Value* result) {
|
||||
result->init_expr = WasmInitExpr::RefFuncConst(function_index);
|
||||
}
|
||||
|
||||
void GlobalGet(FullDecoder* decoder, Value* result,
|
||||
const GlobalIndexImmediate<validate>& imm) {
|
||||
result->init_expr = WasmInitExpr::GlobalGet(imm.index);
|
||||
}
|
||||
|
||||
void StructNewWithRtt(FullDecoder* decoder,
|
||||
const StructIndexImmediate<validate>& imm,
|
||||
const Value& rtt, const Value args[], Value* result) {
|
||||
ZoneVector<WasmInitExpr>* elements =
|
||||
zone_->New<ZoneVector<WasmInitExpr>>(zone_);
|
||||
for (size_t i = 0; i < imm.struct_type->field_count(); i++) {
|
||||
elements->push_back(args[i].init_expr);
|
||||
}
|
||||
bool nominal = decoder->module_->has_supertype(imm.index);
|
||||
|
||||
if (!nominal) elements->push_back(rtt.init_expr);
|
||||
|
||||
result->init_expr =
|
||||
nominal ? WasmInitExpr::StructNew(imm.index, elements)
|
||||
: WasmInitExpr::StructNewWithRtt(imm.index, elements);
|
||||
}
|
||||
|
||||
void StructNewDefault(FullDecoder* decoder,
|
||||
const StructIndexImmediate<validate>& imm,
|
||||
const Value& rtt, Value* result) {
|
||||
bool nominal = decoder->module_->has_supertype(imm.index);
|
||||
result->init_expr = nominal ? WasmInitExpr::StructNewDefault(imm.index)
|
||||
: WasmInitExpr::StructNewDefaultWithRtt(
|
||||
zone_, imm.index, rtt.init_expr);
|
||||
}
|
||||
|
||||
void ArrayInit(FullDecoder* decoder, const ArrayIndexImmediate<validate>& imm,
|
||||
const base::Vector<Value>& elements, const Value& rtt,
|
||||
Value* result) {
|
||||
ZoneVector<WasmInitExpr>* args =
|
||||
zone_->New<ZoneVector<WasmInitExpr>>(zone_);
|
||||
for (Value expr : elements) args->push_back(expr.init_expr);
|
||||
bool nominal = decoder->module_->has_supertype(imm.index);
|
||||
|
||||
if (!nominal) args->push_back(rtt.init_expr);
|
||||
result->init_expr = nominal ? WasmInitExpr::ArrayInitStatic(imm.index, args)
|
||||
: WasmInitExpr::ArrayInit(imm.index, args);
|
||||
}
|
||||
|
||||
void RttCanon(FullDecoder* decoder, uint32_t type_index, Value* result) {
|
||||
result->init_expr = WasmInitExpr::RttCanon(type_index);
|
||||
}
|
||||
|
||||
void RttSub(FullDecoder* decoder, uint32_t type_index, const Value& parent,
|
||||
Value* result, WasmRttSubMode mode) {
|
||||
result->init_expr =
|
||||
WasmInitExpr::RttSub(zone_, type_index, parent.init_expr);
|
||||
}
|
||||
|
||||
void DoReturn(FullDecoder* decoder, uint32_t /*drop_values*/) {
|
||||
// End decoding on "end".
|
||||
decoder->set_end(decoder->pc() + 1);
|
||||
result_ = decoder->stack_value(1)->init_expr;
|
||||
}
|
||||
|
||||
WasmInitExpr result() { return result_; }
|
||||
|
||||
private:
|
||||
WasmInitExpr result_;
|
||||
Zone* zone_;
|
||||
};
|
||||
|
||||
// Appends an initializer expression encoded in {wire_bytes}, in the offset
|
||||
// contained in {expr}.
|
||||
void AppendInitExpr(std::ostream& os, ModuleWireBytes wire_bytes,
|
||||
WireBytesRef expr) {
|
||||
Decoder decoder(wire_bytes.module_bytes());
|
||||
const byte* pc = wire_bytes.module_bytes().begin() + expr.offset();
|
||||
uint32_t length;
|
||||
void AppendInitExpr(std::ostream& os, const WasmInitExpr& expr) {
|
||||
os << "WasmInitExpr.";
|
||||
switch (static_cast<WasmOpcode>(pc[0])) {
|
||||
case kExprGlobalGet:
|
||||
os << "GlobalGet("
|
||||
<< decoder.read_u32v<Decoder::kNoValidation>(pc + 1, &length);
|
||||
bool append_operands = false;
|
||||
switch (expr.kind()) {
|
||||
case WasmInitExpr::kNone:
|
||||
UNREACHABLE();
|
||||
case WasmInitExpr::kGlobalGet:
|
||||
os << "GlobalGet(" << expr.immediate().index;
|
||||
break;
|
||||
case kExprI32Const:
|
||||
os << "I32Const("
|
||||
<< decoder.read_i32v<Decoder::kNoValidation>(pc + 1, &length);
|
||||
case WasmInitExpr::kI32Const:
|
||||
os << "I32Const(" << expr.immediate().i32_const;
|
||||
break;
|
||||
case kExprI64Const:
|
||||
os << "I64Const("
|
||||
<< decoder.read_i64v<Decoder::kNoValidation>(pc + 1, &length);
|
||||
case WasmInitExpr::kI64Const:
|
||||
os << "I64Const(" << expr.immediate().i64_const;
|
||||
break;
|
||||
case kExprF32Const: {
|
||||
uint32_t result = decoder.read_u32<Decoder::kNoValidation>(pc + 1);
|
||||
os << "F32Const(" << bit_cast<float>(result);
|
||||
case WasmInitExpr::kF32Const:
|
||||
os << "F32Const(" << expr.immediate().f32_const;
|
||||
break;
|
||||
}
|
||||
case kExprF64Const: {
|
||||
uint64_t result = decoder.read_u64<Decoder::kNoValidation>(pc + 1);
|
||||
os << "F64Const(" << bit_cast<double>(result);
|
||||
case WasmInitExpr::kF64Const:
|
||||
os << "F64Const(" << expr.immediate().f64_const;
|
||||
break;
|
||||
}
|
||||
case kSimdPrefix: {
|
||||
DCHECK_LE(2 + kSimd128Size, expr.length());
|
||||
DCHECK_EQ(static_cast<WasmOpcode>(pc[1]), kExprS128Const & 0xff);
|
||||
case WasmInitExpr::kS128Const:
|
||||
os << "S128Const([";
|
||||
for (int i = 0; i < kSimd128Size; i++) {
|
||||
os << int(decoder.read_u8<Decoder::kNoValidation>(pc + 2 + i));
|
||||
if (i + 1 < kSimd128Size) os << ", ";
|
||||
os << static_cast<int>(expr.immediate().s128_const[i]);
|
||||
if (i < kSimd128Size - 1) os << ", ";
|
||||
}
|
||||
os << "]";
|
||||
break;
|
||||
}
|
||||
case kExprRefFunc:
|
||||
os << "RefFunc("
|
||||
<< decoder.read_u32v<Decoder::kNoValidation>(pc + 1, &length);
|
||||
case WasmInitExpr::kRefNullConst:
|
||||
os << "RefNull("
|
||||
<< HeapTypeToConstantName(HeapType(expr.immediate().heap_type));
|
||||
break;
|
||||
case kExprRefNull: {
|
||||
HeapType heap_type =
|
||||
value_type_reader::read_heap_type<Decoder::kNoValidation>(
|
||||
&decoder, pc + 1, &length, nullptr, WasmFeatures::All());
|
||||
os << "RefNull(" << HeapTypeToConstantName(heap_type);
|
||||
case WasmInitExpr::kRefFuncConst:
|
||||
os << "RefFunc(" << expr.immediate().index;
|
||||
break;
|
||||
case WasmInitExpr::kStructNewWithRtt:
|
||||
os << "StructNewWithRtt(" << expr.immediate().index;
|
||||
append_operands = true;
|
||||
break;
|
||||
case WasmInitExpr::kStructNew:
|
||||
os << "StructNew(" << expr.immediate().index;
|
||||
append_operands = true;
|
||||
break;
|
||||
case WasmInitExpr::kStructNewDefaultWithRtt:
|
||||
os << "StructNewDefaultWithRtt(" << expr.immediate().index << ", ";
|
||||
AppendInitExpr(os, (*expr.operands())[0]);
|
||||
break;
|
||||
case WasmInitExpr::kStructNewDefault:
|
||||
os << "StructNewDefault(" << expr.immediate().index;
|
||||
break;
|
||||
case WasmInitExpr::kArrayInit:
|
||||
os << "ArrayInit(" << expr.immediate().index;
|
||||
append_operands = true;
|
||||
break;
|
||||
case WasmInitExpr::kArrayInitStatic:
|
||||
os << "ArrayInitStatic(" << expr.immediate().index;
|
||||
append_operands = true;
|
||||
break;
|
||||
case WasmInitExpr::kRttCanon:
|
||||
os << "RttCanon(" << expr.immediate().index;
|
||||
break;
|
||||
case WasmInitExpr::kRttSub:
|
||||
os << "RttSub(" << expr.immediate().index << ", ";
|
||||
AppendInitExpr(os, (*expr.operands())[0]);
|
||||
break;
|
||||
case WasmInitExpr::kRttFreshSub:
|
||||
os << "RttFreshSub(" << expr.immediate().index << ", ";
|
||||
AppendInitExpr(os, (*expr.operands())[0]);
|
||||
break;
|
||||
}
|
||||
case kExprStructNew:
|
||||
UNIMPLEMENTED();
|
||||
case kExprArrayInit:
|
||||
UNIMPLEMENTED();
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
if (append_operands) {
|
||||
os << ", [";
|
||||
for (size_t i = 0; i < expr.operands()->size(); i++) {
|
||||
AppendInitExpr(os, (*expr.operands())[i]);
|
||||
if (i < expr.operands()->size() - 1) os << ", ";
|
||||
}
|
||||
os << "]";
|
||||
}
|
||||
|
||||
os << ")";
|
||||
}
|
||||
|
||||
void DecodeAndAppendInitExpr(StdoutStream& os, Zone* zone,
|
||||
const WasmModule* module,
|
||||
ModuleWireBytes module_bytes, WireBytesRef init,
|
||||
ValueType expected) {
|
||||
FunctionBody body(FunctionSig::Build(zone, {expected}, {}), init.offset(),
|
||||
module_bytes.start() + init.offset(),
|
||||
module_bytes.start() + init.end_offset());
|
||||
WasmFeatures detected;
|
||||
WasmFullDecoder<Decoder::kFullValidation, InitExprInterface, kInitExpression>
|
||||
decoder(zone, module, WasmFeatures::All(), &detected, body, zone);
|
||||
|
||||
decoder.DecodeFunctionBody();
|
||||
|
||||
AppendInitExpr(os, decoder.interface().result());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void GenerateTestCase(Isolate* isolate, ModuleWireBytes wire_bytes,
|
||||
@ -390,6 +557,9 @@ void GenerateTestCase(Isolate* isolate, ModuleWireBytes wire_bytes,
|
||||
WasmModule* module = module_res.value().get();
|
||||
CHECK_NOT_NULL(module);
|
||||
|
||||
AccountingAllocator allocator;
|
||||
Zone zone(&allocator, "init. expression zone");
|
||||
|
||||
StdoutStream os;
|
||||
|
||||
tzset();
|
||||
@ -428,10 +598,11 @@ void GenerateTestCase(Isolate* isolate, ModuleWireBytes wire_bytes,
|
||||
os << ");\n";
|
||||
}
|
||||
|
||||
for (WasmGlobal& glob : module->globals) {
|
||||
os << "builder.addGlobal(" << ValueTypeToConstantName(glob.type) << ", "
|
||||
<< glob.mutability << ", ";
|
||||
AppendInitExpr(os, wire_bytes, glob.init);
|
||||
for (WasmGlobal& global : module->globals) {
|
||||
os << "builder.addGlobal(" << ValueTypeToConstantName(global.type) << ", "
|
||||
<< global.mutability << ", ";
|
||||
DecodeAndAppendInitExpr(os, &zone, module, wire_bytes, global.init,
|
||||
global.type);
|
||||
os << ");\n";
|
||||
}
|
||||
|
||||
@ -451,15 +622,13 @@ void GenerateTestCase(Isolate* isolate, ModuleWireBytes wire_bytes,
|
||||
os << "makeField(" << ValueTypeToConstantName(struct_type->field(index))
|
||||
<< ", " << (struct_type->mutability(index) ? "true" : "false")
|
||||
<< ")";
|
||||
if (index + 1 < field_count)
|
||||
os << ", ";
|
||||
else
|
||||
os << "]);\n";
|
||||
if (index + 1 < field_count) os << ", ";
|
||||
}
|
||||
os << "]);\n";
|
||||
} else if (module->has_array(i)) {
|
||||
const ArrayType* array_type = module->types[i].array_type;
|
||||
os << "builder.addArray("
|
||||
<< ValueTypeToConstantName(array_type->element_type()) << ","
|
||||
<< ValueTypeToConstantName(array_type->element_type()) << ", "
|
||||
<< (array_type->mutability() ? "true" : "false") << ");\n";
|
||||
} else {
|
||||
DCHECK(module->has_signature(i));
|
||||
@ -489,7 +658,8 @@ void GenerateTestCase(Isolate* isolate, ModuleWireBytes wire_bytes,
|
||||
os << "builder.add" << status_str << "ElementSegment(";
|
||||
if (elem_segment.status == WasmElemSegment::kStatusActive) {
|
||||
os << elem_segment.table_index << ", ";
|
||||
AppendInitExpr(os, wire_bytes, elem_segment.offset);
|
||||
DecodeAndAppendInitExpr(os, &zone, module, wire_bytes,
|
||||
elem_segment.offset, kWasmI32);
|
||||
os << ", ";
|
||||
}
|
||||
os << "[";
|
||||
|
Loading…
Reference in New Issue
Block a user