[wasm-stringrefs] Remove subtyping between string view / iter and any

The intention is to be restrictive for now: modules should not
start to depend on this subtyping while the stringref type
hierarchy question is being settled (see
https://github.com/WebAssembly/stringref/issues/3 for details).

Bug: v8:12868
Change-Id: I0140e72f92550c88393dc84bb1fa3ce65840a048
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3865019
Commit-Queue: Matthias Liedtke <mliedtke@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82937}
This commit is contained in:
Matthias Liedtke 2022-09-02 10:17:49 +02:00 committed by V8 LUCI CQ
parent 2f95d10f6b
commit c6efb4da12
3 changed files with 65 additions and 19 deletions

View File

@ -219,14 +219,13 @@ V8_NOINLINE V8_EXPORT_PRIVATE bool IsHeapSubtypeOfImpl(
return super_heap == HeapType::kArray || super_heap == HeapType::kData ||
super_heap == HeapType::kEq || super_heap == HeapType::kAny;
case HeapType::kString:
// TODO(7748): Remove views from any subtype hierarchy as views can't be
// externalized as of now.
case HeapType::kStringViewWtf8:
case HeapType::kStringViewWtf16:
case HeapType::kStringViewIter:
// stringref is a subtype of anyref under wasm-gc.
return sub_heap == super_heap ||
(v8_flags.experimental_wasm_gc && super_heap == HeapType::kAny);
case HeapType::kStringViewWtf8:
case HeapType::kStringViewWtf16:
case HeapType::kStringViewIter:
return sub_heap == super_heap;
case HeapType::kBottom:
UNREACHABLE();
case HeapType::kNone:
@ -480,6 +479,9 @@ HeapType::Representation CommonAncestorWithGeneric(HeapType heap1,
: HeapType::kNoExtern;
case HeapType::kExtern:
return HeapType::kExtern;
case HeapType::kString:
case HeapType::kStringViewIter:
return heap1 == heap2 ? heap1.representation() : HeapType::kBottom;
default:
UNREACHABLE();
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --experimental-wasm-gc
// Flags: --experimental-wasm-gc --experimental-wasm-stringref
d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
@ -43,7 +43,7 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
let builder = new WasmModuleBuilder();
const size = 10;
const maxSize = 15;
const maxSize = 20;
let table = new WebAssembly.Table({
initial: size, maximum: maxSize, element: typeName
});
@ -148,6 +148,18 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
])
.exportFunc();
if (typeName == "anyref") {
builder.addFunction("tableSetFromExtern",
makeSig([kWasmI32, kWasmExternRef], []))
.addBody([
kExprLocalGet, 0,
kExprLocalGet, 1,
kGCPrefix, kExprExternInternalize,
kExprTableSet, 0,
])
.exportFunc();
}
let instance = builder.instantiate({ imports: { table } });
let wasm = instance.exports;
@ -185,8 +197,20 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
assertEquals(12, wasm.tableGetArrayVal(7));
assertEquals(0, wasm.eq(table.get(6), table.get(7))); // Not the same.
// Set stringref.
if (typeName == "anyref") {
table.set(8, "TestString");
assertEquals("TestString", wasm.tableGet(8));
assertEquals("TestString", table.get(8));
let largeString = "Another test string, this time larger to prevent"
+ " any kind of short string optimization.";
wasm.tableSetFromExtern(9, largeString);
assertEquals(largeString, wasm.tableGet(9));
assertEquals(largeString, table.get(9));
}
// Ensure all objects are externalized, so they can be handled by JS.
for (let i = 0; i < size; ++i) {
for (let i = 0; i < table.length; ++i) {
JSON.stringify(table.get(i));
}
@ -200,6 +224,11 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
table.grow(1, null);
table.grow(1, undefined);
}
if (typeName == "anyref") {
table.grow(1, "Grow using a string");
assertEquals("Grow using a string", wasm.tableGet(14));
assertEquals("Grow using a string", table.get(14));
}
// Set from JS with wrapped wasm value of incompatible type.
let invalidValues = {

View File

@ -134,6 +134,7 @@ TEST_F(WasmSubtypingTest, Subtyping) {
kWasmI31Ref, kWasmAnyRef, // --
kWasmExternRef, kWasmNullExternRef, // --
kWasmNullRef, kWasmNullFuncRef, // --
kWasmStringRef, kWasmStringViewIter, // --
refNull(0), ref(0), // struct
refNull(2), ref(2), // array
refNull(11), ref(11) // signature
@ -198,11 +199,15 @@ TEST_F(WasmSubtypingTest, Subtyping) {
const bool is_any_func = ref_type == kWasmFuncRef ||
ref_type == kWasmNullFuncRef ||
ref_type == refNull(11) || ref_type == ref(11);
const bool is_string_view = ref_type == kWasmStringViewIter ||
ref_type == kWasmStringViewWtf8 ||
ref_type == kWasmStringViewWtf16;
SCOPED_TRACE("ref_type: " + ref_type.name());
// Concrete reference types, i31ref and dataref are subtypes of eqref,
// externref/funcref/anyref/functions are not.
SUBTYPE_IFF(ref_type, kWasmEqRef,
ref_type != kWasmAnyRef && !is_any_func && !is_extern);
ref_type != kWasmAnyRef && !is_any_func && !is_extern &&
!is_string_view && ref_type != kWasmStringRef);
// Struct/array types are subtypes of dataref.
SUBTYPE_IFF(ref_type, kWasmDataRef,
ref_type == kWasmDataRef || ref_type == kWasmArrayRef ||
@ -217,8 +222,10 @@ TEST_F(WasmSubtypingTest, Subtyping) {
SUBTYPE_IFF(ref_type, kWasmFuncRef, is_any_func);
// Each reference type is a subtype of itself.
SUBTYPE(ref_type, ref_type);
// Each non-func, non-extern reference type is a subtype of anyref.
SUBTYPE_IFF(ref_type, kWasmAnyRef, !is_any_func && !is_extern);
// Each non-func, non-extern, non-string-view, non-string-iter reference
// type is a subtype of anyref.
SUBTYPE_IFF(ref_type, kWasmAnyRef,
!is_any_func && !is_extern && !is_string_view);
// Only anyref is a subtype of anyref.
SUBTYPE_IFF(kWasmAnyRef, ref_type, ref_type == kWasmAnyRef);
// Only externref and nullexternref are subtypes of externref.
@ -349,8 +356,16 @@ TEST_F(WasmSubtypingTest, Subtyping) {
// Reference type vs. itself and anyref.
for (ValueType type : ref_types) {
SCOPED_TRACE(type.name());
UNION(type, type, type);
INTERSECTION(type, type, type);
if (type == kWasmStringViewIter || type == kWasmStringViewWtf8 ||
type == kWasmStringViewWtf16) {
// String view and string iter aren't subtypes of any but have the same
// null sentinel nullref (ref null none).
INTERSECTION(type, kWasmAnyRef, kWasmNullRef);
continue;
}
if (type == kWasmFuncRef || type == kWasmNullFuncRef || type == ref(11) ||
type == refNull(11) || type == kWasmExternRef ||
type == kWasmNullExternRef) {