[wasm-gc] Support non-function ref globals via WebAssembly.Global
Bug: v8:7748 Change-Id: Ibb43799319f8032d69adcaaeebb48ec8e4e6078c Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3869146 Commit-Queue: Matthias Liedtke <mliedtke@chromium.org> Reviewed-by: Manos Koukoutos <manoskouk@chromium.org> Cr-Commit-Position: refs/heads/main@{#82936}
This commit is contained in:
parent
04224d8cb4
commit
2f95d10f6b
@ -1180,6 +1180,7 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
string->StringEquals(v8_str(isolate, "arrayref"))) {
|
||||
type = i::wasm::kWasmArrayRef;
|
||||
} else {
|
||||
// TODO(7748): Add "i31ref".
|
||||
thrower.TypeError(
|
||||
"Descriptor property 'element' must be a WebAssembly reference type");
|
||||
return;
|
||||
@ -1385,8 +1386,15 @@ bool GetValueType(Isolate* isolate, MaybeLocal<Value> maybe,
|
||||
} else if (enabled_features.has_gc() &&
|
||||
string->StringEquals(v8_str(isolate, "anyref"))) {
|
||||
*type = i::wasm::kWasmAnyRef;
|
||||
} else if (enabled_features.has_gc() &&
|
||||
string->StringEquals(v8_str(isolate, "dataref"))) {
|
||||
*type = i::wasm::kWasmDataRef;
|
||||
} else if (enabled_features.has_gc() &&
|
||||
string->StringEquals(v8_str(isolate, "arrayref"))) {
|
||||
*type = i::wasm::kWasmArrayRef;
|
||||
} else {
|
||||
// Unrecognized type.
|
||||
// TODO(7748): Add "i31ref".
|
||||
*type = i::wasm::kWasmVoid;
|
||||
}
|
||||
return true;
|
||||
@ -1432,6 +1440,24 @@ bool ToF64(Local<v8::Value> value, Local<Context> context, double* f64_value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool checkAndUnpackAnyRef(i::Isolate* i_isolate,
|
||||
i::Handle<i::Object>& in_out_value,
|
||||
i::wasm::ValueType type, ErrorThrower& thrower) {
|
||||
const char* error_message = nullptr;
|
||||
auto module = nullptr;
|
||||
bool valid = internal::wasm::TypecheckJSObject(
|
||||
i_isolate, module, in_out_value, type, &error_message);
|
||||
if (!valid) {
|
||||
DCHECK(error_message != nullptr);
|
||||
thrower.TypeError("%s", error_message);
|
||||
return false;
|
||||
}
|
||||
if (!internal::v8_flags.wasm_gc_js_interop) {
|
||||
internal::wasm::TryUnpackObjectWrapper(i_isolate, in_out_value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// WebAssembly.Global
|
||||
@ -1573,6 +1599,7 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
if (!value->IsNull() && !value->IsString()) {
|
||||
thrower.TypeError(
|
||||
"The value of stringref globals must be null or a string");
|
||||
break;
|
||||
}
|
||||
|
||||
global_obj->SetStringRef(Utils::OpenHandle(*value));
|
||||
@ -1584,7 +1611,14 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
case internal::wasm::HeapType::kI31:
|
||||
case internal::wasm::HeapType::kData:
|
||||
case internal::wasm::HeapType::kArray:
|
||||
case internal::wasm::HeapType::kAny:
|
||||
case internal::wasm::HeapType::kAny: {
|
||||
internal::Handle<internal::Object> value_handle =
|
||||
Utils::OpenHandle(*value);
|
||||
if (checkAndUnpackAnyRef(i_isolate, value_handle, type, thrower)) {
|
||||
global_obj->SetAnyRef(value_handle);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case internal::wasm::HeapType::kStringViewWtf8:
|
||||
case internal::wasm::HeapType::kStringViewWtf16:
|
||||
case internal::wasm::HeapType::kStringViewIter:
|
||||
@ -2683,8 +2717,22 @@ void WebAssemblyGlobalGetValueCommon(
|
||||
case i::wasm::HeapType::kI31:
|
||||
case i::wasm::HeapType::kData:
|
||||
case i::wasm::HeapType::kArray:
|
||||
case i::wasm::HeapType::kAny:
|
||||
case i::wasm::HeapType::kEq:
|
||||
case i::wasm::HeapType::kAny: {
|
||||
i::Handle<i::Object> result = receiver->GetRef();
|
||||
if (!i::v8_flags.wasm_gc_js_interop && result->IsWasmObject()) {
|
||||
// Transform wasm object into JS-compliant representation.
|
||||
i::Handle<i::JSObject> wrapper =
|
||||
i_isolate->factory()->NewJSObject(i_isolate->object_function());
|
||||
i::JSObject::AddProperty(
|
||||
i_isolate, wrapper,
|
||||
i_isolate->factory()->wasm_wrapped_object_symbol(), result,
|
||||
i::NONE);
|
||||
result = wrapper;
|
||||
}
|
||||
return_value.Set(Utils::ToLocal(result));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// TODO(7748): Implement these.
|
||||
UNIMPLEMENTED();
|
||||
@ -2805,8 +2853,16 @@ void WebAssemblyGlobalSetValue(
|
||||
case i::wasm::HeapType::kI31:
|
||||
case i::wasm::HeapType::kData:
|
||||
case i::wasm::HeapType::kArray:
|
||||
case i::wasm::HeapType::kAny:
|
||||
case i::wasm::HeapType::kEq:
|
||||
case i::wasm::HeapType::kAny: {
|
||||
internal::Handle<internal::Object> value_handle =
|
||||
Utils::OpenHandle(*args[0]);
|
||||
if (checkAndUnpackAnyRef(i_isolate, value_handle, receiver->type(),
|
||||
thrower)) {
|
||||
receiver->SetAnyRef(value_handle);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// TODO(7748): Implement these.
|
||||
UNIMPLEMENTED();
|
||||
|
@ -171,6 +171,15 @@ void WasmGlobalObject::SetExternRef(Handle<Object> value) {
|
||||
tagged_buffer().set(offset(), *value);
|
||||
}
|
||||
|
||||
void WasmGlobalObject::SetAnyRef(Handle<Object> value) {
|
||||
DCHECK(type().is_reference_to(wasm::HeapType::kAny) ||
|
||||
type().is_reference_to(wasm::HeapType::kEq) ||
|
||||
type().is_reference_to(wasm::HeapType::kData) ||
|
||||
type().is_reference_to(wasm::HeapType::kArray) ||
|
||||
type().is_reference_to(wasm::HeapType::kI31));
|
||||
tagged_buffer().set(offset(), *value);
|
||||
}
|
||||
|
||||
bool WasmGlobalObject::SetFuncRef(Isolate* isolate, Handle<Object> value) {
|
||||
DCHECK_EQ(type(), wasm::kWasmFuncRef);
|
||||
if (value->IsNull() ||
|
||||
|
@ -315,6 +315,7 @@ class WasmGlobalObject
|
||||
inline void SetF32(float value);
|
||||
inline void SetF64(double value);
|
||||
inline void SetExternRef(Handle<Object> value);
|
||||
inline void SetAnyRef(Handle<Object> value);
|
||||
inline bool SetFuncRef(Isolate* isolate, Handle<Object> value);
|
||||
inline void SetStringRef(Handle<Object> value);
|
||||
|
||||
|
@ -283,3 +283,230 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
assertEquals(null, instance.exports.get_string2());
|
||||
assertEquals("Content of any", instance.exports.get_any());
|
||||
})();
|
||||
|
||||
(function TestAnyRefGlobalFromJS() {
|
||||
print(arguments.callee.name);
|
||||
let anyref_global = new WebAssembly.Global(
|
||||
{ value: "anyref", mutable: true }, "initial value");
|
||||
assertEquals("initial value", anyref_global.value);
|
||||
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.addImportedGlobal("imports", "anyref_global", kWasmAnyRef, true);
|
||||
let struct_type = builder.addStruct([makeField(kWasmI32, false)]);
|
||||
let array_type = builder.addArray(kWasmI32);
|
||||
|
||||
builder.addFunction("get_extern", makeSig([], [kWasmExternRef]))
|
||||
.addBody([kExprGlobalGet, 0, kGCPrefix, kExprExternExternalize])
|
||||
.exportFunc();
|
||||
builder.addFunction("get_struct_val", makeSig([], [kWasmI32]))
|
||||
.addBody([
|
||||
kExprGlobalGet, 0,
|
||||
kGCPrefix, kExprRefAsData,
|
||||
kGCPrefix, kExprRefCast, struct_type,
|
||||
kGCPrefix, kExprStructGet, struct_type, 0,
|
||||
])
|
||||
.exportFunc();
|
||||
builder.addFunction("get_array_val", makeSig([], [kWasmI32]))
|
||||
.addBody([
|
||||
kExprGlobalGet, 0,
|
||||
kGCPrefix, kExprRefAsData,
|
||||
kGCPrefix, kExprRefCast, array_type,
|
||||
kExprI32Const, 0,
|
||||
kGCPrefix, kExprArrayGet, array_type,
|
||||
])
|
||||
.exportFunc();
|
||||
builder.addFunction("create_struct", makeSig([kWasmI32], [kWasmExternRef]))
|
||||
.addBody([
|
||||
kExprLocalGet, 0,
|
||||
kGCPrefix, kExprStructNew, struct_type,
|
||||
kGCPrefix, kExprExternExternalize])
|
||||
.exportFunc();
|
||||
builder.addFunction("create_array", makeSig([kWasmI32], [kWasmExternRef]))
|
||||
.addBody([
|
||||
kExprLocalGet, 0,
|
||||
kGCPrefix, kExprArrayNewFixed, array_type, 1,
|
||||
kGCPrefix, kExprExternExternalize])
|
||||
.exportFunc();
|
||||
|
||||
let instance = builder.instantiate({imports : {anyref_global}});
|
||||
let wasm = instance.exports;
|
||||
|
||||
anyref_global.value = "Set anyref from string";
|
||||
assertEquals("Set anyref from string", anyref_global.value);
|
||||
assertEquals("Set anyref from string", wasm.get_extern());
|
||||
anyref_global.value = wasm.create_struct(42);
|
||||
assertEquals(42, wasm.get_struct_val());
|
||||
anyref_global.value = wasm.create_array(43);
|
||||
assertEquals(43, wasm.get_array_val());
|
||||
anyref_global.value = null;
|
||||
assertEquals(null, anyref_global.value);
|
||||
assertEquals(null, wasm.get_extern());
|
||||
anyref_global.value = 12345;
|
||||
assertEquals(12345, wasm.get_extern());
|
||||
|
||||
assertThrows(() => anyref_global.value = {}, TypeError);
|
||||
assertThrows(() => anyref_global.value = undefined, TypeError);
|
||||
})();
|
||||
|
||||
(function TestEqRefGlobalFromJS() {
|
||||
print(arguments.callee.name);
|
||||
let eqref_global = new WebAssembly.Global(
|
||||
{ value: "eqref", mutable: true }, null);
|
||||
assertEquals(null, eqref_global.value);
|
||||
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.addImportedGlobal("imports", "eqref_global", kWasmEqRef, true);
|
||||
let struct_type = builder.addStruct([makeField(kWasmI32, false)]);
|
||||
let array_type = builder.addArray(kWasmI32);
|
||||
|
||||
builder.addFunction("get_extern", makeSig([], [kWasmExternRef]))
|
||||
.addBody([kExprGlobalGet, 0, kGCPrefix, kExprExternExternalize])
|
||||
.exportFunc();
|
||||
builder.addFunction("get_struct_val", makeSig([], [kWasmI32]))
|
||||
.addBody([
|
||||
kExprGlobalGet, 0,
|
||||
kGCPrefix, kExprRefAsData,
|
||||
kGCPrefix, kExprRefCast, struct_type,
|
||||
kGCPrefix, kExprStructGet, struct_type, 0,
|
||||
])
|
||||
.exportFunc();
|
||||
builder.addFunction("get_array_val", makeSig([], [kWasmI32]))
|
||||
.addBody([
|
||||
kExprGlobalGet, 0,
|
||||
kGCPrefix, kExprRefAsData,
|
||||
kGCPrefix, kExprRefCast, array_type,
|
||||
kExprI32Const, 0,
|
||||
kGCPrefix, kExprArrayGet, array_type,
|
||||
])
|
||||
.exportFunc();
|
||||
builder.addFunction("create_struct", makeSig([kWasmI32], [kWasmExternRef]))
|
||||
.addBody([
|
||||
kExprLocalGet, 0,
|
||||
kGCPrefix, kExprStructNew, struct_type,
|
||||
kGCPrefix, kExprExternExternalize])
|
||||
.exportFunc();
|
||||
builder.addFunction("create_array", makeSig([kWasmI32], [kWasmExternRef]))
|
||||
.addBody([
|
||||
kExprLocalGet, 0,
|
||||
kGCPrefix, kExprArrayNewFixed, array_type, 1,
|
||||
kGCPrefix, kExprExternExternalize])
|
||||
.exportFunc();
|
||||
|
||||
let instance = builder.instantiate({imports : {eqref_global}});
|
||||
let wasm = instance.exports;
|
||||
|
||||
eqref_global.value = wasm.create_struct(42);
|
||||
assertEquals(42, wasm.get_struct_val());
|
||||
eqref_global.value = wasm.create_array(43);
|
||||
assertEquals(43, wasm.get_array_val());
|
||||
eqref_global.value = null;
|
||||
assertEquals(null, eqref_global.value);
|
||||
assertEquals(null, wasm.get_extern());
|
||||
eqref_global.value = 12345;
|
||||
assertEquals(12345, wasm.get_extern());
|
||||
|
||||
assertThrows(() => eqref_global.value = {}, TypeError);
|
||||
assertThrows(() => eqref_global.value = undefined, TypeError);
|
||||
assertThrows(() => eqref_global.value = "string", TypeError);
|
||||
})();
|
||||
|
||||
(function TestDataRefGlobalFromJS() {
|
||||
print(arguments.callee.name);
|
||||
let dataref_global = new WebAssembly.Global(
|
||||
{ value: "dataref", mutable: true }, null);
|
||||
assertNull(dataref_global.value);
|
||||
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.addImportedGlobal("imports", "dataref_global", kWasmDataRef, true);
|
||||
let struct_type = builder.addStruct([makeField(kWasmI32, false)]);
|
||||
let array_type = builder.addArray(kWasmI32);
|
||||
|
||||
builder.addFunction("get_struct_val", makeSig([], [kWasmI32]))
|
||||
.addBody([
|
||||
kExprGlobalGet, 0,
|
||||
kGCPrefix, kExprRefAsData,
|
||||
kGCPrefix, kExprRefCast, struct_type,
|
||||
kGCPrefix, kExprStructGet, struct_type, 0,
|
||||
])
|
||||
.exportFunc();
|
||||
builder.addFunction("get_array_val", makeSig([], [kWasmI32]))
|
||||
.addBody([
|
||||
kExprGlobalGet, 0,
|
||||
kGCPrefix, kExprRefAsData,
|
||||
kGCPrefix, kExprRefCast, array_type,
|
||||
kExprI32Const, 0,
|
||||
kGCPrefix, kExprArrayGet, array_type,
|
||||
])
|
||||
.exportFunc();
|
||||
builder.addFunction("create_struct", makeSig([kWasmI32], [kWasmExternRef]))
|
||||
.addBody([
|
||||
kExprLocalGet, 0,
|
||||
kGCPrefix, kExprStructNew, struct_type,
|
||||
kGCPrefix, kExprExternExternalize])
|
||||
.exportFunc();
|
||||
builder.addFunction("create_array", makeSig([kWasmI32], [kWasmExternRef]))
|
||||
.addBody([
|
||||
kExprLocalGet, 0,
|
||||
kGCPrefix, kExprArrayNewFixed, array_type, 1,
|
||||
kGCPrefix, kExprExternExternalize])
|
||||
.exportFunc();
|
||||
|
||||
let instance = builder.instantiate({imports : {dataref_global}});
|
||||
let wasm = instance.exports;
|
||||
|
||||
dataref_global.value = wasm.create_struct(42);
|
||||
assertEquals(42, wasm.get_struct_val());
|
||||
dataref_global.value = wasm.create_array(43);
|
||||
assertEquals(43, wasm.get_array_val());
|
||||
dataref_global.value = null;
|
||||
assertEquals(null, dataref_global.value);
|
||||
|
||||
assertThrows(() => dataref_global.value = undefined, TypeError);
|
||||
assertThrows(() => dataref_global.value = "string", TypeError);
|
||||
})();
|
||||
|
||||
(function TestArrayRefGlobalFromJS() {
|
||||
print(arguments.callee.name);
|
||||
let arrayref_global = new WebAssembly.Global(
|
||||
{ value: "arrayref", mutable: true }, null);
|
||||
assertNull(arrayref_global.value);
|
||||
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.addImportedGlobal("imports", "arrayref_global", kWasmArrayRef, true);
|
||||
let struct_type = builder.addStruct([makeField(kWasmI32, false)]);
|
||||
let array_type = builder.addArray(kWasmI32);
|
||||
|
||||
builder.addFunction("get_array_val", makeSig([], [kWasmI32]))
|
||||
.addBody([
|
||||
kExprGlobalGet, 0,
|
||||
kGCPrefix, kExprRefAsData,
|
||||
kGCPrefix, kExprRefCast, array_type,
|
||||
kExprI32Const, 0,
|
||||
kGCPrefix, kExprArrayGet, array_type,
|
||||
])
|
||||
.exportFunc();
|
||||
builder.addFunction("create_struct", makeSig([kWasmI32], [kWasmExternRef]))
|
||||
.addBody([
|
||||
kExprLocalGet, 0,
|
||||
kGCPrefix, kExprStructNew, struct_type,
|
||||
kGCPrefix, kExprExternExternalize])
|
||||
.exportFunc();
|
||||
builder.addFunction("create_array", makeSig([kWasmI32], [kWasmExternRef]))
|
||||
.addBody([
|
||||
kExprLocalGet, 0,
|
||||
kGCPrefix, kExprArrayNewFixed, array_type, 1,
|
||||
kGCPrefix, kExprExternExternalize])
|
||||
.exportFunc();
|
||||
|
||||
let instance = builder.instantiate({imports : {arrayref_global}});
|
||||
let wasm = instance.exports;
|
||||
|
||||
arrayref_global.value = wasm.create_array(43);
|
||||
assertEquals(43, wasm.get_array_val());
|
||||
arrayref_global.value = null;
|
||||
assertEquals(null, arrayref_global.value);
|
||||
|
||||
assertThrows(() => arrayref_global.value = undefined, TypeError);
|
||||
assertThrows(() => arrayref_global.value = "string", TypeError);
|
||||
assertThrows(() => arrayref_global.value = wasm.create_struct(1), TypeError);
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user