[wasm-gc] Remove nominal types
Some tests and testing infrastructure had to be changed because it relied on nominal types. Drive-by: Support function supertypes in wasm-module-builder.js. Bug: v8:7748 Change-Id: Ife92431d1842ff9de91e296a50421aa48f02c0de Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3776197 Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Commit-Queue: Manos Koukoutos <manoskouk@chromium.org> Cr-Commit-Position: refs/heads/main@{#81862}
This commit is contained in:
parent
884226c1d0
commit
af39b32154
@ -597,9 +597,6 @@ class ModuleDecoderTemplate : public Decoder {
|
||||
case kWasmFunctionTypeCode: return "func";
|
||||
case kWasmStructTypeCode: return "struct";
|
||||
case kWasmArrayTypeCode: return "array";
|
||||
case kWasmFunctionNominalCode: return "function-nominal";
|
||||
case kWasmStructNominalCode: return "struct-nominal";
|
||||
case kWasmArrayNominalCode: return "array-nominal";
|
||||
default: return "unknown";
|
||||
// clang-format on
|
||||
}
|
||||
@ -622,13 +619,6 @@ class ModuleDecoderTemplate : public Decoder {
|
||||
const ArrayType* type = consume_array(module_->signature_zone.get());
|
||||
return {type, kNoSuperType};
|
||||
}
|
||||
case kWasmFunctionNominalCode:
|
||||
case kWasmArrayNominalCode:
|
||||
case kWasmStructNominalCode:
|
||||
tracer_.NextLine();
|
||||
errorf(pc() - 1,
|
||||
"mixing nominal and isorecursive types is not allowed");
|
||||
return {};
|
||||
default:
|
||||
tracer_.NextLine();
|
||||
errorf(pc() - 1, "unknown type form: %d", kind);
|
||||
@ -645,67 +635,6 @@ class ModuleDecoderTemplate : public Decoder {
|
||||
return true;
|
||||
}
|
||||
|
||||
TypeDefinition consume_nominal_type_definition() {
|
||||
DCHECK(enabled_features_.has_gc());
|
||||
size_t num_types = module_->types.size();
|
||||
uint8_t kind = consume_u8(" kind: ", tracer_);
|
||||
tracer_.Description(TypeKindName(kind));
|
||||
switch (kind) {
|
||||
case kWasmFunctionNominalCode: {
|
||||
const FunctionSig* sig = consume_sig(module_->signature_zone.get());
|
||||
uint32_t super_index = kNoSuperType;
|
||||
HeapType super_type = consume_super_type();
|
||||
if (super_type.is_index()) {
|
||||
super_index = super_type.representation();
|
||||
} else if (V8_UNLIKELY(super_type != HeapType::kFunc)) {
|
||||
errorf(pc() - 1, "type %zu: invalid supertype %d", num_types,
|
||||
super_type.code());
|
||||
return {};
|
||||
}
|
||||
return {sig, super_index};
|
||||
}
|
||||
case kWasmStructNominalCode: {
|
||||
const StructType* type = consume_struct(module_->signature_zone.get());
|
||||
uint32_t super_index = kNoSuperType;
|
||||
HeapType super_type = consume_super_type();
|
||||
if (super_type.is_index()) {
|
||||
super_index = super_type.representation();
|
||||
} else if (V8_UNLIKELY(super_type != HeapType::kData)) {
|
||||
errorf(pc() - 1, "type %zu: invalid supertype %d", num_types,
|
||||
super_type.code());
|
||||
return {};
|
||||
}
|
||||
return {type, super_index};
|
||||
}
|
||||
case kWasmArrayNominalCode: {
|
||||
const ArrayType* type = consume_array(module_->signature_zone.get());
|
||||
uint32_t super_index = kNoSuperType;
|
||||
HeapType super_type = consume_super_type();
|
||||
if (super_type.is_index()) {
|
||||
super_index = super_type.representation();
|
||||
} else if (V8_UNLIKELY(super_type != HeapType::kData)) {
|
||||
errorf(pc() - 1, "type %zu: invalid supertype %d", num_types,
|
||||
super_type.code());
|
||||
return {};
|
||||
}
|
||||
return {type, super_index};
|
||||
}
|
||||
case kWasmFunctionTypeCode:
|
||||
case kWasmArrayTypeCode:
|
||||
case kWasmStructTypeCode:
|
||||
case kWasmSubtypeCode:
|
||||
case kWasmRecursiveTypeGroupCode:
|
||||
tracer_.NextLine();
|
||||
errorf(pc() - 1,
|
||||
"mixing nominal and isorecursive types is not allowed");
|
||||
return {};
|
||||
default:
|
||||
tracer_.NextLine();
|
||||
errorf(pc() - 1, "unknown type form: %d", kind);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
TypeDefinition consume_subtype_definition() {
|
||||
DCHECK(enabled_features_.has_gc());
|
||||
uint8_t kind = read_u8<Decoder::kFullValidation>(pc(), "type kind");
|
||||
@ -761,9 +690,6 @@ class ModuleDecoderTemplate : public Decoder {
|
||||
case kWasmStructTypeCode:
|
||||
case kWasmSubtypeCode:
|
||||
case kWasmRecursiveTypeGroupCode:
|
||||
case kWasmFunctionNominalCode:
|
||||
case kWasmStructNominalCode:
|
||||
case kWasmArrayNominalCode:
|
||||
errorf(
|
||||
"Unknown type code 0x%02x, enable with --experimental-wasm-gc",
|
||||
opcode);
|
||||
@ -777,62 +703,37 @@ class ModuleDecoderTemplate : public Decoder {
|
||||
return;
|
||||
}
|
||||
|
||||
if (types_count > 0) {
|
||||
uint8_t first_type_opcode = this->read_u8<Decoder::kFullValidation>(pc());
|
||||
if (first_type_opcode == kWasmFunctionNominalCode ||
|
||||
first_type_opcode == kWasmStructNominalCode ||
|
||||
first_type_opcode == kWasmArrayNominalCode) {
|
||||
// wasm-gc nominal type section decoding.
|
||||
// In a nominal module, all types belong in the same recursive group. We
|
||||
// use the type vector's capacity to mark the end of the current
|
||||
// recursive group.
|
||||
module_->types.reserve(types_count);
|
||||
for (uint32_t i = 0; ok() && i < types_count; ++i) {
|
||||
TRACE("DecodeType[%d] module+%d\n", i,
|
||||
static_cast<int>(pc_ - start_));
|
||||
for (uint32_t i = 0; ok() && i < types_count; ++i) {
|
||||
TRACE("DecodeType[%d] module+%d\n", i, static_cast<int>(pc_ - start_));
|
||||
uint8_t kind = read_u8<Decoder::kFullValidation>(pc(), "type kind");
|
||||
if (kind == kWasmRecursiveTypeGroupCode) {
|
||||
consume_bytes(1, "rec. group definition", tracer_);
|
||||
tracer_.NextLine();
|
||||
uint32_t group_size =
|
||||
consume_count("recursive group size", kV8MaxWasmTypes);
|
||||
if (module_->types.size() + group_size > kV8MaxWasmTypes) {
|
||||
errorf(pc(), "Type definition count exceeds maximum %zu",
|
||||
kV8MaxWasmTypes);
|
||||
return;
|
||||
}
|
||||
// Reserve space for the current recursive group, so we are
|
||||
// allowed to reference its elements.
|
||||
module_->types.reserve(module_->types.size() + group_size);
|
||||
for (uint32_t j = 0; j < group_size; j++) {
|
||||
tracer_.TypeOffset(pc_offset());
|
||||
TypeDefinition type = consume_nominal_type_definition();
|
||||
TypeDefinition type = consume_subtype_definition();
|
||||
if (ok()) module_->add_type(type);
|
||||
}
|
||||
if (ok() && FLAG_wasm_type_canonicalization) {
|
||||
type_canon->AddRecursiveGroup(module_.get(), types_count);
|
||||
type_canon->AddRecursiveGroup(module_.get(), group_size);
|
||||
}
|
||||
} else {
|
||||
// wasm-gc isorecursive type section decoding.
|
||||
for (uint32_t i = 0; ok() && i < types_count; ++i) {
|
||||
TRACE("DecodeType[%d] module+%d\n", i,
|
||||
static_cast<int>(pc_ - start_));
|
||||
uint8_t kind = read_u8<Decoder::kFullValidation>(pc(), "type kind");
|
||||
if (kind == kWasmRecursiveTypeGroupCode) {
|
||||
consume_bytes(1, "rec. group definition", tracer_);
|
||||
tracer_.NextLine();
|
||||
uint32_t group_size =
|
||||
consume_count("recursive group size", kV8MaxWasmTypes);
|
||||
if (module_->types.size() + group_size > kV8MaxWasmTypes) {
|
||||
errorf(pc(), "Type definition count exceeds maximum %zu",
|
||||
kV8MaxWasmTypes);
|
||||
return;
|
||||
}
|
||||
// Reserve space for the current recursive group, so we are
|
||||
// allowed to reference its elements.
|
||||
module_->types.reserve(module_->types.size() + group_size);
|
||||
for (uint32_t j = 0; j < group_size; j++) {
|
||||
tracer_.TypeOffset(pc_offset());
|
||||
TypeDefinition type = consume_subtype_definition();
|
||||
if (ok()) module_->add_type(type);
|
||||
}
|
||||
if (ok() && FLAG_wasm_type_canonicalization) {
|
||||
type_canon->AddRecursiveGroup(module_.get(), group_size);
|
||||
}
|
||||
} else {
|
||||
tracer_.TypeOffset(pc_offset());
|
||||
TypeDefinition type = consume_subtype_definition();
|
||||
if (ok()) {
|
||||
module_->add_type(type);
|
||||
if (FLAG_wasm_type_canonicalization) {
|
||||
type_canon->AddRecursiveGroup(module_.get(), 1);
|
||||
}
|
||||
}
|
||||
tracer_.TypeOffset(pc_offset());
|
||||
TypeDefinition type = consume_subtype_definition();
|
||||
if (ok()) {
|
||||
module_->add_type(type);
|
||||
if (FLAG_wasm_type_canonicalization) {
|
||||
type_canon->AddRecursiveGroup(module_.get(), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -846,16 +747,11 @@ class ModuleDecoderTemplate : public Decoder {
|
||||
// {consume_super_type} has checked this.
|
||||
DCHECK_LT(explicit_super, module_->types.size());
|
||||
int depth = GetSubtypingDepth(module, i);
|
||||
DCHECK_GE(depth, 0);
|
||||
if (depth > static_cast<int>(kV8MaxRttSubtypingDepth)) {
|
||||
errorf("type %d: subtyping depth is greater than allowed", i);
|
||||
continue;
|
||||
}
|
||||
// TODO(7748): Replace this with a DCHECK once we reject inheritance
|
||||
// cycles for nominal modules.
|
||||
if (depth == -1) {
|
||||
errorf("type %d: cyclic inheritance", i);
|
||||
continue;
|
||||
}
|
||||
if (!ValidSubtypeDefinition(i, explicit_super, module, module)) {
|
||||
errorf("type %d has invalid explicit supertype %d", i, explicit_super);
|
||||
continue;
|
||||
|
@ -61,9 +61,6 @@ enum ValueTypeCode : uint8_t {
|
||||
constexpr uint8_t kWasmFunctionTypeCode = 0x60;
|
||||
constexpr uint8_t kWasmStructTypeCode = 0x5f;
|
||||
constexpr uint8_t kWasmArrayTypeCode = 0x5e;
|
||||
constexpr uint8_t kWasmFunctionNominalCode = 0x5d;
|
||||
constexpr uint8_t kWasmStructNominalCode = 0x5c;
|
||||
constexpr uint8_t kWasmArrayNominalCode = 0x5b;
|
||||
constexpr uint8_t kWasmSubtypeCode = 0x50;
|
||||
constexpr uint8_t kWasmRecursiveTypeGroupCode = 0x4f;
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
||||
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
|
||||
var builder = new WasmModuleBuilder();
|
||||
builder.setNominal();
|
||||
let supertype = builder.addStruct([makeField(kWasmI32, true)]);
|
||||
let subtype = builder.addStruct(
|
||||
[makeField(kWasmI32, true), makeField(kWasmI32, true)], supertype);
|
||||
|
@ -9,7 +9,6 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
(function TestNominalTypesBasic() {
|
||||
print(arguments.callee.name);
|
||||
var builder = new WasmModuleBuilder();
|
||||
builder.setNominal();
|
||||
let struct1 = builder.addStruct([makeField(kWasmI32, true)]);
|
||||
let struct2 = builder.addStruct(
|
||||
[makeField(kWasmI32, true), makeField(kWasmI32, true)], struct1);
|
||||
@ -39,7 +38,6 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
(function TestSubtypingDepthTooLarge() {
|
||||
print(arguments.callee.name);
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.setNominal();
|
||||
builder.addStruct([]);
|
||||
for (let i = 0; i < 32; i++) builder.addStruct([], i);
|
||||
assertThrows(
|
||||
@ -50,7 +48,6 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
(function TestArrayNewDataStatic() {
|
||||
print(arguments.callee.name);
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.setNominal();
|
||||
builder.setEarlyDataCountSection();
|
||||
let array_type_index = builder.addArray(kWasmI16, true);
|
||||
|
||||
@ -110,7 +107,6 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
(function TestArrayNewData() {
|
||||
print(arguments.callee.name);
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.setNominal();
|
||||
builder.setEarlyDataCountSection();
|
||||
let array_type_index = builder.addArray(kWasmI16, true);
|
||||
|
||||
|
@ -363,7 +363,6 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
(function AllocationFolding() {
|
||||
print(arguments.callee.name);
|
||||
var builder = new WasmModuleBuilder();
|
||||
builder.setNominal();
|
||||
|
||||
let struct_index = builder.addStruct([makeField(kWasmI32, true)]);
|
||||
let struct_2 = builder.addStruct([
|
||||
|
@ -77,7 +77,6 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
|
||||
(function ImmutableLoadThroughEffect() {
|
||||
var builder = new WasmModuleBuilder();
|
||||
builder.setNominal();
|
||||
var struct = builder.addStruct([
|
||||
makeField(kWasmI32, false), makeField(kWasmI32, true)]);
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.setSingletonRecGroups();
|
||||
|
||||
let struct_index = builder.addStruct([makeField(kWasmI32, true)]);
|
||||
let identical_struct_index = builder.addStruct([makeField(kWasmI32, true)]);
|
||||
|
@ -79,9 +79,6 @@ let kLocalNamesCode = 2;
|
||||
let kWasmFunctionTypeForm = 0x60;
|
||||
let kWasmStructTypeForm = 0x5f;
|
||||
let kWasmArrayTypeForm = 0x5e;
|
||||
let kWasmFunctionNominalForm = 0x5d;
|
||||
let kWasmStructNominalForm = 0x5c;
|
||||
let kWasmArrayNominalForm = 0x5b;
|
||||
let kWasmSubtypeForm = 0x50;
|
||||
let kWasmRecursiveTypeGroupForm = 0x4f;
|
||||
|
||||
@ -1265,7 +1262,11 @@ class WasmModuleBuilder {
|
||||
this.num_imported_globals = 0;
|
||||
this.num_imported_tables = 0;
|
||||
this.num_imported_tags = 0;
|
||||
this.nominal = false; // Controls only how gc-modules are printed.
|
||||
// If a wasm-gc type is detected, all types are put by default into a single
|
||||
// recursive group. This field overrides this behavior and puts each type in
|
||||
// a separate rec. group instead.
|
||||
// TODO(7748): Support more flexible rec. groups.
|
||||
this.singleton_rec_groups = false;
|
||||
this.early_data_count_section = false;
|
||||
return this;
|
||||
}
|
||||
@ -1327,11 +1328,11 @@ class WasmModuleBuilder {
|
||||
|
||||
// TODO(7748): Support recursive groups.
|
||||
|
||||
// TODO(7748): Support function supertypes.
|
||||
addType(type) {
|
||||
this.types.push(type);
|
||||
addType(type, supertype_idx = kNoSuperType) {
|
||||
var pl = type.params.length; // should have params
|
||||
var rl = type.results.length; // should have results
|
||||
type.supertype = supertype_idx;
|
||||
this.types.push(type);
|
||||
return this.types.length - 1;
|
||||
}
|
||||
|
||||
@ -1592,8 +1593,8 @@ class WasmModuleBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
setNominal() {
|
||||
this.nominal = true;
|
||||
setSingletonRecGroups() {
|
||||
this.singleton_rec_groups = true;
|
||||
}
|
||||
|
||||
setEarlyDataCountSection() {
|
||||
@ -1616,54 +1617,35 @@ class WasmModuleBuilder {
|
||||
if (wasm.types.length > 0) {
|
||||
if (debug) print('emitting types @ ' + binary.length);
|
||||
binary.emit_section(kTypeSectionCode, section => {
|
||||
// If any type is a wasm-gc type, wrap everything in a recursive group.
|
||||
// TODO(7748): Support more flexible rec. groups.
|
||||
if (!this.singleton_rec_groups &&
|
||||
wasm.types.findIndex(type => type instanceof WasmStruct ||
|
||||
type instanceof WasmArray) >= 0) {
|
||||
section.emit_u32v(1);
|
||||
section.emit_u8(kWasmRecursiveTypeGroupForm);
|
||||
}
|
||||
section.emit_u32v(wasm.types.length);
|
||||
|
||||
for (let type of wasm.types) {
|
||||
if (type.supertype != kNoSuperType) {
|
||||
section.emit_u8(kWasmSubtypeForm);
|
||||
section.emit_u8(1); // supertype count
|
||||
section.emit_u32v(type.supertype);
|
||||
}
|
||||
if (type instanceof WasmStruct) {
|
||||
if (!this.nominal && type.supertype != kNoSuperType) {
|
||||
section.emit_u8(kWasmSubtypeForm);
|
||||
section.emit_u8(1); // supertype count
|
||||
section.emit_u32v(type.supertype);
|
||||
}
|
||||
section.emit_u8(this.nominal ? kWasmStructNominalForm
|
||||
: kWasmStructTypeForm);
|
||||
section.emit_u8(kWasmStructTypeForm);
|
||||
section.emit_u32v(type.fields.length);
|
||||
for (let field of type.fields) {
|
||||
section.emit_type(field.type);
|
||||
section.emit_u8(field.mutability ? 1 : 0);
|
||||
}
|
||||
if (this.nominal) {
|
||||
if (type.supertype === kNoSuperType) {
|
||||
section.emit_u8(kDataRefCode);
|
||||
} else {
|
||||
section.emit_heap_type(type.supertype);
|
||||
}
|
||||
}
|
||||
} else if (type instanceof WasmArray) {
|
||||
if (!this.nominal && type.supertype != kNoSuperType) {
|
||||
section.emit_u8(kWasmSubtypeForm);
|
||||
section.emit_u8(1); // supertype count
|
||||
section.emit_u32v(type.supertype);
|
||||
}
|
||||
section.emit_u8(this.nominal ? kWasmArrayNominalForm
|
||||
: kWasmArrayTypeForm);
|
||||
section.emit_u8(kWasmArrayTypeForm);
|
||||
section.emit_type(type.type);
|
||||
section.emit_u8(type.mutability ? 1 : 0);
|
||||
if (this.nominal) {
|
||||
if (type.supertype === kNoSuperType) {
|
||||
section.emit_u8(kDataRefCode);
|
||||
} else {
|
||||
section.emit_heap_type(type.supertype);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* TODO(7748): Support function supertypes.
|
||||
if (!this.nominal && type.supertype != kNoSuperType) {
|
||||
section.emit_u8(kWasmSubtypeForm);
|
||||
section.emit_u8(1); // supertype count
|
||||
section.emit_u32v(type.supertype);
|
||||
} */
|
||||
section.emit_u8(this.nominal ? kWasmFunctionNominalForm
|
||||
: kWasmFunctionTypeForm);
|
||||
section.emit_u8(kWasmFunctionTypeForm);
|
||||
section.emit_u32v(type.params.length);
|
||||
for (let param of type.params) {
|
||||
section.emit_type(param);
|
||||
@ -1672,15 +1654,6 @@ class WasmModuleBuilder {
|
||||
for (let result of type.results) {
|
||||
section.emit_type(result);
|
||||
}
|
||||
if (this.nominal) {
|
||||
/* TODO(7748): Support function supertypes.
|
||||
if (type.supertype === kNoSuperType) {
|
||||
section.emit_u8(kFuncRefCode);
|
||||
} else {
|
||||
section.emit_heap_type(type.supertype);
|
||||
}*/
|
||||
section.emit_u8(kFuncRefCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -857,13 +857,13 @@ TEST_F(WasmModuleVerifyTest, ArrayNewFixedInitExpr) {
|
||||
0, 3, WASM_I32V(10), WASM_I32V(20), WASM_I32V(30)))};
|
||||
EXPECT_VERIFIES(basic);
|
||||
|
||||
static const byte basic_nominal[] = {
|
||||
static const byte basic_static[] = {
|
||||
SECTION(Type, ENTRY_COUNT(1), WASM_ARRAY_DEF(kI16Code, true)),
|
||||
SECTION(Global, ENTRY_COUNT(1), // --
|
||||
kRefCode, 0, 0, // type, mutability
|
||||
WASM_INIT_EXPR_ARRAY_NEW_FIXED_STATIC(
|
||||
0, 3, WASM_I32V(10), WASM_I32V(20), WASM_I32V(30)))};
|
||||
EXPECT_VERIFIES(basic_nominal);
|
||||
EXPECT_VERIFIES(basic_static);
|
||||
|
||||
static const byte basic_immutable[] = {
|
||||
SECTION(Type, ENTRY_COUNT(1), WASM_ARRAY_DEF(kI32Code, false)),
|
||||
@ -987,136 +987,6 @@ TEST_F(WasmModuleVerifyTest, InvalidStructTypeDef) {
|
||||
EXPECT_FAILURE_WITH_MSG(invalid_mutability, "invalid mutability");
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, NominalStructTypeDef) {
|
||||
WASM_FEATURE_SCOPE(typed_funcref);
|
||||
WASM_FEATURE_SCOPE(gc);
|
||||
|
||||
// Inheritance: t1 <: t2 <: t0
|
||||
static const byte all_good[] = {
|
||||
SECTION(Type, ENTRY_COUNT(3), // --
|
||||
kWasmStructNominalCode, // type #0
|
||||
1, // field count
|
||||
kI32Code, 1, // mut i32
|
||||
kDataRefCode, // root of type hierarchy
|
||||
|
||||
kWasmStructNominalCode, // type #1
|
||||
2, // field count
|
||||
kI32Code, 1, // mut i32 (inherited)
|
||||
kI64Code, 1, // mut i32 (added)
|
||||
2, // supertype
|
||||
|
||||
kWasmStructNominalCode, // type #2
|
||||
1, // field count
|
||||
kI32Code, 1, // mut i32 (inherited)
|
||||
0)}; // supertype
|
||||
EXPECT_VERIFIES(all_good);
|
||||
ModuleResult result = DecodeModule(all_good, all_good + sizeof(all_good));
|
||||
EXPECT_OK(result);
|
||||
WasmModule* module = result.value().get();
|
||||
EXPECT_EQ(kNoSuperType, module->supertype(0));
|
||||
EXPECT_EQ(2u, module->supertype(1));
|
||||
EXPECT_EQ(0u, module->supertype(2));
|
||||
|
||||
static const byte self_or_mutual_ref[] = {
|
||||
SECTION(Type, ENTRY_COUNT(4), // --
|
||||
kWasmStructNominalCode, 0, // empty struct
|
||||
kDataRefCode, // root of hierarchy
|
||||
|
||||
kWasmStructNominalCode, // type1
|
||||
1, // field count
|
||||
kRefNullCode, 1, 1, // mut (ref null type1)
|
||||
0, // supertype
|
||||
|
||||
kWasmStructNominalCode, // type 2
|
||||
1, // field count
|
||||
kRefNullCode, 3, 1, // mut (ref null type3)
|
||||
0, // supertype
|
||||
|
||||
kWasmStructNominalCode, // type 3
|
||||
1, // field count
|
||||
kRefNullCode, 2, 1, // mut (ref null type2)
|
||||
0)}; // supertype
|
||||
EXPECT_VERIFIES(self_or_mutual_ref);
|
||||
|
||||
static const byte mutual_ref_with_subtyping[] = {
|
||||
SECTION(Type,
|
||||
ENTRY_COUNT(3), // --
|
||||
kWasmStructNominalCode, //
|
||||
1, // field count
|
||||
kRefNullCode, 0, 0, // ref type0
|
||||
kDataRefCode, // root of hierarchy
|
||||
|
||||
kWasmStructNominalCode, // --
|
||||
1, // field count
|
||||
kRefNullCode, 2, 0, // ref type2
|
||||
0, // supertype
|
||||
|
||||
kWasmStructNominalCode, // --
|
||||
1, // field count
|
||||
kRefNullCode, 1, 0, // ref type1
|
||||
0)}; // supertype
|
||||
EXPECT_VERIFIES(mutual_ref_with_subtyping);
|
||||
|
||||
static const byte inheritance_cycle[] = {
|
||||
SECTION(Type, ENTRY_COUNT(2), // --
|
||||
kWasmStructNominalCode, 0, 1, // no fields, supertype 1
|
||||
kWasmStructNominalCode, 0, 0)}; // no fields, supertype 0
|
||||
EXPECT_FAILURE_WITH_MSG(inheritance_cycle, "cyclic inheritance");
|
||||
|
||||
static const byte invalid_field[] = {
|
||||
SECTION(Type, ENTRY_COUNT(2), // --
|
||||
kWasmStructTypeCode, U32V_1(1), kI32Code, 1, // t0: [i32]
|
||||
kWasmStructNominalCode, U32V_1(2), // t1:
|
||||
kI64Code, 1, // i64 (invalid inheritance)
|
||||
kI32Code, 1, U32V_1(0))}; // i32 (added), supertype 0
|
||||
EXPECT_FAILURE_WITH_MSG(
|
||||
invalid_field, "mixing nominal and isorecursive types is not allowed");
|
||||
|
||||
static const byte structural_supertype[] = {
|
||||
SECTION(Type, ENTRY_COUNT(2), // --
|
||||
kWasmStructTypeCode, 0, // empty struct
|
||||
kWasmStructNominalCode, 0, // also empty
|
||||
0)}; // supertype is structural type
|
||||
EXPECT_FAILURE_WITH_MSG(
|
||||
structural_supertype,
|
||||
"mixing nominal and isorecursive types is not allowed");
|
||||
|
||||
static const byte supertype_oob[] = {
|
||||
SECTION(Type, ENTRY_COUNT(1), // --
|
||||
kWasmStructNominalCode,
|
||||
0, // empty struct
|
||||
13)}; // supertype with invalid index
|
||||
EXPECT_FAILURE_WITH_MSG(supertype_oob, "Type index 13 is out of bounds");
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, NominalFunctionTypeDef) {
|
||||
WASM_FEATURE_SCOPE(typed_funcref);
|
||||
WASM_FEATURE_SCOPE(gc);
|
||||
EXPERIMENTAL_FLAG_SCOPE(gc); // Needed for subtype checking.
|
||||
|
||||
static const byte all_good[] = {
|
||||
SECTION(Type, ENTRY_COUNT(2), // --
|
||||
kWasmFunctionNominalCode, // type #0
|
||||
1, // params count
|
||||
kRefCode, 0, // ref #0
|
||||
1, // results count
|
||||
kRefNullCode, 0, // (ref null 0)
|
||||
kFuncRefCode, // root of type hierarchy
|
||||
|
||||
kWasmFunctionNominalCode, // type #1
|
||||
1, // params count
|
||||
kRefNullCode, 0, // refined (contravariant)
|
||||
1, // results count
|
||||
kRefCode, 0, // refined (covariant)
|
||||
0)}; // supertype
|
||||
EXPECT_VERIFIES(all_good);
|
||||
ModuleResult result = DecodeModule(all_good, all_good + sizeof(all_good));
|
||||
EXPECT_OK(result);
|
||||
WasmModule* module = result.value().get();
|
||||
EXPECT_EQ(kNoSuperType, module->supertype(0));
|
||||
EXPECT_EQ(0u, module->supertype(1));
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, InvalidArrayTypeDef) {
|
||||
WASM_FEATURE_SCOPE(typed_funcref);
|
||||
WASM_FEATURE_SCOPE(gc);
|
||||
|
Loading…
Reference in New Issue
Block a user