Commit 799421d5 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[wasm-gc] Temporary exposure of Wasm objects to JS

This is a stop-gap solution (while we wait for a proper spec)
that lets managed WasmGC objects perform round-trips through
JavaScript. On the JavaScript side, they appear as empty/opaque.

Bug: v8:7748
Change-Id: I0dd368bc14d622f3ef41871484228267359e9b5b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2316306
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69207}
parent c19e57ee
......@@ -423,6 +423,7 @@ extern macro ToStringStringConstant(): String;
extern macro TrueConstant(): True;
extern macro UndefinedConstant(): Undefined;
extern macro ValueOfStringConstant(): String;
extern macro WasmWrappedObjectSymbolConstant(): Symbol;
const TheHole: TheHole = TheHoleConstant();
const Null: Null = NullConstant();
......
......@@ -261,6 +261,19 @@ builtin WasmIsRttSubtype(implicit context: Context)(sub: Map, super: Map): Smi {
unreachable;
}
// Redeclaration with different typing (value is an Object, not JSAny).
extern transitioning runtime
CreateDataProperty(implicit context: Context)(JSReceiver, JSAny, Object);
transitioning builtin WasmAllocateObjectWrapper(implicit context: Context)(
obj: Object): JSObject {
// Note: {obj} can be null, or i31ref. The code below is agnostic to that.
const wrapper = NewJSObject();
const symbol = WasmWrappedObjectSymbolConstant();
CreateDataProperty(wrapper, symbol, obj);
return wrapper;
}
builtin WasmInt32ToNumber(value: int32): Number {
return ChangeInt32ToTagged(value);
}
......
......@@ -200,6 +200,8 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
V(UndefinedValue, undefined_value, Undefined) \
V(uninitialized_symbol, uninitialized_symbol, UninitializedSymbol) \
V(valueOf_string, valueOf_string, ValueOfString) \
V(wasm_wrapped_object_symbol, wasm_wrapped_object_symbol, \
WasmWrappedObjectSymbol) \
V(zero_string, zero_string, ZeroString) \
UNIQUE_INSTANCE_TYPE_MAP_LIST_GENERATOR( \
UNIQUE_INSTANCE_TYPE_IMMUTABLE_IMMOVABLE_MAP_ADAPTER, V)
......
......@@ -5877,6 +5877,9 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
representation == wasm::HeapType::kFunc) {
return node;
}
if (representation == wasm::HeapType::kEq) {
return BuildAllocateObjectWrapper(node);
}
// TODO(7748): Figure out a JS interop story for arrays and structs.
// If this is reached, then IsJSCompatibleSignature() is too permissive.
UNREACHABLE();
......@@ -5892,6 +5895,34 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
}
}
// TODO(7748): Temporary solution to allow round-tripping of Wasm objects
// through JavaScript, where they show up as opaque boxes. This will disappear
// once we have a proper WasmGC <-> JS interaction story.
Node* BuildAllocateObjectWrapper(Node* input) {
return CALL_BUILTIN(
WasmAllocateObjectWrapper, input,
LOAD_INSTANCE_FIELD(NativeContext, MachineType::TaggedPointer()));
}
Node* BuildUnpackObjectWrapper(Node* input) {
Node* obj = CALL_BUILTIN(
WasmGetOwnProperty, input,
LOAD_FULL_POINTER(BuildLoadIsolateRoot(),
IsolateData::root_slot_offset(
RootIndex::kwasm_wrapped_object_symbol)),
LOAD_INSTANCE_FIELD(NativeContext, MachineType::TaggedPointer()));
// Invalid object wrappers (i.e. any other JS object that doesn't have the
// magic hidden property) will return {undefined}. Map that to {null}.
Node* undefined = LOAD_FULL_POINTER(
BuildLoadIsolateRoot(),
IsolateData::root_slot_offset(RootIndex::kUndefinedValue));
Node* is_undefined = gasm_->WordEqual(obj, undefined);
Diamond check(graph(), mcgraph()->common(), is_undefined,
BranchHint::kFalse);
check.Chain(control());
return check.Phi(MachineRepresentation::kTagged, RefNull(), obj);
}
Node* BuildChangeInt64ToBigInt(Node* input) {
const Operator* call =
mcgraph()->common()->Call(GetI64ToBigIntCallDescriptor());
......@@ -5961,6 +5992,8 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
return input;
}
case wasm::HeapType::kEq:
return BuildUnpackObjectWrapper(input);
default:
// If this is reached, then IsJSCompatibleSignature() is too
// permissive.
......
......@@ -365,6 +365,7 @@
V(_, wasm_exception_tag_symbol) \
V(_, wasm_exception_values_symbol) \
V(_, wasm_uncatchable_symbol) \
V(_, wasm_wrapped_object_symbol) \
V(_, uninitialized_symbol)
#define PUBLIC_SYMBOL_LIST_GENERATOR(V, _) \
......
......@@ -1219,6 +1219,9 @@ bool GetValueType(Isolate* isolate, MaybeLocal<Value> maybe,
} else if (enabled_features.has_eh() &&
string->StringEquals(v8_str(isolate, "exnref"))) {
*type = i::wasm::kWasmExnRef;
} else if (enabled_features.has_gc() &&
string->StringEquals(v8_str(isolate, "eqref"))) {
*type = i::wasm::kWasmEqRef;
} else {
// Unrecognized type.
*type = i::wasm::kWasmStmt;
......
......@@ -46,7 +46,8 @@ bool IsJSCompatibleSignature(const FunctionSig* sig,
// allow them here.
if (!(representation == HeapType::kExtern ||
representation == HeapType::kExn ||
representation == HeapType::kFunc)) {
representation == HeapType::kFunc ||
representation == HeapType::kEq)) {
return false;
}
}
......
......@@ -58,6 +58,22 @@ class WasmGCTester {
return fun->func_index();
}
void DefineExportedFunction(const char* name, FunctionSig* sig,
std::initializer_list<byte> code) {
WasmFunctionBuilder* fun = builder_.AddFunction(sig);
fun->EmitCode(code.begin(), static_cast<uint32_t>(code.size()));
builder_.AddExport(CStrVector(name), fun);
}
MaybeHandle<Object> CallExportedFunction(const char* name, int argc,
Handle<Object> args[]) {
Handle<WasmExportedFunction> func =
testing::GetExportedFunction(isolate_, instance_, name)
.ToHandleChecked();
return Execution::Call(isolate_, func,
isolate_->factory()->undefined_value(), argc, args);
}
uint32_t DefineStruct(std::initializer_list<F> fields) {
StructType::Builder type_builder(&zone,
static_cast<uint32_t>(fields.size()));
......@@ -880,29 +896,62 @@ TEST(I31Casts) {
tester.CheckHasThrown(kCastStructToI31, 0);
}
TEST(JsAccessDisallowed) {
TEST(JsAccess) {
WasmGCTester tester;
uint32_t type_index = tester.DefineStruct({F(wasm::kWasmI32, true)});
ValueType kRefTypes[] = {ref(type_index)};
FunctionSig sig_q_v(1, 0, kRefTypes);
WasmFunctionBuilder* fun = tester.builder()->AddFunction(&sig_q_v);
byte code[] = {WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(42),
ValueType kEqRefTypes[] = {kWasmEqRef};
ValueType kEqToI[] = {kWasmI32, kWasmEqRef};
FunctionSig sig_t_v(1, 0, kRefTypes);
FunctionSig sig_q_v(1, 0, kEqRefTypes);
FunctionSig sig_i_q(1, 1, kEqToI);
tester.DefineExportedFunction(
"disallowed", &sig_t_v,
{WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(42),
WASM_RTT_CANON(type_index)),
kExprEnd};
fun->EmitCode(code, sizeof(code));
tester.builder()->AddExport(CStrVector("f"), fun);
kExprEnd});
// Same code, different signature.
tester.DefineExportedFunction(
"producer", &sig_q_v,
{WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(42),
WASM_RTT_CANON(type_index)),
kExprEnd});
tester.DefineExportedFunction(
"consumer", &sig_i_q,
{WASM_STRUCT_GET(type_index, 0,
WASM_REF_CAST(kLocalEqRef, type_index, WASM_GET_LOCAL(0),
WASM_RTT_CANON(type_index))),
kExprEnd});
tester.CompileModule();
TryCatch try_catch(reinterpret_cast<v8::Isolate*>(tester.isolate()));
MaybeHandle<WasmExportedFunction> exported =
testing::GetExportedFunction(tester.isolate(), tester.instance(), "f");
CHECK(!exported.is_null());
CHECK(!try_catch.HasCaught());
MaybeHandle<Object> result = Execution::Call(
tester.isolate(), exported.ToHandleChecked(),
tester.isolate()->factory()->undefined_value(), 0, nullptr);
CHECK(result.is_null());
Isolate* isolate = tester.isolate();
TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
MaybeHandle<Object> maybe_result =
tester.CallExportedFunction("disallowed", 0, nullptr);
CHECK(maybe_result.is_null());
CHECK(try_catch.HasCaught());
try_catch.Reset();
isolate->clear_pending_exception();
maybe_result = tester.CallExportedFunction("producer", 0, nullptr);
{
Handle<Object> args[] = {maybe_result.ToHandleChecked()};
maybe_result = tester.CallExportedFunction("consumer", 1, args);
}
Handle<Object> result = maybe_result.ToHandleChecked();
CHECK(result->IsSmi());
CHECK_EQ(42, Smi::cast(*result).value());
// Calling {consumer} with any other object (e.g. the Smi we just got as
// {result}) should trap.
{
Handle<Object> args[] = {result};
maybe_result = tester.CallExportedFunction("consumer", 1, args);
}
CHECK(maybe_result.is_null());
CHECK(try_catch.HasCaught());
try_catch.Reset();
isolate->clear_pending_exception();
}
} // namespace test_gc
......
......@@ -298,65 +298,65 @@ KNOWN_MAPS = {
("read_only_space", 0x0319d): (96, "EnumCacheMap"),
("read_only_space", 0x031ed): (87, "ArrayBoilerplateDescriptionMap"),
("read_only_space", 0x032d9): (99, "InterceptorInfoMap"),
("read_only_space", 0x053b9): (72, "PromiseFulfillReactionJobTaskMap"),
("read_only_space", 0x053e1): (73, "PromiseRejectReactionJobTaskMap"),
("read_only_space", 0x05409): (74, "CallableTaskMap"),
("read_only_space", 0x05431): (75, "CallbackTaskMap"),
("read_only_space", 0x05459): (76, "PromiseResolveThenableJobTaskMap"),
("read_only_space", 0x05481): (79, "FunctionTemplateInfoMap"),
("read_only_space", 0x054a9): (80, "ObjectTemplateInfoMap"),
("read_only_space", 0x054d1): (81, "AccessCheckInfoMap"),
("read_only_space", 0x054f9): (82, "AccessorInfoMap"),
("read_only_space", 0x05521): (83, "AccessorPairMap"),
("read_only_space", 0x05549): (84, "AliasedArgumentsEntryMap"),
("read_only_space", 0x05571): (85, "AllocationMementoMap"),
("read_only_space", 0x05599): (88, "AsmWasmDataMap"),
("read_only_space", 0x055c1): (89, "AsyncGeneratorRequestMap"),
("read_only_space", 0x055e9): (90, "BreakPointMap"),
("read_only_space", 0x05611): (91, "BreakPointInfoMap"),
("read_only_space", 0x05639): (92, "CachedTemplateObjectMap"),
("read_only_space", 0x05661): (94, "ClassPositionsMap"),
("read_only_space", 0x05689): (95, "DebugInfoMap"),
("read_only_space", 0x056b1): (98, "FunctionTemplateRareDataMap"),
("read_only_space", 0x056d9): (100, "InterpreterDataMap"),
("read_only_space", 0x05701): (101, "PromiseCapabilityMap"),
("read_only_space", 0x05729): (102, "PromiseReactionMap"),
("read_only_space", 0x05751): (103, "PropertyDescriptorObjectMap"),
("read_only_space", 0x05779): (104, "PrototypeInfoMap"),
("read_only_space", 0x057a1): (105, "ScriptMap"),
("read_only_space", 0x057c9): (106, "SourceTextModuleInfoEntryMap"),
("read_only_space", 0x057f1): (107, "StackFrameInfoMap"),
("read_only_space", 0x05819): (108, "StackTraceFrameMap"),
("read_only_space", 0x05841): (109, "TemplateObjectDescriptionMap"),
("read_only_space", 0x05869): (110, "Tuple2Map"),
("read_only_space", 0x05891): (111, "WasmCapiFunctionDataMap"),
("read_only_space", 0x058b9): (112, "WasmExceptionTagMap"),
("read_only_space", 0x058e1): (113, "WasmExportedFunctionDataMap"),
("read_only_space", 0x05909): (114, "WasmIndirectFunctionTableMap"),
("read_only_space", 0x05931): (115, "WasmJSFunctionDataMap"),
("read_only_space", 0x05959): (116, "WasmValueMap"),
("read_only_space", 0x05981): (136, "SloppyArgumentsElementsMap"),
("read_only_space", 0x059a9): (172, "OnHeapBasicBlockProfilerDataMap"),
("read_only_space", 0x059d1): (169, "InternalClassMap"),
("read_only_space", 0x059f9): (178, "SmiPairMap"),
("read_only_space", 0x05a21): (177, "SmiBoxMap"),
("read_only_space", 0x05a49): (147, "ExportedSubClassBaseMap"),
("read_only_space", 0x05a71): (148, "ExportedSubClassMap"),
("read_only_space", 0x05a99): (68, "AbstractInternalClassSubclass1Map"),
("read_only_space", 0x05ac1): (69, "AbstractInternalClassSubclass2Map"),
("read_only_space", 0x05ae9): (135, "InternalClassWithSmiElementsMap"),
("read_only_space", 0x05b11): (170, "InternalClassWithStructElementsMap"),
("read_only_space", 0x05b39): (149, "ExportedSubClass2Map"),
("read_only_space", 0x05b61): (179, "SortStateMap"),
("read_only_space", 0x05b89): (86, "AllocationSiteWithWeakNextMap"),
("read_only_space", 0x05bb1): (86, "AllocationSiteWithoutWeakNextMap"),
("read_only_space", 0x05bd9): (77, "LoadHandler1Map"),
("read_only_space", 0x05c01): (77, "LoadHandler2Map"),
("read_only_space", 0x05c29): (77, "LoadHandler3Map"),
("read_only_space", 0x05c51): (78, "StoreHandler0Map"),
("read_only_space", 0x05c79): (78, "StoreHandler1Map"),
("read_only_space", 0x05ca1): (78, "StoreHandler2Map"),
("read_only_space", 0x05cc9): (78, "StoreHandler3Map"),
("read_only_space", 0x053c9): (72, "PromiseFulfillReactionJobTaskMap"),
("read_only_space", 0x053f1): (73, "PromiseRejectReactionJobTaskMap"),
("read_only_space", 0x05419): (74, "CallableTaskMap"),
("read_only_space", 0x05441): (75, "CallbackTaskMap"),
("read_only_space", 0x05469): (76, "PromiseResolveThenableJobTaskMap"),
("read_only_space", 0x05491): (79, "FunctionTemplateInfoMap"),
("read_only_space", 0x054b9): (80, "ObjectTemplateInfoMap"),
("read_only_space", 0x054e1): (81, "AccessCheckInfoMap"),
("read_only_space", 0x05509): (82, "AccessorInfoMap"),
("read_only_space", 0x05531): (83, "AccessorPairMap"),
("read_only_space", 0x05559): (84, "AliasedArgumentsEntryMap"),
("read_only_space", 0x05581): (85, "AllocationMementoMap"),
("read_only_space", 0x055a9): (88, "AsmWasmDataMap"),
("read_only_space", 0x055d1): (89, "AsyncGeneratorRequestMap"),
("read_only_space", 0x055f9): (90, "BreakPointMap"),
("read_only_space", 0x05621): (91, "BreakPointInfoMap"),
("read_only_space", 0x05649): (92, "CachedTemplateObjectMap"),
("read_only_space", 0x05671): (94, "ClassPositionsMap"),
("read_only_space", 0x05699): (95, "DebugInfoMap"),
("read_only_space", 0x056c1): (98, "FunctionTemplateRareDataMap"),
("read_only_space", 0x056e9): (100, "InterpreterDataMap"),
("read_only_space", 0x05711): (101, "PromiseCapabilityMap"),
("read_only_space", 0x05739): (102, "PromiseReactionMap"),
("read_only_space", 0x05761): (103, "PropertyDescriptorObjectMap"),
("read_only_space", 0x05789): (104, "PrototypeInfoMap"),
("read_only_space", 0x057b1): (105, "ScriptMap"),
("read_only_space", 0x057d9): (106, "SourceTextModuleInfoEntryMap"),
("read_only_space", 0x05801): (107, "StackFrameInfoMap"),
("read_only_space", 0x05829): (108, "StackTraceFrameMap"),
("read_only_space", 0x05851): (109, "TemplateObjectDescriptionMap"),
("read_only_space", 0x05879): (110, "Tuple2Map"),
("read_only_space", 0x058a1): (111, "WasmCapiFunctionDataMap"),
("read_only_space", 0x058c9): (112, "WasmExceptionTagMap"),
("read_only_space", 0x058f1): (113, "WasmExportedFunctionDataMap"),
("read_only_space", 0x05919): (114, "WasmIndirectFunctionTableMap"),
("read_only_space", 0x05941): (115, "WasmJSFunctionDataMap"),
("read_only_space", 0x05969): (116, "WasmValueMap"),
("read_only_space", 0x05991): (136, "SloppyArgumentsElementsMap"),
("read_only_space", 0x059b9): (172, "OnHeapBasicBlockProfilerDataMap"),
("read_only_space", 0x059e1): (169, "InternalClassMap"),
("read_only_space", 0x05a09): (178, "SmiPairMap"),
("read_only_space", 0x05a31): (177, "SmiBoxMap"),
("read_only_space", 0x05a59): (147, "ExportedSubClassBaseMap"),
("read_only_space", 0x05a81): (148, "ExportedSubClassMap"),
("read_only_space", 0x05aa9): (68, "AbstractInternalClassSubclass1Map"),
("read_only_space", 0x05ad1): (69, "AbstractInternalClassSubclass2Map"),
("read_only_space", 0x05af9): (135, "InternalClassWithSmiElementsMap"),
("read_only_space", 0x05b21): (170, "InternalClassWithStructElementsMap"),
("read_only_space", 0x05b49): (149, "ExportedSubClass2Map"),
("read_only_space", 0x05b71): (179, "SortStateMap"),
("read_only_space", 0x05b99): (86, "AllocationSiteWithWeakNextMap"),
("read_only_space", 0x05bc1): (86, "AllocationSiteWithoutWeakNextMap"),
("read_only_space", 0x05be9): (77, "LoadHandler1Map"),
("read_only_space", 0x05c11): (77, "LoadHandler2Map"),
("read_only_space", 0x05c39): (77, "LoadHandler3Map"),
("read_only_space", 0x05c61): (78, "StoreHandler0Map"),
("read_only_space", 0x05c89): (78, "StoreHandler1Map"),
("read_only_space", 0x05cb1): (78, "StoreHandler2Map"),
("read_only_space", 0x05cd9): (78, "StoreHandler3Map"),
("map_space", 0x0211d): (1057, "ExternalMap"),
("map_space", 0x02145): (1072, "JSMessageObjectMap"),
("map_space", 0x0216d): (181, "WasmRttEqrefMap"),
......
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