Commit 5fdb5a14 authored by mtrofin's avatar mtrofin Committed by Commit bot

[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}
parent 4482bc2e
......@@ -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.
......
......@@ -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);
......
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