Commit c6efb4da authored by Matthias Liedtke's avatar Matthias Liedtke Committed by V8 LUCI CQ

[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: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82937}
parent 2f95d10f
...@@ -219,14 +219,13 @@ V8_NOINLINE V8_EXPORT_PRIVATE bool IsHeapSubtypeOfImpl( ...@@ -219,14 +219,13 @@ V8_NOINLINE V8_EXPORT_PRIVATE bool IsHeapSubtypeOfImpl(
return super_heap == HeapType::kArray || super_heap == HeapType::kData || return super_heap == HeapType::kArray || super_heap == HeapType::kData ||
super_heap == HeapType::kEq || super_heap == HeapType::kAny; super_heap == HeapType::kEq || super_heap == HeapType::kAny;
case HeapType::kString: 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. // stringref is a subtype of anyref under wasm-gc.
return sub_heap == super_heap || return sub_heap == super_heap ||
(v8_flags.experimental_wasm_gc && super_heap == HeapType::kAny); (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: case HeapType::kBottom:
UNREACHABLE(); UNREACHABLE();
case HeapType::kNone: case HeapType::kNone:
...@@ -480,6 +479,9 @@ HeapType::Representation CommonAncestorWithGeneric(HeapType heap1, ...@@ -480,6 +479,9 @@ HeapType::Representation CommonAncestorWithGeneric(HeapType heap1,
: HeapType::kNoExtern; : HeapType::kNoExtern;
case HeapType::kExtern: case HeapType::kExtern:
return HeapType::kExtern; return HeapType::kExtern;
case HeapType::kString:
case HeapType::kStringViewIter:
return heap1 == heap2 ? heap1.representation() : HeapType::kBottom;
default: default:
UNREACHABLE(); UNREACHABLE();
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // 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'); d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
...@@ -43,7 +43,7 @@ for (let [typeName, type] of Object.entries(tableTypes)) { ...@@ -43,7 +43,7 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
let builder = new WasmModuleBuilder(); let builder = new WasmModuleBuilder();
const size = 10; const size = 10;
const maxSize = 15; const maxSize = 20;
let table = new WebAssembly.Table({ let table = new WebAssembly.Table({
initial: size, maximum: maxSize, element: typeName initial: size, maximum: maxSize, element: typeName
}); });
...@@ -148,6 +148,18 @@ for (let [typeName, type] of Object.entries(tableTypes)) { ...@@ -148,6 +148,18 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
]) ])
.exportFunc(); .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 instance = builder.instantiate({ imports: { table } });
let wasm = instance.exports; let wasm = instance.exports;
...@@ -185,8 +197,20 @@ for (let [typeName, type] of Object.entries(tableTypes)) { ...@@ -185,8 +197,20 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
assertEquals(12, wasm.tableGetArrayVal(7)); assertEquals(12, wasm.tableGetArrayVal(7));
assertEquals(0, wasm.eq(table.get(6), table.get(7))); // Not the same. 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. // 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)); JSON.stringify(table.get(i));
} }
...@@ -200,6 +224,11 @@ for (let [typeName, type] of Object.entries(tableTypes)) { ...@@ -200,6 +224,11 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
table.grow(1, null); table.grow(1, null);
table.grow(1, undefined); 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. // Set from JS with wrapped wasm value of incompatible type.
let invalidValues = { let invalidValues = {
......
...@@ -129,14 +129,15 @@ TEST_F(WasmSubtypingTest, Subtyping) { ...@@ -129,14 +129,15 @@ TEST_F(WasmSubtypingTest, Subtyping) {
constexpr ValueType numeric_types[] = {kWasmI32, kWasmI64, kWasmF32, kWasmF64, constexpr ValueType numeric_types[] = {kWasmI32, kWasmI64, kWasmF32, kWasmF64,
kWasmS128}; kWasmS128};
constexpr ValueType ref_types[] = { constexpr ValueType ref_types[] = {
kWasmFuncRef, kWasmEqRef, // -- kWasmFuncRef, kWasmEqRef, // --
kWasmDataRef, kWasmArrayRef, // -- kWasmDataRef, kWasmArrayRef, // --
kWasmI31Ref, kWasmAnyRef, // -- kWasmI31Ref, kWasmAnyRef, // --
kWasmExternRef, kWasmNullExternRef, // -- kWasmExternRef, kWasmNullExternRef, // --
kWasmNullRef, kWasmNullFuncRef, // -- kWasmNullRef, kWasmNullFuncRef, // --
refNull(0), ref(0), // struct kWasmStringRef, kWasmStringViewIter, // --
refNull(2), ref(2), // array refNull(0), ref(0), // struct
refNull(11), ref(11) // signature refNull(2), ref(2), // array
refNull(11), ref(11) // signature
}; };
// Some macros to help managing types and modules. // Some macros to help managing types and modules.
...@@ -198,11 +199,15 @@ TEST_F(WasmSubtypingTest, Subtyping) { ...@@ -198,11 +199,15 @@ TEST_F(WasmSubtypingTest, Subtyping) {
const bool is_any_func = ref_type == kWasmFuncRef || const bool is_any_func = ref_type == kWasmFuncRef ||
ref_type == kWasmNullFuncRef || ref_type == kWasmNullFuncRef ||
ref_type == refNull(11) || ref_type == ref(11); 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()); SCOPED_TRACE("ref_type: " + ref_type.name());
// Concrete reference types, i31ref and dataref are subtypes of eqref, // Concrete reference types, i31ref and dataref are subtypes of eqref,
// externref/funcref/anyref/functions are not. // externref/funcref/anyref/functions are not.
SUBTYPE_IFF(ref_type, kWasmEqRef, 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. // Struct/array types are subtypes of dataref.
SUBTYPE_IFF(ref_type, kWasmDataRef, SUBTYPE_IFF(ref_type, kWasmDataRef,
ref_type == kWasmDataRef || ref_type == kWasmArrayRef || ref_type == kWasmDataRef || ref_type == kWasmArrayRef ||
...@@ -217,8 +222,10 @@ TEST_F(WasmSubtypingTest, Subtyping) { ...@@ -217,8 +222,10 @@ TEST_F(WasmSubtypingTest, Subtyping) {
SUBTYPE_IFF(ref_type, kWasmFuncRef, is_any_func); SUBTYPE_IFF(ref_type, kWasmFuncRef, is_any_func);
// Each reference type is a subtype of itself. // Each reference type is a subtype of itself.
SUBTYPE(ref_type, ref_type); SUBTYPE(ref_type, ref_type);
// Each non-func, non-extern reference type is a subtype of anyref. // Each non-func, non-extern, non-string-view, non-string-iter reference
SUBTYPE_IFF(ref_type, kWasmAnyRef, !is_any_func && !is_extern); // 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. // Only anyref is a subtype of anyref.
SUBTYPE_IFF(kWasmAnyRef, ref_type, ref_type == kWasmAnyRef); SUBTYPE_IFF(kWasmAnyRef, ref_type, ref_type == kWasmAnyRef);
// Only externref and nullexternref are subtypes of externref. // Only externref and nullexternref are subtypes of externref.
...@@ -349,8 +356,16 @@ TEST_F(WasmSubtypingTest, Subtyping) { ...@@ -349,8 +356,16 @@ TEST_F(WasmSubtypingTest, Subtyping) {
// Reference type vs. itself and anyref. // Reference type vs. itself and anyref.
for (ValueType type : ref_types) { for (ValueType type : ref_types) {
SCOPED_TRACE(type.name());
UNION(type, type, type); UNION(type, type, type);
INTERSECTION(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) || if (type == kWasmFuncRef || type == kWasmNullFuncRef || type == ref(11) ||
type == refNull(11) || type == kWasmExternRef || type == refNull(11) || type == kWasmExternRef ||
type == kWasmNullExternRef) { type == kWasmNullExternRef) {
......
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