[wasm-gc] Add callback for Wasm GC origin trial

The callback can be used to enable / disable Wasm GC from Chrome or
other users. For more simplicity and as many users of Wasm GC also use
stringrefs, enabling it via the callback will also stringrefs.

Bug: v8:7748
Change-Id: I474034eabe438f0ce9759c1d34dda12a99aa491e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4165090
Auto-Submit: Matthias Liedtke <mliedtke@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Adam Klein <adamk@chromium.org>
Commit-Queue: Matthias Liedtke <mliedtke@chromium.org>
Cr-Commit-Position: refs/heads/main@{#85306}
This commit is contained in:
Matthias Liedtke 2023-01-16 09:53:41 +01:00 committed by V8 LUCI CQ
parent 6ca23f83ee
commit debcabf7b5
10 changed files with 138 additions and 0 deletions

View File

@ -328,6 +328,10 @@ using WasmSimdEnabledCallback = bool (*)(Local<Context> context);
// --- Callback for checking if WebAssembly exceptions are enabled ---
using WasmExceptionsEnabledCallback = bool (*)(Local<Context> context);
// --- Callback for checking if WebAssembly GC is enabled ---
// If the callback returns true, it will also enable Wasm stringrefs.
using WasmGCEnabledCallback = bool (*)(Local<Context> context);
// --- Callback for checking if the SharedArrayBuffer constructor is enabled ---
using SharedArrayBufferConstructorEnabledCallback =
bool (*)(Local<Context> context);

View File

@ -1513,6 +1513,13 @@ class V8_EXPORT Isolate {
V8_DEPRECATED("Wasm exceptions are always enabled")
void SetWasmExceptionsEnabledCallback(WasmExceptionsEnabledCallback callback);
/**
* Register callback to control whehter Wasm GC is enabled.
* The callback overwrites the value of the flag.
* If the callback returns true, it will also enable Wasm stringrefs.
*/
void SetWasmGCEnabledCallback(WasmGCEnabledCallback callback);
void SetSharedArrayBufferConstructorEnabledCallback(
SharedArrayBufferConstructorEnabledCallback callback);

View File

@ -9766,6 +9766,9 @@ CALLBACK_SETTER(WasmAsyncResolvePromiseCallback,
CALLBACK_SETTER(WasmLoadSourceMapCallback, WasmLoadSourceMapCallback,
wasm_load_source_map_callback)
CALLBACK_SETTER(WasmGCEnabledCallback, WasmGCEnabledCallback,
wasm_gc_enabled_callback)
CALLBACK_SETTER(SharedArrayBufferConstructorEnabledCallback,
SharedArrayBufferConstructorEnabledCallback,
sharedarraybuffer_constructor_enabled_callback)

View File

@ -2940,6 +2940,31 @@ bool Isolate::IsSharedArrayBufferConstructorEnabled(Handle<Context> context) {
return false;
}
bool Isolate::IsWasmGCEnabled(Handle<Context> context) {
#ifdef V8_ENABLE_WEBASSEMBLY
if (wasm_gc_enabled_callback()) {
v8::Local<v8::Context> api_context = v8::Utils::ToLocal(context);
return wasm_gc_enabled_callback()(api_context);
}
return v8_flags.experimental_wasm_gc;
#else
return false;
#endif
}
bool Isolate::IsWasmStringRefEnabled(Handle<Context> context) {
// If Wasm GC is explicitly enabled via a callback, also enable stringref.
#ifdef V8_ENABLE_WEBASSEMBLY
if (wasm_gc_enabled_callback()) {
v8::Local<v8::Context> api_context = v8::Utils::ToLocal(context);
return wasm_gc_enabled_callback()(api_context);
}
return v8_flags.experimental_wasm_stringref;
#else
return false;
#endif
}
Handle<Context> Isolate::GetIncumbentContext() {
JavaScriptFrameIterator it(this);

View File

@ -510,6 +510,7 @@ using DebugObjectCache = std::vector<Handle<HeapObject>>;
V(WasmLoadSourceMapCallback, wasm_load_source_map_callback, nullptr) \
V(WasmSimdEnabledCallback, wasm_simd_enabled_callback, nullptr) \
V(WasmExceptionsEnabledCallback, wasm_exceptions_enabled_callback, nullptr) \
V(WasmGCEnabledCallback, wasm_gc_enabled_callback, nullptr) \
/* State for Relocatable. */ \
V(Relocatable*, relocatable_top, nullptr) \
V(DebugObjectCache*, string_stream_debug_object_cache, nullptr) \
@ -769,6 +770,9 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
bool IsSharedArrayBufferConstructorEnabled(Handle<Context> context);
bool IsWasmGCEnabled(Handle<Context> context);
bool IsWasmStringRefEnabled(Handle<Context> context);
THREAD_LOCAL_TOP_ADDRESS(Context, pending_handler_context)
THREAD_LOCAL_TOP_ADDRESS(Address, pending_handler_entrypoint)
THREAD_LOCAL_TOP_ADDRESS(Address, pending_handler_constant_pool)

View File

@ -494,5 +494,17 @@ RUNTIME_FUNCTION(Runtime_FreezeWasmLazyCompilation) {
return ReadOnlyRoots(isolate).undefined_value();
}
// This runtime function enables WebAssembly GC through an embedder
// callback and thereby bypasses the value in v8_flags.
RUNTIME_FUNCTION(Runtime_SetWasmGCEnabled) {
DCHECK_EQ(1, args.length());
bool enable = args.at(0)->BooleanValue(isolate);
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
WasmGCEnabledCallback enabled = [](v8::Local<v8::Context>) { return true; };
WasmGCEnabledCallback disabled = [](v8::Local<v8::Context>) { return false; };
v8_isolate->SetWasmGCEnabledCallback(enable ? enabled : disabled);
return ReadOnlyRoots(isolate).undefined_value();
}
} // namespace internal
} // namespace v8

View File

@ -668,6 +668,7 @@ namespace internal {
F(SerializeWasmModule, 1, 1) \
F(SetWasmCompileControls, 2, 1) \
F(SetWasmInstantiateControls, 0, 1) \
F(SetWasmGCEnabled, 1, 1) \
F(WasmGetNumberOfInstances, 1, 1) \
F(WasmNumCodeSpaces, 1, 1) \
F(WasmEnterDebugging, 0, 1) \

View File

@ -33,6 +33,12 @@ WasmFeatures WasmFeatures::FromIsolate(Isolate* isolate) {
WasmFeatures WasmFeatures::FromContext(Isolate* isolate,
Handle<Context> context) {
WasmFeatures features = WasmFeatures::FromFlags();
if (isolate->IsWasmGCEnabled(handle(isolate->context(), isolate))) {
features.Add(kFeature_gc);
}
if (isolate->IsWasmStringRefEnabled(handle(isolate->context(), isolate))) {
features.Add(kFeature_stringref);
}
// This space intentionally left blank for future Wasm origin trials.
return features;
}

View File

@ -0,0 +1,46 @@
// Copyright 2023 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --noexperimental-wasm-gc --no-experimental-wasm-stringref
// Flags: --allow-natives-syntax
load("test/mjsunit/wasm/wasm-module-builder.js");
function instantiateModuleWithGC() {
// Build a WebAssembly module which uses Wasm GC features.
const builder = new WasmModuleBuilder();
builder.addFunction('main', makeSig([], [kWasmAnyRef]))
.addBody([
kExprI32Const, 42,
kGCPrefix, kExprI31New,
])
.exportFunc();
return builder.instantiate();
}
function instantiateModuleWithStringRef() {
// Build a WebAssembly module which uses stringref features.
const builder = new WasmModuleBuilder();
builder.addFunction("main",
makeSig([kWasmStringRef], [kWasmStringRef]))
.addBody([kExprLocalGet, 0])
.exportFunc();
return builder.instantiate();
}
// Due to --noexperimental-wasm-gc GC is disabled.
assertThrows(instantiateModuleWithGC, WebAssembly.CompileError);
// Due to --noexperimental-wasm-stringref stringrefs are not supported.
assertThrows(instantiateModuleWithStringRef, WebAssembly.CompileError);
// Disable WebAssembly GC explicitly.
%SetWasmGCEnabled(false);
assertThrows(instantiateModuleWithGC, WebAssembly.CompileError);
assertThrows(instantiateModuleWithStringRef, WebAssembly.CompileError);
// Enable WebAssembly GC explicitly.
%SetWasmGCEnabled(true);
assertEquals(42, instantiateModuleWithGC().exports.main());
// Enabling Wasm GC via callback will also enable wasm stringref.
let str = "Hello World!";
assertSame(str, instantiateModuleWithStringRef().exports.main(str));

View File

@ -13,6 +13,7 @@
#include "include/v8-wasm.h"
#include "src/api/api-inl.h"
#include "src/handles/global-handles.h"
#include "test/common/flag-utils.h"
#include "test/unittests/test-utils.h"
#include "testing/gtest/include/gtest/gtest.h"
@ -156,4 +157,33 @@ TEST_F(ApiWasmTest, WasmStreamingSetCallback) {
Promise::kPending);
}
TEST_F(ApiWasmTest, WasmEnableDisableGC) {
Local<Context> context_local = Context::New(isolate());
Context::Scope context_scope(context_local);
i::Handle<i::Context> context = v8::Utils::OpenHandle(*context_local);
// When using the flags, stringref and GC are controlled independently.
{
i::FlagScope<bool> flag_gc(&i::v8_flags.experimental_wasm_gc, false);
i::FlagScope<bool> flag_stringref(&i::v8_flags.experimental_wasm_stringref,
true);
EXPECT_FALSE(i_isolate()->IsWasmGCEnabled(context));
EXPECT_TRUE(i_isolate()->IsWasmStringRefEnabled(context));
}
{
i::FlagScope<bool> flag_gc(&i::v8_flags.experimental_wasm_gc, true);
i::FlagScope<bool> flag_stringref(&i::v8_flags.experimental_wasm_stringref,
false);
EXPECT_TRUE(i_isolate()->IsWasmGCEnabled(context));
EXPECT_FALSE(i_isolate()->IsWasmStringRefEnabled(context));
}
// When providing a callback, the callback will control GC and stringref.
isolate()->SetWasmGCEnabledCallback([](auto) { return true; });
EXPECT_TRUE(i_isolate()->IsWasmGCEnabled(context));
EXPECT_TRUE(i_isolate()->IsWasmStringRefEnabled(context));
isolate()->SetWasmGCEnabledCallback([](auto) { return false; });
EXPECT_FALSE(i_isolate()->IsWasmGCEnabled(context));
EXPECT_FALSE(i_isolate()->IsWasmStringRefEnabled(context));
isolate()->SetWasmGCEnabledCallback(nullptr);
}
} // namespace v8