From d314be67304a37fff81df6e2e069675824c569fc Mon Sep 17 00:00:00 2001 From: Jakob Kummerow Date: Wed, 4 Aug 2021 22:58:16 +0200 Subject: [PATCH] [wasm-gc] Experiment: accept types with explicit inheritance This patch makes V8 accept the binary format produced by Binaryen after https://github.com/WebAssembly/binaryen/pull/3933 when the --experimental-wasm-gc-experiments flag is present. The explicit inheritance information is not used for anything. Validation is performed only insofar as explicit supertypes must be valid types. Bug: v8:7748 Change-Id: Id5b5050aa03591281632e3a2a161aa93422e10bd Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3071406 Reviewed-by: Manos Koukoutos Commit-Queue: Jakob Kummerow Cr-Commit-Position: refs/heads/master@{#76135} --- src/wasm/module-decoder.cc | 45 ++++++++++++++++++++++++ src/wasm/wasm-constants.h | 3 ++ test/mjsunit/wasm/gc-nominal.js | 31 ++++++++++++++++ test/mjsunit/wasm/wasm-module-builder.js | 40 +++++++++++++++++++-- 4 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 test/mjsunit/wasm/gc-nominal.js diff --git a/src/wasm/module-decoder.cc b/src/wasm/module-decoder.cc index f2022b8ccb..b014f8a8c7 100644 --- a/src/wasm/module-decoder.cc +++ b/src/wasm/module-decoder.cc @@ -562,6 +562,21 @@ class ModuleDecoderImpl : public Decoder { module_->add_signature(s); break; } + case kWasmFunctionExtendingTypeCode: { + if (!enabled_features_.has_gc_experiments()) { + errorf(pc(), + "nominal types need --experimental-wasm-gc-experiments"); + break; + } + const FunctionSig* s = consume_sig(module_->signature_zone.get()); + module_->add_signature(s); + uint32_t super_index = consume_u32v("supertype"); + if (!module_->has_signature(super_index)) { + errorf(pc(), "invalid function supertype index: %d", super_index); + break; + } + break; + } case kWasmStructTypeCode: { if (!enabled_features_.has_gc()) { errorf(pc(), @@ -575,6 +590,21 @@ class ModuleDecoderImpl : public Decoder { // {signature_map} does for function signatures? break; } + case kWasmStructExtendingTypeCode: { + if (!enabled_features_.has_gc_experiments()) { + errorf(pc(), + "nominal types need --experimental-wasm-gc-experiments"); + break; + } + const StructType* s = consume_struct(module_->signature_zone.get()); + module_->add_struct_type(s); + uint32_t super_index = consume_u32v("supertype"); + if (!module_->has_struct(super_index)) { + errorf(pc(), "invalid struct supertype: %d", super_index); + break; + } + break; + } case kWasmArrayTypeCode: { if (!enabled_features_.has_gc()) { errorf(pc(), @@ -586,6 +616,21 @@ class ModuleDecoderImpl : public Decoder { module_->add_array_type(type); break; } + case kWasmArrayExtendingTypeCode: { + if (!enabled_features_.has_gc_experiments()) { + errorf(pc(), + "nominal types need --experimental-wasm-gc-experiments"); + break; + } + const ArrayType* type = consume_array(module_->signature_zone.get()); + module_->add_array_type(type); + uint32_t super_index = consume_u32v("supertype"); + if (!module_->has_array(super_index)) { + errorf(pc(), "invalid array supertype: %d", super_index); + break; + } + break; + } default: errorf(pc(), "unknown type form: %d", kind); break; diff --git a/src/wasm/wasm-constants.h b/src/wasm/wasm-constants.h index ecfaa65217..726ceaa018 100644 --- a/src/wasm/wasm-constants.h +++ b/src/wasm/wasm-constants.h @@ -50,6 +50,9 @@ enum ValueTypeCode : uint8_t { constexpr uint8_t kWasmFunctionTypeCode = 0x60; constexpr uint8_t kWasmStructTypeCode = 0x5f; constexpr uint8_t kWasmArrayTypeCode = 0x5e; +constexpr uint8_t kWasmFunctionExtendingTypeCode = 0x5d; +constexpr uint8_t kWasmStructExtendingTypeCode = 0x5c; +constexpr uint8_t kWasmArrayExtendingTypeCode = 0x5b; // Binary encoding of import/export kinds. enum ImportExportKindCode : uint8_t { diff --git a/test/mjsunit/wasm/gc-nominal.js b/test/mjsunit/wasm/gc-nominal.js new file mode 100644 index 0000000000..0483b4a78f --- /dev/null +++ b/test/mjsunit/wasm/gc-nominal.js @@ -0,0 +1,31 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --experimental-wasm-gc-experiments + +d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); + +var builder = new WasmModuleBuilder(); +let struct1 = builder.addStruct([makeField(kWasmI32, true)]); +let struct2 = builder.addStructExtending( + [makeField(kWasmI32, true), makeField(kWasmI32, true)], struct1); + +let array1 = builder.addArray(kWasmI32, true); +let array2 = builder.addArrayExtending(kWasmI32, true, array1); + +builder.addFunction("main", kSig_v_v) + .addLocals(wasmOptRefType(struct1), 1) + .addLocals(wasmOptRefType(array1), 1) + .addBody([ + kGCPrefix, kExprRttCanon, struct2, + kGCPrefix, kExprStructNewDefault, struct2, + kExprLocalSet, 0, + kExprI32Const, 10, // length + kGCPrefix, kExprRttCanon, array2, + kGCPrefix, kExprArrayNewDefault, array2, + kExprLocalSet, 1 + ]); + +// This test is only interested in type checking. +builder.instantiate(); diff --git a/test/mjsunit/wasm/wasm-module-builder.js b/test/mjsunit/wasm/wasm-module-builder.js index 9eff8cc2e5..f71b1854a2 100644 --- a/test/mjsunit/wasm/wasm-module-builder.js +++ b/test/mjsunit/wasm/wasm-module-builder.js @@ -77,6 +77,9 @@ let kLocalNamesCode = 2; let kWasmFunctionTypeForm = 0x60; let kWasmStructTypeForm = 0x5f; let kWasmArrayTypeForm = 0x5e; +let kWasmFunctionExtendingTypeForm = 0x5d; +let kWasmStructExtendingTypeForm = 0x5c; +let kWasmArrayExtendingTypeForm = 0x5b; let kLimitsNoMaximum = 0x00; let kLimitsWithMaximum = 0x01; @@ -1223,6 +1226,15 @@ class WasmStruct { throw new Error('struct fields must be an array'); } this.fields = fields; + this.type_form = kWasmStructTypeForm; + } +} + +class WasmStructExtending extends WasmStruct { + constructor(fields, supertype_idx) { + super(fields); + this.supertype = supertype_idx; + this.type_form = kWasmStructExtendingTypeForm; } } @@ -1231,9 +1243,17 @@ class WasmArray { this.type = type; if (!mutability) throw new Error("Immutable arrays are not supported yet"); this.mutability = mutability; + this.type_form = kWasmArrayTypeForm; } } +class WasmArrayExtending extends WasmArray { + constructor(type, mutability, supertype_idx) { + super(type, mutability); + this.supertype = supertype_idx; + this.type_form = kWasmArrayExtendingTypeForm; + } +} class WasmElemSegment { constructor(table, offset, type, elements, is_decl) { this.table = table; @@ -1356,11 +1376,21 @@ class WasmModuleBuilder { return this.types.length - 1; } + addStructExtending(fields, supertype_idx) { + this.types.push(new WasmStructExtending(fields, supertype_idx)); + return this.types.length - 1; + } + addArray(type, mutability) { this.types.push(new WasmArray(type, mutability)); return this.types.length - 1; } + addArrayExtending(type, mutability, supertype_idx) { + this.types.push(new WasmArrayExtending(type, mutability, supertype_idx)); + return this.types.length - 1; + } + addGlobal(type, mutable, init) { if (init === undefined) init = WasmInitExpr.defaultFor(type); let glob = new WasmGlobalBuilder(this, type, mutable, init); @@ -1589,16 +1619,22 @@ class WasmModuleBuilder { section.emit_u32v(wasm.types.length); for (let type of wasm.types) { if (type instanceof WasmStruct) { - section.emit_u8(kWasmStructTypeForm); + section.emit_u8(type.type_form); 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 (type instanceof WasmStructExtending) { + section.emit_u32v(type.supertype); + } } else if (type instanceof WasmArray) { - section.emit_u8(kWasmArrayTypeForm); + section.emit_u8(type.type_form); section.emit_type(type.type); section.emit_u8(type.mutability ? 1 : 0); + if (type instanceof WasmArrayExtending) { + section.emit_u32v(type.supertype); + } } else { section.emit_u8(kWasmFunctionTypeForm); section.emit_u32v(type.params.length);