Commit 0759c506 authored by Thibaud Michaud's avatar Thibaud Michaud Committed by Commit Bot

[wasm] Support multi-value in JS to JS wrappers

R=mstarzinger@chromium.org

Bug: v8:9492
Change-Id: Ie404eb6cb07ea033a10d29dd1b9aba6cb1f03b69
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1826663
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64134}
parent 9b1e174f
......@@ -5640,6 +5640,22 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
return jump_table_offset;
}
Node* BuildMultiReturnFixedArrayFromIterable(const wasm::FunctionSig* sig,
Node* iterable, Node* context) {
Node* iterable_to_fixed_array =
BuildLoadBuiltinFromIsolateRoot(Builtins::kIterableToFixedArrayForWasm);
IterableToFixedArrayForWasmDescriptor interface_descriptor;
Node* length = BuildChangeUint31ToSmi(
Uint32Constant(static_cast<uint32_t>(sig->return_count())));
auto call_descriptor = Linkage::GetStubCallDescriptor(
mcgraph()->zone(), interface_descriptor,
interface_descriptor.GetStackParameterCount(), CallDescriptor::kNoFlags,
Operator::kNoProperties, StubCallMode::kCallCodeObject);
return SetEffect(graph()->NewNode(
mcgraph()->common()->Call(call_descriptor), iterable_to_fixed_array,
iterable, length, context, Effect(), Control()));
}
void BuildJSToWasmWrapper(bool is_import) {
const int wasm_count = static_cast<int>(sig_->parameter_count());
......@@ -5924,20 +5940,9 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
BuildModifyThreadInWasmFlag(true);
Return(val);
} else {
Node* iterable_to_fixed_array = BuildLoadBuiltinFromIsolateRoot(
Builtins::kIterableToFixedArrayForWasm);
IterableToFixedArrayForWasmDescriptor interface_descriptor;
Node* length = BuildChangeUint31ToSmi(
Uint32Constant(static_cast<uint32_t>(sig_->return_count())));
auto call_descriptor = Linkage::GetStubCallDescriptor(
mcgraph()->zone(), interface_descriptor,
interface_descriptor.GetStackParameterCount(),
CallDescriptor::kNoFlags, Operator::kNoProperties,
StubCallMode::kCallCodeObject);
Node* fixed_array =
BuildMultiReturnFixedArrayFromIterable(sig_, call, native_context);
Vector<Node*> wasm_values = Buffer(sig_->return_count());
Node* fixed_array = graph()->NewNode(
mcgraph()->common()->Call(call_descriptor), iterable_to_fixed_array,
call, length, native_context, Effect(), Control());
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));
......@@ -6191,14 +6196,30 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
Node* call = SetEffect(graph()->NewNode(
mcgraph()->common()->Call(call_descriptor), pos, args.begin()));
// TODO(wasm): Extend this to support multi-return.
DCHECK_LE(sig_->return_count(), 1);
// Convert return JS values to wasm numbers and back to JS values.
Node* jsval =
sig_->return_count() == 0
? BuildLoadUndefinedValueFromInstance()
: ToJS(FromJS(call, context, sig_->GetReturn()), sig_->GetReturn());
Node* jsval;
if (sig_->return_count() == 0) {
jsval = BuildLoadUndefinedValueFromInstance();
} else if (sig_->return_count() == 1) {
jsval = ToJS(FromJS(call, context, sig_->GetReturn()), sig_->GetReturn());
} else {
Node* fixed_array =
BuildMultiReturnFixedArrayFromIterable(sig_, call, context);
int32_t return_count = static_cast<int32_t>(sig_->return_count());
Node* size =
graph()->NewNode(mcgraph()->common()->NumberConstant(return_count));
Node* result_fixed_array =
BuildCallToRuntime(Runtime::kWasmNewMultiReturnFixedArray, &size, 1);
for (unsigned i = 0; i < sig_->return_count(); ++i) {
const auto& type = sig_->GetReturn(i);
Node* elem = LOAD_FIXED_ARRAY_SLOT_ANY(fixed_array, i);
Node* cast = ToJS(FromJS(elem, context, type), type);
STORE_FIXED_ARRAY_SLOT_ANY(result_fixed_array, i, cast);
}
jsval = BuildCallToRuntimeWithContext(Runtime::kWasmNewMultiReturnJSArray,
context, &result_fixed_array, 1,
effect_, Control());
}
Return(jsval);
}
......
......@@ -602,6 +602,9 @@ class WasmGraphBuilder {
Node* BuildDecodeException32BitValue(Node* values_array, uint32_t* index);
Node* BuildDecodeException64BitValue(Node* values_array, uint32_t* index);
Node* BuildMultiReturnFixedArrayFromIterable(const wasm::FunctionSig* sig,
Node* iterable, Node* context);
Vector<Node*> Realloc(Node* const* buffer, size_t old_count,
size_t new_count) {
DCHECK_GE(new_count, old_count); // Only support growing.
......
// Copyright 2019 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: --experimental-wasm-type-reflection --expose-gc --experimental-wasm-mv
(function TestFunctionConstructedCoercions() {
let obj1 = { valueOf: _ => 123.45 };
let obj2 = { toString: _ => "456" };
let gcer = { valueOf: _ => gc() };
let testcases = [
{ params: { sig: [],
val: [],
exp: [], },
result: { sig: ["i32", "f32"],
val: [42.7, "xyz"],
exp: [42, NaN] },
},
{ params: { sig: [],
val: [],
exp: [], },
result: { sig: ["i32", "f32", "f64"],
val: (function* () { yield obj1; yield obj2; yield "789" })(),
exp: [123, 456, 789], },
},
{ params: { sig: [],
val: [],
exp: [], },
result: { sig: ["i32", "f32", "f64"],
val: new Proxy([gcer, {}, "xyz"], {
get: function(obj, prop) { return Reflect.get(obj, prop); }
}),
exp: [0, NaN, NaN], },
},
];
testcases.forEach(function({params, result}) {
let p = params.sig; let r = result.sig; var params_after;
function testFun() { params_after = arguments; return result.val; }
let fun = new WebAssembly.Function({parameters:p, results:r}, testFun);
let result_after = fun.apply(undefined, params.val);
assertArrayEquals(params.exp, params_after);
assertEquals(result.exp, result_after);
});
})();
(function TestFunctionConstructedCoercionsThrow() {
let proxy_throw = new Proxy([1, 2], {
get: function(obj, prop) {
if (prop == 1) {
throw new Error("abc");
}
return Reflect.get(obj, prop); },
});
function* generator_throw() {
yield 1;
throw new Error("def");
}
let testcases = [
{ val: 0,
error: Error,
msg: /not iterable/ },
{ val: [1],
error: TypeError,
msg: /multi-return length mismatch/ },
{ val: [1, 2, 3],
error: TypeError,
msg: /multi-return length mismatch/ },
{ val: proxy_throw,
error: Error,
msg: /abc/ },
{ val: generator_throw(),
error: Error,
msg: /def/ },
];
testcases.forEach(function({val, error, msg}) {
fun = new WebAssembly.Function({parameters:[], results:["i32", "i32"]},
() => val);
assertThrows(fun, error, msg);
})
})();
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