[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:
mtrofin 2017-03-24 11:26:07 -07:00 committed by Commit bot
parent 4482bc2e76
commit 5fdb5a148e
6 changed files with 92 additions and 3 deletions

View File

@ -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.

View File

@ -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();

View File

@ -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,

View File

@ -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. */ \

View File

@ -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();
}

View File

@ -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);