[wasm] Add multi-return support for Wasm to JS calls
Allows JS functions returning array-like objects to be imported as multi-return functions in WebAssembly modules. Importing a generator does not work as required by the specification yet. R=mstarzinger@chromium.org Bug: v8:9492 Change-Id: Iaf61a0f718eb50676913aa1486fb39cebecfc090 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1815246 Commit-Queue: Thibaud Michaud <thibaudm@chromium.org> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Cr-Commit-Position: refs/heads/master@{#63965}
This commit is contained in:
parent
ecb1638a56
commit
63e9a7d9bf
@ -5887,15 +5887,29 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
|
||||
SetEffect(call);
|
||||
SetSourcePosition(call, 0);
|
||||
|
||||
// Convert the return value back.
|
||||
Node* val = sig_->return_count() == 0
|
||||
? mcgraph()->Int32Constant(0)
|
||||
: FromJS(call, native_context, sig_->GetReturn());
|
||||
|
||||
// Set the ThreadInWasm flag again.
|
||||
BuildModifyThreadInWasmFlag(true);
|
||||
|
||||
Return(val);
|
||||
// Convert the return value(s) back.
|
||||
if (sig_->return_count() <= 1) {
|
||||
Node* val = sig_->return_count() == 0
|
||||
? mcgraph()->Int32Constant(0)
|
||||
: FromJS(call, native_context, sig_->GetReturn());
|
||||
BuildModifyThreadInWasmFlag(true);
|
||||
Return(val);
|
||||
} else {
|
||||
Node* size = graph()->NewNode(
|
||||
mcgraph()->common()->NumberConstant(sig_->return_count()));
|
||||
Node* args[] = {call, size};
|
||||
// TODO(thibaudm): Replace runtime call with TurboFan code.
|
||||
Node* fixed_array = BuildCallToRuntimeWithContext(
|
||||
Runtime::kWasmIterableToFixedArray, native_context, args, 2, effect_,
|
||||
Control());
|
||||
Vector<Node*> wasm_values = Buffer(sig_->return_count());
|
||||
for (unsigned i = 0; i < sig_->return_count(); ++i) {
|
||||
wasm_values[i] = FromJS(LOAD_FIXED_ARRAY_SLOT_ANY(fixed_array, i),
|
||||
native_context, sig_->GetReturn(i));
|
||||
}
|
||||
BuildModifyThreadInWasmFlag(true);
|
||||
Return(wasm_values);
|
||||
}
|
||||
|
||||
if (ContainsInt64(sig_)) LowerInt64(kCalledFromWasm);
|
||||
return true;
|
||||
|
@ -587,5 +587,26 @@ RUNTIME_FUNCTION(Runtime_WasmNewMultiReturnJSArray) {
|
||||
fixed_array_handle, PACKED_ELEMENTS);
|
||||
return *array;
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_WasmIterableToFixedArray) {
|
||||
// TODO(thibaudm): The current implementation does not handle generators as
|
||||
// required by the spec.
|
||||
DCHECK_EQ(2, args.length());
|
||||
HandleScope scope(isolate);
|
||||
CONVERT_ARG_CHECKED(Object, arg, 0);
|
||||
if (!arg.IsJSReceiver()) {
|
||||
return ThrowWasmError(isolate, MessageTemplate::kWasmTrapFuncSigMismatch);
|
||||
}
|
||||
Handle<JSReceiver> receiver(JSReceiver::cast(arg), isolate);
|
||||
CONVERT_INT32_ARG_CHECKED(size, 1);
|
||||
Handle<FixedArray> fixed_array = isolate->factory()->NewFixedArray(size);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
Handle<Object> handle;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, handle, JSReceiver::GetElement(isolate, receiver, i));
|
||||
fixed_array->set(i, *handle);
|
||||
}
|
||||
return *fixed_array;
|
||||
}
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -559,7 +559,8 @@ namespace internal {
|
||||
F(WasmIsValidFuncRefValue, 1, 1) \
|
||||
F(WasmCompileLazy, 2, 1) \
|
||||
F(WasmNewMultiReturnFixedArray, 1, 1) \
|
||||
F(WasmNewMultiReturnJSArray, 1, 1)
|
||||
F(WasmNewMultiReturnJSArray, 1, 1) \
|
||||
F(WasmIterableToFixedArray, 2, 1)
|
||||
|
||||
#define FOR_EACH_INTRINSIC_RETURN_PAIR_IMPL(F, I) \
|
||||
F(DebugBreakOnBytecode, 1, 2) \
|
||||
|
@ -320,7 +320,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
assertEquals(instance.exports.main(10), 200);
|
||||
})();
|
||||
|
||||
(function MultiJSReturnTest() {
|
||||
(function MultiWasmToJSReturnTest() {
|
||||
print(arguments.callee.name);
|
||||
let builder = new WasmModuleBuilder();
|
||||
let sig_fi_if = makeSig([kWasmI32, kWasmF32], [kWasmF32, kWasmI32]);
|
||||
@ -350,3 +350,56 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
assertEquals(instance.exports.addsubmul(4), [8, 0, 16]);
|
||||
assertEquals(instance.exports.addsubmul(5), [10, 0, 25]);
|
||||
})();
|
||||
|
||||
(function MultiJSToWasmReturnTest() {
|
||||
print(arguments.callee.name);
|
||||
let builder = new WasmModuleBuilder();
|
||||
function swap(x, y) { return [y, x]; }
|
||||
function swap_proxy(x, y) {
|
||||
return new Proxy([y, x], {
|
||||
get: function(obj, prop) { return Reflect.get(obj, prop); },
|
||||
});
|
||||
}
|
||||
function proxy_throw(x, y) {
|
||||
return new Proxy([y, x], {
|
||||
get: function(obj, prop) {
|
||||
if (prop == 1) {
|
||||
throw new Error("abc");
|
||||
}
|
||||
return Reflect.get(obj, prop); },
|
||||
});
|
||||
}
|
||||
function drop_first(x, y) {
|
||||
return [y];
|
||||
}
|
||||
function repeat(x, y) {
|
||||
return [x, y, x, y];
|
||||
}
|
||||
function not_receiver(x, y) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
builder.addImport('imports', 'f', kSig_ii_ii);
|
||||
builder.addFunction("main", kSig_ii_ii)
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprGetLocal, 1,
|
||||
kExprCallFunction, 0])
|
||||
.exportAs("main")
|
||||
|
||||
let module = new WebAssembly.Module(builder.toBuffer());
|
||||
|
||||
var instance = new WebAssembly.Instance(module, { 'imports' : { 'f' : swap } });
|
||||
assertEquals(instance.exports.main(1, 2), [2, 1]);
|
||||
instance = new WebAssembly.Instance(module, { 'imports' : { 'f' : swap_proxy } });
|
||||
assertEquals(instance.exports.main(1, 2), [2, 1]);
|
||||
instance = new WebAssembly.Instance(module, { 'imports' : { 'f' : drop_first } });
|
||||
assertEquals(instance.exports.main(1, 2), [2, 0]);
|
||||
instance = new WebAssembly.Instance(module, { 'imports' : { 'f' : repeat } });
|
||||
assertEquals(instance.exports.main(1, 2), [1, 2]);
|
||||
|
||||
instance = new WebAssembly.Instance(module, { 'imports' : { 'f' : proxy_throw } });
|
||||
assertThrows(() => instance.exports.main(1, 2), Error, "abc");
|
||||
instance = new WebAssembly.Instance(module, { 'imports' : { 'f' : not_receiver } });
|
||||
assertThrows(() => instance.exports.main(1, 2), WebAssembly.RuntimeError);
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user