Commit 71cf4890 authored by mtrofin's avatar mtrofin Committed by Commit bot

[wasm] instantiate expressed in terms of compile

Today, the semantics of:

WebAssembly.instantiate

and

WebAssembly.compile().then(new WebAssemblyInstance)

are subtly different, to the point where attempting the proposed
change uncovered bugs.

In the future, it's possible that .instantiate actually have different
semantics - if we pre-specialized to the provided ffi, for example.
Right now that's not the case.

This CL:
- gets our implementation closer to what developers may write using
the compile -> new Instance alternative, in particular wrt promise
creation. By reusing code paths, we uncover more bugs, and keep
maintenance cost lower.

- it gives us the response-based WebAssembly.instantiate implicitly.
Otherwise, we'd need that same implementation on the blink side. The
negative is maintenance: imagine if the bugs I mentioned could only be
found when running in Blink.

BUG=chromium:697028

Review-Url: https://codereview.chromium.org/2806073002
Cr-Original-Commit-Position: refs/heads/master@{#44592}
Committed: https://chromium.googlesource.com/v8/v8/+/7829af3275ff4644a2d0a1270abe1a1e4415e9fb
Review-Url: https://codereview.chromium.org/2806073002
Cr-Commit-Position: refs/heads/master@{#44669}
parent 12363355
...@@ -111,6 +111,21 @@ bool WasmInstantiateOverride(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -111,6 +111,21 @@ bool WasmInstantiateOverride(const v8::FunctionCallbackInfo<v8::Value>& args) {
return true; return true;
} }
bool GetWasmFromArray(const v8::FunctionCallbackInfo<v8::Value>& args) {
CHECK(args.Length() == 1);
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
v8::Local<v8::Value> module =
v8::Local<v8::Object>::Cast(args[0])->Get(context, 0).ToLocalChecked();
v8::Local<v8::Promise::Resolver> resolver =
v8::Promise::Resolver::New(context).ToLocalChecked();
args.GetReturnValue().Set(resolver->GetPromise());
USE(resolver->Resolve(context, module));
return true;
}
bool NoExtension(const v8::FunctionCallbackInfo<v8::Value>&) { return false; }
} // namespace } // namespace
namespace v8 { namespace v8 {
...@@ -452,6 +467,16 @@ RUNTIME_FUNCTION(Runtime_ClearFunctionFeedback) { ...@@ -452,6 +467,16 @@ RUNTIME_FUNCTION(Runtime_ClearFunctionFeedback) {
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
RUNTIME_FUNCTION(Runtime_SetWasmCompileFromPromiseOverload) {
isolate->set_wasm_compile_callback(GetWasmFromArray);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_ResetWasmOverloads) {
isolate->set_wasm_compile_callback(NoExtension);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_CheckWasmWrapperElision) { RUNTIME_FUNCTION(Runtime_CheckWasmWrapperElision) {
// This only supports the case where the function being exported // This only supports the case where the function being exported
// calls an intermediate function, and the intermediate function // calls an intermediate function, and the intermediate function
...@@ -1007,5 +1032,6 @@ RUNTIME_FUNCTION(Runtime_DecrementWaitCount) { ...@@ -1007,5 +1032,6 @@ RUNTIME_FUNCTION(Runtime_DecrementWaitCount) {
isolate->DecrementWaitCountForTesting(); isolate->DecrementWaitCountForTesting();
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -617,6 +617,8 @@ namespace internal { ...@@ -617,6 +617,8 @@ namespace internal {
F(ValidateWasmOrphanedInstance, 1, 1) \ F(ValidateWasmOrphanedInstance, 1, 1) \
F(SetWasmCompileControls, 2, 1) \ F(SetWasmCompileControls, 2, 1) \
F(SetWasmInstantiateControls, 0, 1) \ F(SetWasmInstantiateControls, 0, 1) \
F(SetWasmCompileFromPromiseOverload, 0, 1) \
F(ResetWasmOverloads, 0, 1) \
F(HeapObjectVerify, 1, 1) \ F(HeapObjectVerify, 1, 1) \
F(WasmNumInterpretedCalls, 1, 1) \ F(WasmNumInterpretedCalls, 1, 1) \
F(RedirectToWasmInterpreter, 2, 1) F(RedirectToWasmInterpreter, 2, 1)
......
This diff is collapsed.
...@@ -2603,44 +2603,6 @@ void wasm::AsyncInstantiate(Isolate* isolate, Handle<JSPromise> promise, ...@@ -2603,44 +2603,6 @@ void wasm::AsyncInstantiate(Isolate* isolate, Handle<JSPromise> promise,
instance_object.ToHandleChecked()); instance_object.ToHandleChecked());
} }
void wasm::AsyncCompileAndInstantiate(Isolate* isolate,
Handle<JSPromise> promise,
const ModuleWireBytes& bytes,
MaybeHandle<JSReceiver> imports) {
ErrorThrower thrower(isolate, nullptr);
// Compile the module.
MaybeHandle<WasmModuleObject> module_object =
SyncCompile(isolate, &thrower, bytes);
if (thrower.error()) {
RejectPromise(isolate, handle(isolate->context()), &thrower, promise);
return;
}
Handle<WasmModuleObject> module = module_object.ToHandleChecked();
// Instantiate the module.
MaybeHandle<WasmInstanceObject> instance_object = SyncInstantiate(
isolate, &thrower, module, imports, Handle<JSArrayBuffer>::null());
if (thrower.error()) {
RejectPromise(isolate, handle(isolate->context()), &thrower, promise);
return;
}
Handle<JSFunction> object_function =
Handle<JSFunction>(isolate->native_context()->object_function(), isolate);
Handle<JSObject> ret =
isolate->factory()->NewJSObject(object_function, TENURED);
Handle<String> module_property_name =
isolate->factory()->InternalizeUtf8String("module");
Handle<String> instance_property_name =
isolate->factory()->InternalizeUtf8String("instance");
JSObject::AddProperty(ret, module_property_name, module, NONE);
JSObject::AddProperty(ret, instance_property_name,
instance_object.ToHandleChecked(), NONE);
ResolvePromise(isolate, handle(isolate->context()), promise, ret);
}
// Encapsulates all the state and steps of an asynchronous compilation. // Encapsulates all the state and steps of an asynchronous compilation.
// An asynchronous compile job consists of a number of tasks that are executed // An asynchronous compile job consists of a number of tasks that are executed
// as foreground and background tasks. Any phase that touches the V8 heap or // as foreground and background tasks. Any phase that touches the V8 heap or
......
...@@ -472,10 +472,6 @@ V8_EXPORT_PRIVATE void AsyncInstantiate(Isolate* isolate, ...@@ -472,10 +472,6 @@ V8_EXPORT_PRIVATE void AsyncInstantiate(Isolate* isolate,
Handle<WasmModuleObject> module_object, Handle<WasmModuleObject> module_object,
MaybeHandle<JSReceiver> imports); MaybeHandle<JSReceiver> imports);
V8_EXPORT_PRIVATE void AsyncCompileAndInstantiate(
Isolate* isolate, Handle<JSPromise> promise, const ModuleWireBytes& bytes,
MaybeHandle<JSReceiver> imports);
#if V8_TARGET_ARCH_64_BIT #if V8_TARGET_ARCH_64_BIT
const bool kGuardRegionsSupported = true; const bool kGuardRegionsSupported = true;
#else #else
......
...@@ -2,19 +2,33 @@ ...@@ -2,19 +2,33 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --expose-wasm // Flags: --allow-natives-syntax
load("test/mjsunit/wasm/wasm-constants.js"); load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js"); load("test/mjsunit/wasm/wasm-module-builder.js");
(function BasicTest() { const kReturnValue = 15;
var kReturnValue = 15;
function getBuilder() {
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addFunction("main", kSig_i_i) builder.addFunction("main", kSig_i_i)
.addBody([kExprI32Const, kReturnValue]) .addBody([kExprI32Const, kReturnValue])
.exportFunc(); .exportFunc();
return builder;
}
(function BasicTest() {
var builder = getBuilder();
var main = builder.instantiate().exports.main; var main = builder.instantiate().exports.main;
assertEquals(kReturnValue, main()); assertEquals(kReturnValue, main());
})(); })();
(function AsyncTest() {
var builder = getBuilder();
var buffer = builder.toBuffer();
assertPromiseResult(
WebAssembly.instantiate(buffer)
.then(pair => pair.instance.exports.main(), assertUnreachable)
.then(result => assertEquals(kReturnValue, result), assertUnreachable));
})();
...@@ -713,7 +713,6 @@ function assertCompileError(args, err, msg) { ...@@ -713,7 +713,6 @@ function assertCompileError(args, err, msg) {
var error = null; var error = null;
assertPromiseResult(compile(...args), unexpectedSuccess, error => { assertPromiseResult(compile(...args), unexpectedSuccess, error => {
assertTrue(error instanceof err); assertTrue(error instanceof err);
assertTrue(Boolean(error.stack.match('js-api.js')));
// TODO assertTrue(Boolean(error.message.match(msg))); // TODO assertTrue(Boolean(error.message.match(msg)));
}); });
} }
...@@ -760,7 +759,6 @@ function assertInstantiateError(args, err, msg) { ...@@ -760,7 +759,6 @@ function assertInstantiateError(args, err, msg) {
var error = null; var error = null;
assertPromiseResult(instantiate(...args), unexpectedSuccess, error => { assertPromiseResult(instantiate(...args), unexpectedSuccess, error => {
assertTrue(error instanceof err); assertTrue(error instanceof err);
assertTrue(Boolean(error.stack.match('js-api.js')));
// TODO assertTrue(Boolean(error.message.match(msg))); // TODO assertTrue(Boolean(error.message.match(msg)));
}); });
} }
......
// Copyright 2017 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: --allow-natives-syntax
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
%ResetWasmOverloads();
let buffer = (() => {
let builder = new WasmModuleBuilder();
builder.addFunction("f", kSig_i_v)
.addBody([kExprI32Const, 42])
.exportAs("f");
return builder.toBuffer();
})();
var module = new WebAssembly.Module(buffer);
var wrapper = [module];
assertPromiseResult(
WebAssembly.instantiate(wrapper),
assertUnreachable,
e => assertTrue(e instanceof TypeError));
assertPromiseResult(
(() => {
%SetWasmCompileFromPromiseOverload();
return WebAssembly.instantiate(wrapper);
})(),
pair => {
print(2);
var pair = result.pair;
assertTrue(pair.instance instanceof WebAssembly.Instance);
assertTrue(pair.module instanceof WebAssembly.Module);
%ResetWasmOverloads();
},
assertUnreachable);
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