[stringref] Add support for stringref globals, with JS interface
Bug: v8:12868 Change-Id: I955155db468b2ecd86fa6c5a73c616b0e4c66446 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3644949 Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Commit-Queue: Andy Wingo <wingo@igalia.com> Cr-Commit-Position: refs/heads/main@{#80584}
This commit is contained in:
parent
eb56775a69
commit
1a3edfb7e5
@ -1346,6 +1346,9 @@ bool GetValueType(Isolate* isolate, MaybeLocal<Value> maybe,
|
||||
} else if (enabled_features.has_gc() &&
|
||||
string->StringEquals(v8_str(isolate, "eqref"))) {
|
||||
*type = i::wasm::kWasmEqRef;
|
||||
} else if (enabled_features.has_stringref() &&
|
||||
string->StringEquals(v8_str(isolate, "stringref"))) {
|
||||
*type = i::wasm::kWasmStringRef;
|
||||
} else {
|
||||
// Unrecognized type.
|
||||
*type = i::wasm::kWasmVoid;
|
||||
@ -1523,13 +1526,28 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case i::wasm::HeapType::kString: {
|
||||
if (args.Length() < 2) {
|
||||
thrower.TypeError(
|
||||
"Missing initial value when creating stringref global");
|
||||
break;
|
||||
}
|
||||
|
||||
DCHECK_EQ(type.nullability(), i::wasm::kNullable);
|
||||
if (!value->IsNull() && !value->IsString()) {
|
||||
thrower.TypeError(
|
||||
"The value of stringref globals must be null or a string");
|
||||
}
|
||||
|
||||
global_obj->SetStringRef(Utils::OpenHandle(*value));
|
||||
break;
|
||||
}
|
||||
case internal::wasm::HeapType::kBottom:
|
||||
UNREACHABLE();
|
||||
case i::wasm::HeapType::kEq:
|
||||
case internal::wasm::HeapType::kI31:
|
||||
case internal::wasm::HeapType::kData:
|
||||
case internal::wasm::HeapType::kArray:
|
||||
case internal::wasm::HeapType::kString:
|
||||
case internal::wasm::HeapType::kStringViewWtf8:
|
||||
case internal::wasm::HeapType::kStringViewWtf16:
|
||||
case internal::wasm::HeapType::kStringViewIter:
|
||||
@ -2434,6 +2452,7 @@ void WebAssemblyGlobalGetValueCommon(
|
||||
case i::wasm::kOptRef:
|
||||
switch (receiver->type().heap_representation()) {
|
||||
case i::wasm::HeapType::kAny:
|
||||
case i::wasm::HeapType::kString:
|
||||
return_value.Set(Utils::ToLocal(receiver->GetRef()));
|
||||
break;
|
||||
case i::wasm::HeapType::kFunc: {
|
||||
@ -2446,16 +2465,21 @@ void WebAssemblyGlobalGetValueCommon(
|
||||
return_value.Set(Utils::ToLocal(result));
|
||||
break;
|
||||
}
|
||||
case i::wasm::HeapType::kStringViewWtf8:
|
||||
thrower.TypeError("stringview_wtf8 has no JS representation");
|
||||
break;
|
||||
case i::wasm::HeapType::kStringViewWtf16:
|
||||
thrower.TypeError("stringview_wtf16 has no JS representation");
|
||||
break;
|
||||
case i::wasm::HeapType::kStringViewIter:
|
||||
thrower.TypeError("stringview_iter has no JS representation");
|
||||
break;
|
||||
case i::wasm::HeapType::kBottom:
|
||||
UNREACHABLE();
|
||||
case i::wasm::HeapType::kI31:
|
||||
case i::wasm::HeapType::kData:
|
||||
case i::wasm::HeapType::kArray:
|
||||
case i::wasm::HeapType::kEq:
|
||||
case i::wasm::HeapType::kString:
|
||||
case i::wasm::HeapType::kStringViewWtf8:
|
||||
case i::wasm::HeapType::kStringViewWtf16:
|
||||
case i::wasm::HeapType::kStringViewIter:
|
||||
default:
|
||||
// TODO(7748): Implement these.
|
||||
UNIMPLEMENTED();
|
||||
@ -2543,16 +2567,40 @@ void WebAssemblyGlobalSetValue(
|
||||
}
|
||||
break;
|
||||
}
|
||||
case i::wasm::HeapType::kString: {
|
||||
if (!args[0]->IsString()) {
|
||||
if (args[0]->IsNull()) {
|
||||
if (receiver->type().nullability() == i::wasm::kNonNullable) {
|
||||
thrower.TypeError(
|
||||
"Can't set non-nullable stringref global to null");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
thrower.TypeError(
|
||||
receiver->type().nullability() == i::wasm::kNonNullable
|
||||
? "Non-nullable stringref global can only hold a string"
|
||||
: "Stringref global can only hold null or a string");
|
||||
break;
|
||||
}
|
||||
}
|
||||
receiver->SetStringRef(Utils::OpenHandle(*args[0]));
|
||||
break;
|
||||
}
|
||||
case i::wasm::HeapType::kStringViewWtf8:
|
||||
thrower.TypeError("stringview_wtf8 has no JS representation");
|
||||
break;
|
||||
case i::wasm::HeapType::kStringViewWtf16:
|
||||
thrower.TypeError("stringview_wtf16 has no JS representation");
|
||||
break;
|
||||
case i::wasm::HeapType::kStringViewIter:
|
||||
thrower.TypeError("stringview_iter has no JS representation");
|
||||
break;
|
||||
case i::wasm::HeapType::kBottom:
|
||||
UNREACHABLE();
|
||||
case i::wasm::HeapType::kI31:
|
||||
case i::wasm::HeapType::kData:
|
||||
case i::wasm::HeapType::kArray:
|
||||
case i::wasm::HeapType::kEq:
|
||||
case i::wasm::HeapType::kString:
|
||||
case i::wasm::HeapType::kStringViewWtf8:
|
||||
case i::wasm::HeapType::kStringViewWtf16:
|
||||
case i::wasm::HeapType::kStringViewIter:
|
||||
default:
|
||||
// TODO(7748): Implement these.
|
||||
UNIMPLEMENTED();
|
||||
|
@ -145,7 +145,7 @@ double WasmGlobalObject::GetF64() {
|
||||
}
|
||||
|
||||
Handle<Object> WasmGlobalObject::GetRef() {
|
||||
// We use this getter for externref and funcref.
|
||||
// We use this getter for externref, funcref, and stringref.
|
||||
DCHECK(type().is_reference());
|
||||
return handle(tagged_buffer().get(offset()), GetIsolate());
|
||||
}
|
||||
@ -181,6 +181,12 @@ bool WasmGlobalObject::SetFuncRef(Isolate* isolate, Handle<Object> value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void WasmGlobalObject::SetStringRef(Handle<Object> value) {
|
||||
DCHECK_EQ(type(), wasm::kWasmStringRef);
|
||||
DCHECK(value->IsNull() || value->IsString());
|
||||
tagged_buffer().set(offset(), *value);
|
||||
}
|
||||
|
||||
// WasmInstanceObject
|
||||
SANDBOXED_POINTER_ACCESSORS(WasmInstanceObject, memory_start, byte*,
|
||||
kMemoryStartOffset)
|
||||
|
@ -303,6 +303,7 @@ class WasmGlobalObject
|
||||
inline void SetF64(double value);
|
||||
inline void SetExternRef(Handle<Object> value);
|
||||
inline bool SetFuncRef(Isolate* isolate, Handle<Object> value);
|
||||
inline void SetStringRef(Handle<Object> value);
|
||||
|
||||
private:
|
||||
// This function returns the address of the global's data in the
|
||||
|
@ -94,6 +94,125 @@ function assertInvalid(fn, message) {
|
||||
TypeError, "type incompatibility when transforming from/to JS");
|
||||
})();
|
||||
|
||||
// TODO(wingo): Test stringref-valued globals (defined and imported).
|
||||
(function TestDefinedGlobals() {
|
||||
let kSig_w_v = makeSig([], [kWasmStringRef]);
|
||||
let kSig_v_w = makeSig([kWasmStringRef], []);
|
||||
let kSig_x_v = makeSig([], [kWasmStringViewWtf8]);
|
||||
let kSig_y_v = makeSig([], [kWasmStringViewWtf16]);
|
||||
let kSig_z_v = makeSig([], [kWasmStringViewIter]);
|
||||
let builder = new WasmModuleBuilder();
|
||||
|
||||
builder.addGlobal(kWasmStringRef, true).exportAs('w');
|
||||
builder.addGlobal(kWasmStringViewWtf8, true).exportAs('x');
|
||||
builder.addGlobal(kWasmStringViewWtf16, true).exportAs('y');
|
||||
builder.addGlobal(kWasmStringViewIter, true).exportAs('z');
|
||||
|
||||
builder.addFunction("get_stringref", kSig_w_v)
|
||||
.exportFunc()
|
||||
.addBody([
|
||||
kExprGlobalGet, 0,
|
||||
]);
|
||||
builder.addFunction("set_stringref", kSig_v_w)
|
||||
.exportFunc()
|
||||
.addBody([
|
||||
kExprLocalGet, 0,
|
||||
kExprGlobalSet, 0
|
||||
]);
|
||||
|
||||
builder.addFunction("get_stringview_wtf8", kSig_x_v)
|
||||
.exportFunc()
|
||||
.addBody([
|
||||
kExprGlobalGet, 1,
|
||||
]);
|
||||
builder.addFunction("get_stringview_wtf16", kSig_y_v)
|
||||
.exportFunc()
|
||||
.addBody([
|
||||
kExprGlobalGet, 2,
|
||||
]);
|
||||
builder.addFunction("get_stringview_iter", kSig_z_v)
|
||||
.exportFunc()
|
||||
.addBody([
|
||||
kExprGlobalGet, 3,
|
||||
]);
|
||||
|
||||
let instance = builder.instantiate()
|
||||
|
||||
assertEquals(null, instance.exports.get_stringref());
|
||||
instance.exports.set_stringref('foo');
|
||||
assertEquals('foo', instance.exports.get_stringref());
|
||||
|
||||
assertEquals('foo', instance.exports.w.value);
|
||||
instance.exports.w.value = 'bar';
|
||||
assertEquals('bar', instance.exports.w.value);
|
||||
assertEquals('bar', instance.exports.get_stringref());
|
||||
|
||||
assertThrows(()=>instance.exports.get_stringview_wtf8(),
|
||||
TypeError, "type incompatibility when transforming from/to JS");
|
||||
assertThrows(()=>instance.exports.get_stringview_wtf16(),
|
||||
TypeError, "type incompatibility when transforming from/to JS");
|
||||
assertThrows(()=>instance.exports.get_stringview_iter(),
|
||||
TypeError, "type incompatibility when transforming from/to JS");
|
||||
|
||||
let unsupportedGlobalMessage = (mode, type) => {
|
||||
return `${mode} WebAssembly.Global.value: ${type} has no JS representation`;
|
||||
}
|
||||
for (let [global, type] of [[instance.exports.x, 'stringview_wtf8'],
|
||||
[instance.exports.y, 'stringview_wtf16'],
|
||||
[instance.exports.z, 'stringview_iter']]) {
|
||||
assertThrows(()=>global.value, TypeError,
|
||||
unsupportedGlobalMessage('get', type));
|
||||
assertThrows(()=>{global.value = null}, TypeError,
|
||||
unsupportedGlobalMessage('set', type));
|
||||
}
|
||||
})();
|
||||
|
||||
(function TestImportedGlobals() {
|
||||
for (let type of ['stringview_wtf8', 'stringview_wtf16',
|
||||
'stringview_iter']) {
|
||||
let msg = "WebAssembly.Global(): Descriptor property 'value' must be" +
|
||||
" a WebAssembly type";
|
||||
|
||||
assertThrows(()=>new WebAssembly.Global({ mutable: true, value: type }),
|
||||
TypeError, msg);
|
||||
assertThrows(()=>new WebAssembly.Global({ mutable: true, value: type },
|
||||
null),
|
||||
TypeError, msg);
|
||||
}
|
||||
|
||||
assertThrows(()=>new WebAssembly.Global({ value: 'stringref' }),
|
||||
TypeError,
|
||||
"WebAssembly.Global(): " +
|
||||
"Missing initial value when creating stringref global");
|
||||
|
||||
let kSig_w_v = makeSig([], [kWasmStringRef]);
|
||||
let kSig_v_w = makeSig([kWasmStringRef], []);
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.addImportedGlobal('env', 'w', kWasmStringRef, true)
|
||||
builder.addFunction("get_stringref", kSig_w_v)
|
||||
.exportFunc()
|
||||
.addBody([
|
||||
kExprGlobalGet, 0,
|
||||
]);
|
||||
builder.addFunction("set_stringref", kSig_v_w)
|
||||
.exportFunc()
|
||||
.addBody([
|
||||
kExprLocalGet, 0,
|
||||
kExprGlobalSet, 0
|
||||
]);
|
||||
|
||||
let w = new WebAssembly.Global({ mutable: true, value: 'stringref' },
|
||||
null);
|
||||
let instance = builder.instantiate({env: {w: w}})
|
||||
|
||||
assertEquals(null, instance.exports.get_stringref());
|
||||
instance.exports.set_stringref('foo');
|
||||
assertEquals('foo', instance.exports.get_stringref());
|
||||
|
||||
assertEquals('foo', w.value);
|
||||
w.value = 'bar';
|
||||
assertEquals('bar', w.value);
|
||||
assertEquals('bar', instance.exports.get_stringref());
|
||||
})();
|
||||
|
||||
// TODO(wingo): Test calls from wasm to JS.
|
||||
// TODO(wingo): Test stringrefs in tables.
|
||||
|
Loading…
Reference in New Issue
Block a user