[wasm] Override mechanism for wasm js APIs
V8 side mechanism for overriding the wasm js APIs. We will use these to: - implement the Chrome-side constraints on module size, and throw with more actionable error messages, while preserving layering. The old mechansms will be deleted once we update the Chrome side with this new mechanism. - implement Chrome-side .compile and .instantiate overrides accepting Response objects. We may want to evolve this mechanism into something more general, not requiring V8 preparation, by replacing the v8-definition with embedder provided definitions. We're currently exploring if we can expand "Extras", for instance. BUG= Review-Url: https://codereview.chromium.org/2773063002 Cr-Commit-Position: refs/heads/master@{#44119}
This commit is contained in:
parent
4482bc2e76
commit
5fdb5a148e
@ -6008,6 +6008,8 @@ typedef bool (*AllowWasmInstantiateCallback)(Isolate* isolate,
|
||||
MaybeLocal<Value> ffi,
|
||||
bool as_promise);
|
||||
|
||||
typedef bool (*ExtensionCallback)(const FunctionCallbackInfo<Value>&);
|
||||
|
||||
// --- Garbage Collection Callbacks ---
|
||||
|
||||
/**
|
||||
@ -7251,6 +7253,11 @@ class V8_EXPORT Isolate {
|
||||
void SetAllowWasmCompileCallback(AllowWasmCompileCallback callback);
|
||||
void SetAllowWasmInstantiateCallback(AllowWasmInstantiateCallback callback);
|
||||
|
||||
void SetWasmModuleCallback(ExtensionCallback callback);
|
||||
void SetWasmCompileCallback(ExtensionCallback callback);
|
||||
void SetWasmInstanceCallback(ExtensionCallback callback);
|
||||
void SetWasmInstantiateCallback(ExtensionCallback callback);
|
||||
|
||||
/**
|
||||
* Check if V8 is dead and therefore unusable. This is the case after
|
||||
* fatal errors such as out-of-memory situations.
|
||||
|
12
src/api.cc
12
src/api.cc
@ -8735,6 +8735,18 @@ void Isolate::SetAllowWasmInstantiateCallback(
|
||||
isolate->set_allow_wasm_instantiate_callback(callback);
|
||||
}
|
||||
|
||||
#define CALLBACK_SETTER(ExternalName, Type, InternalName) \
|
||||
void Isolate::Set##ExternalName(Type callback) { \
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); \
|
||||
isolate->set_##InternalName(callback); \
|
||||
}
|
||||
|
||||
CALLBACK_SETTER(WasmModuleCallback, ExtensionCallback, wasm_module_callback)
|
||||
CALLBACK_SETTER(WasmCompileCallback, ExtensionCallback, wasm_compile_callback)
|
||||
CALLBACK_SETTER(WasmInstanceCallback, ExtensionCallback, wasm_instance_callback)
|
||||
CALLBACK_SETTER(WasmInstantiateCallback, ExtensionCallback,
|
||||
wasm_instantiate_callback)
|
||||
|
||||
bool Isolate::IsDead() {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
return isolate->IsDead();
|
||||
|
@ -434,6 +434,7 @@ bool GetStackTraceLimit(Isolate* isolate, int* result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NoExtension(const v8::FunctionCallbackInfo<v8::Value>&) { return false; }
|
||||
} // namespace
|
||||
|
||||
Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
|
||||
|
@ -397,6 +397,10 @@ typedef List<HeapObject*> DebugObjectCache;
|
||||
V(AllowCodeGenerationFromStringsCallback, allow_code_gen_callback, nullptr) \
|
||||
V(AllowWasmCompileCallback, allow_wasm_compile_callback, nullptr) \
|
||||
V(AllowWasmInstantiateCallback, allow_wasm_instantiate_callback, nullptr) \
|
||||
V(ExtensionCallback, wasm_module_callback, &NoExtension) \
|
||||
V(ExtensionCallback, wasm_instance_callback, &NoExtension) \
|
||||
V(ExtensionCallback, wasm_compile_callback, &NoExtension) \
|
||||
V(ExtensionCallback, wasm_instantiate_callback, &NoExtension) \
|
||||
V(ExternalReferenceRedirectorPointer*, external_reference_redirector, \
|
||||
nullptr) \
|
||||
/* State for Relocatable. */ \
|
||||
|
@ -45,7 +45,7 @@ bool IsWasmCompileAllowed(v8::Isolate* isolate, v8::Local<v8::Value> value,
|
||||
// Use the compile controls for instantiation, too
|
||||
bool IsWasmInstantiateAllowed(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> module_or_bytes,
|
||||
v8::MaybeLocal<v8::Value> ffi, bool is_async) {
|
||||
bool is_async) {
|
||||
DCHECK_GT(g_PerIsolateWasmControls.Get().count(isolate), 0);
|
||||
const WasmCompileControls& ctrls = g_PerIsolateWasmControls.Get().at(isolate);
|
||||
if (is_async && ctrls.AllowAnySizeForAsync) return true;
|
||||
@ -57,6 +57,60 @@ bool IsWasmInstantiateAllowed(v8::Isolate* isolate,
|
||||
return static_cast<uint32_t>(module->GetWasmWireBytes()->Length()) <=
|
||||
ctrls.MaxWasmBufferSize;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> NewRangeException(v8::Isolate* isolate,
|
||||
const char* message) {
|
||||
return v8::Exception::RangeError(
|
||||
v8::String::NewFromOneByte(isolate,
|
||||
reinterpret_cast<const uint8_t*>(message),
|
||||
v8::NewStringType::kNormal)
|
||||
.ToLocalChecked());
|
||||
}
|
||||
|
||||
void ThrowRangeException(v8::Isolate* isolate, const char* message) {
|
||||
isolate->ThrowException(NewRangeException(isolate, message));
|
||||
}
|
||||
|
||||
void RejectPromiseWithRangeError(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args, const char* message) {
|
||||
v8::Isolate* isolate = args.GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||
v8::Local<v8::Promise::Resolver> resolver;
|
||||
if (!v8::Promise::Resolver::New(context).ToLocal(&resolver)) return;
|
||||
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
|
||||
return_value.Set(resolver->GetPromise());
|
||||
|
||||
auto maybe = resolver->Reject(context, NewRangeException(isolate, message));
|
||||
CHECK(!maybe.IsNothing());
|
||||
return;
|
||||
}
|
||||
|
||||
bool WasmModuleOverride(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
if (IsWasmCompileAllowed(args.GetIsolate(), args[0], false)) return false;
|
||||
ThrowRangeException(args.GetIsolate(), "Sync compile not allowed");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WasmCompileOverride(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
if (IsWasmCompileAllowed(args.GetIsolate(), args[0], true)) return false;
|
||||
RejectPromiseWithRangeError(args, "Async compile not allowed");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WasmInstanceOverride(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
if (IsWasmInstantiateAllowed(args.GetIsolate(), args[0], false)) return false;
|
||||
ThrowRangeException(args.GetIsolate(), "Sync instantiate not allowed");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WasmInstantiateOverride(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
if (IsWasmInstantiateAllowed(args.GetIsolate(), args[0], true)) return false;
|
||||
RejectPromiseWithRangeError(args, "Async instantiate not allowed");
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace v8 {
|
||||
@ -516,14 +570,17 @@ RUNTIME_FUNCTION(Runtime_SetWasmCompileControls) {
|
||||
WasmCompileControls& ctrl = (*g_PerIsolateWasmControls.Pointer())[v8_isolate];
|
||||
ctrl.AllowAnySizeForAsync = allow_async;
|
||||
ctrl.MaxWasmBufferSize = static_cast<uint32_t>(block_size->value());
|
||||
isolate->set_allow_wasm_compile_callback(IsWasmCompileAllowed);
|
||||
v8_isolate->SetWasmModuleCallback(WasmModuleOverride);
|
||||
v8_isolate->SetWasmCompileCallback(WasmCompileOverride);
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_SetWasmInstantiateControls) {
|
||||
HandleScope scope(isolate);
|
||||
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
|
||||
CHECK(args.length() == 0);
|
||||
isolate->set_allow_wasm_instantiate_callback(IsWasmInstantiateAllowed);
|
||||
v8_isolate->SetWasmInstanceCallback(WasmInstanceOverride);
|
||||
v8_isolate->SetWasmInstantiateCallback(WasmInstantiateOverride);
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
@ -178,6 +178,8 @@ i::MaybeHandle<i::JSReceiver> GetSecondArgumentAsImports(
|
||||
void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::Isolate* isolate = args.GetIsolate();
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
if (i_isolate->wasm_compile_callback()(args)) return;
|
||||
|
||||
HandleScope scope(isolate);
|
||||
ErrorThrower thrower(i_isolate, "WebAssembly.compile()");
|
||||
|
||||
@ -222,6 +224,8 @@ void WebAssemblyValidate(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
void WebAssemblyModule(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::Isolate* isolate = args.GetIsolate();
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
if (i_isolate->wasm_module_callback()(args)) return;
|
||||
|
||||
HandleScope scope(isolate);
|
||||
ErrorThrower thrower(i_isolate, "WebAssembly.Module()");
|
||||
|
||||
@ -297,6 +301,8 @@ void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
HandleScope scope(args.GetIsolate());
|
||||
v8::Isolate* isolate = args.GetIsolate();
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
if (i_isolate->wasm_instance_callback()(args)) return;
|
||||
|
||||
ErrorThrower thrower(i_isolate, "WebAssembly.Instance()");
|
||||
|
||||
auto maybe_module = GetFirstArgumentAsModule(args, &thrower);
|
||||
@ -322,6 +328,8 @@ void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
void WebAssemblyInstantiate(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::Isolate* isolate = args.GetIsolate();
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
if (i_isolate->wasm_instantiate_callback()(args)) return;
|
||||
|
||||
ErrorThrower thrower(i_isolate, "WebAssembly.instantiate()");
|
||||
|
||||
HandleScope scope(isolate);
|
||||
|
Loading…
Reference in New Issue
Block a user