Commit 8df26597 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by V8 LUCI CQ

[wasm-gc] Fixes for the JS/Wasm boundary

- i31s should not be packed in {WasmWrapperGraphBuilder::ToJS}.
- anyref should be able to hold any JS value (except null if non
  nullable).
- Restructure TypeCheckJSObject.

Bug: v8:7748
Change-Id: I51ab6b84e89a70e565ce56de7a41f8693aa28e5b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3871073Reviewed-by: 's avatarMatthias Liedtke <mliedtke@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82992}
parent 6811cb9f
......@@ -6304,7 +6304,19 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
WasmInternalFunction::kExternalOffset));
}
}
case wasm::HeapType::kEq:
case wasm::HeapType::kEq: {
// TODO(7748): Update this when JS interop is settled.
auto done = gasm_->MakeLabel(MachineRepresentation::kTaggedPointer);
// Do not wrap i31s.
gasm_->GotoIf(IsSmi(node), &done, node);
if (type.kind() == wasm::kRefNull) {
// Do not wrap {null}.
gasm_->GotoIf(IsNull(node), &done, node);
}
gasm_->Goto(&done, BuildAllocateObjectWrapper(node, context));
gasm_->Bind(&done);
return done.PhiAt(0);
}
case wasm::HeapType::kData:
case wasm::HeapType::kArray:
// TODO(7748): Update this when JS interop is settled.
......
......@@ -2334,9 +2334,10 @@ Handle<AsmWasmData> AsmWasmData::New(
namespace wasm {
bool TryUnpackObjectWrapper(Isolate* isolate, Handle<Object>& in_out_value) {
if (in_out_value->IsUndefined(isolate)) return false;
if (in_out_value->IsNull(isolate)) return true;
if (!in_out_value->IsJSObject()) return false;
if (in_out_value->IsUndefined(isolate) || in_out_value->IsNull(isolate) ||
!in_out_value->IsJSObject()) {
return false;
}
Handle<Name> key = isolate->factory()->wasm_wrapped_object_symbol();
LookupIterator it(isolate, in_out_value, key,
LookupIterator::OWN_SKIP_INTERCEPTOR);
......@@ -2345,6 +2346,8 @@ bool TryUnpackObjectWrapper(Isolate* isolate, Handle<Object>& in_out_value) {
return true;
}
// TODO(7748): Unify this with transforming from JS to wasm representation, and
// use it as the single interface for the JS->wasm boundary.
bool TypecheckJSObject(Isolate* isolate, const WasmModule* module,
Handle<Object> value, ValueType expected,
const char** error_message) {
......@@ -2369,6 +2372,10 @@ bool TypecheckJSObject(Isolate* isolate, const WasmModule* module,
}
V8_FALLTHROUGH;
case kRef: {
// TODO(7748): Follow any changes in proposed JS API. In particular,
// finalize the v8_flags.wasm_gc_js_interop situation.
// TODO(7748): Allow all in-range numbers for i31.
// TODO(7748): Streamline interaction of undefined and (ref any).
HeapType::Representation repr = expected.heap_representation();
switch (repr) {
case HeapType::kFunc: {
......@@ -2382,44 +2389,54 @@ bool TypecheckJSObject(Isolate* isolate, const WasmModule* module,
return true;
}
case HeapType::kExtern:
return true;
case HeapType::kData:
case HeapType::kArray:
if (!value->IsNull(isolate)) return true;
*error_message = "null is not allowed for (ref extern)";
return false;
case HeapType::kAny:
case HeapType::kEq:
case HeapType::kI31: {
// TODO(7748): Change this when we have a decision on the JS API for
// structs/arrays.
// TODO(7748): Reiterate isSmi() check for i31refs once spec work is
// done: Probably all JS number objects shall be allowed if
// representable as a 31 bit SMI.
if (!v8_flags.wasm_gc_js_interop) {
if (!value->IsSmi() && !value->IsString() &&
!TryUnpackObjectWrapper(isolate, value)) {
TryUnpackObjectWrapper(isolate, value);
}
if (!value->IsNull(isolate)) return true;
*error_message = "null is not allowed for (ref any)";
return false;
case HeapType::kData: {
if (v8_flags.wasm_gc_js_interop
? value->IsWasmStruct() || value->IsWasmArray()
: TryUnpackObjectWrapper(isolate, value)) {
return true;
}
*error_message =
"eqref/dataref/i31ref object must be null (if nullable) or "
"wrapped with the wasm object wrapper";
"dataref object must be null (if nullable) or a wasm "
"struct/array";
return false;
}
case HeapType::kArray: {
if ((v8_flags.wasm_gc_js_interop ||
TryUnpackObjectWrapper(isolate, value)) &&
value->IsWasmArray()) {
return true;
}
if (repr == HeapType::kI31) {
if (!value->IsSmi()) {
*error_message = "i31ref-typed object cannot be a heap object";
*error_message =
"arrayref object must be null (if nullable) or a wasm array";
return false;
}
case HeapType::kEq: {
if (value->IsSmi() ||
(v8_flags.wasm_gc_js_interop
? value->IsWasmStruct() || value->IsWasmArray()
: TryUnpackObjectWrapper(isolate, value))) {
return true;
}
if (!(((repr == HeapType::kEq || repr == HeapType::kAny) &&
value->IsSmi()) ||
(repr == HeapType::kAny && value->IsString()) ||
(repr != HeapType::kArray && value->IsWasmStruct()) ||
value->IsWasmArray())) {
*error_message = "object incompatible with wasm type";
*error_message =
"eqref object must be null (if nullable) or a wasm "
"i31/struct/array";
return false;
}
return true;
case HeapType::kI31: {
if (value->IsSmi()) return true;
*error_message =
"i31ref object must be null (if nullable) or a wasm i31";
return false;
}
case HeapType::kString:
if (value->IsString()) return true;
......@@ -2525,11 +2542,6 @@ bool TypecheckJSObject(Isolate* isolate, const WasmModule* module,
}
}
case kRtt:
// TODO(7748): Implement when the JS API for rtts is decided on.
*error_message =
"passing rtts between Webassembly and Javascript is not supported "
"yet.";
return false;
case kI8:
case kI16:
case kI32:
......
......@@ -344,8 +344,12 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
anyref_global.value = 12345;
assertEquals(12345, wasm.get_extern());
assertThrows(() => anyref_global.value = {}, TypeError);
assertThrows(() => anyref_global.value = undefined, TypeError);
let o = {};
anyref_global.value = o;
assertEquals(o, anyref_global.value);
assertEquals(o, wasm.get_extern());
anyref_global.value = undefined;
assertEquals(undefined, anyref_global.value);
})();
(function TestEqRefGlobalFromJS() {
......
......@@ -284,8 +284,8 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
/Argument 1 must be specified for non-nullable element type/);
wasmTable.grow(1, instance.exports.create_struct(33));
assertEquals(33, instance.exports.struct_getter(4));
assertThrows(() => wasmTable.set(4, undefined), TypeError,
/Argument 1 is invalid/);
// undefined is ok for (ref any), but not null.
wasmTable.set(4, undefined);
assertThrows(() => wasmTable.set(4, null), TypeError,
/Argument 1 is invalid/);
})();
......
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