blob: 0cf2639d5bcaab9a9032d20f2da453f3b3097c68 [file] [log] [blame]
// 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: --expose-wasm --experimental-wasm-return-call
// Reduce the stack size to test that we are indeed doing return calls (instead
// of standard calls which consume stack space).
// Flags: --stack-size=128
load("test/mjsunit/wasm/wasm-module-builder.js");
(function TestFactorialReturnCall() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
const sig_i_iii = builder.addType(kSig_i_iii);
// construct the code for the function
// f_aux(N,X) where N=<1 => X
// f_aux(N,X) => f_aux(N-1,X*N)
let fact_aux = builder.addFunction("fact_aux",kSig_i_ii);
fact_aux.addBody([
kExprLocalGet, 0, kExprI32Const, 1, kExprI32LeS,
kExprIf, kWasmI32,
kExprLocalGet, 1,
kExprElse,
kExprLocalGet, 0,
kExprI32Const, 1,
kExprI32Sub,
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprI32Mul,
kExprReturnCall, fact_aux.index,
kExprEnd
]);
//main(N)=>fact_aux(N,1)
let main = builder.addFunction("main", kSig_i_i)
.addBody([
kExprLocalGet, 0,
kExprI32Const, 1,
kExprReturnCall,0
]).exportFunc();
let module = builder.instantiate();
print(" --three--");
assertEquals(6, module.exports.main(3));
print(" --four--");
assertEquals(24, module.exports.main(4));
})();
(function TestIndirectFactorialReturnCall() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
const sig_i_iii = builder.addType(kSig_i_iii);
// construct the code for the function
// fact(N) => f_ind(N,1,f).
//
// f_ind(N,X,_) where N=<1 => X
// f_ind(N,X,F) => F(N-1,X*N,F).
let f_ind = builder.addFunction("f_ind",kSig_i_iii).
addBody([
kExprLocalGet, 0, kExprI32Const, 1, kExprI32LeS,
kExprIf, kWasmI32,
kExprLocalGet, 1,
kExprElse,
kExprLocalGet, 0,
kExprI32Const, 1,
kExprI32Sub,
kExprLocalGet, 0,
kExprLocalGet, 1,
kExprI32Mul,
kExprLocalGet, 2,
kExprLocalGet, 2,
kExprReturnCallIndirect, sig_i_iii, kTableZero,
kExprEnd
]);
//main(N)=>fact_aux(N,1)
let main = builder.addFunction("main", kSig_i_i)
.addBody([
kExprLocalGet, 0,
kExprI32Const, 1,
kExprI32Const, f_ind.index,
kExprReturnCall, f_ind.index
]).exportFunc();
builder.appendToTable([f_ind.index, main.index]);
let module = builder.instantiate();
print(" --three--");
assertEquals(6, module.exports.main(3));
print(" --four--");
assertEquals(24, module.exports.main(4));
})();
(function TestImportReturnCall() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
const sig_i_iii = builder.addType(kSig_i_iii);
let pick = builder.addImport("q", "pick", sig_i_iii);
let main = builder.addFunction("main", kSig_i_iii)
.addBody([
kExprLocalGet, 1,
kExprLocalGet, 2,
kExprLocalGet, 0,
kExprReturnCall, pick
])
.exportFunc();
let module = builder.instantiate({q: {
pick: function(a, b, c) { return c ? a : b; }}});
print(" --left--");
assertEquals(-2, module.exports.main(1, -2, 3));
print(" --right--");
assertEquals(3, module.exports.main(0, -2, 3));
})();
(function TestImportIndirectReturnCall() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
const sig_i_iii = builder.addType(kSig_i_iii);
let pick = builder.addImport("q", "pick", sig_i_iii);
builder.addTable(kWasmAnyFunc, 4);
// Arbitrary location in the table.
const tableIndex = 3;
builder.addElementSegment(0, tableIndex,false,[pick]);
let main = builder.addFunction("main", kSig_i_iii)
.addBody([
kExprLocalGet, 1,
kExprLocalGet, 2,
kExprLocalGet, 0,
kExprI32Const, tableIndex,
kExprReturnCallIndirect, sig_i_iii, kTableZero
])
.exportFunc();
builder.appendToTable([pick, main.index]);
let module = builder.instantiate({q: {
pick: function(a, b, c) { return c ? a : b; }
}});
print(" --left--");
assertEquals(-2, module.exports.main(1, -2, 3));
print(" --right--");
assertEquals(3, module.exports.main(0, -2, 3));
})();
(function TestMultiReturnCallWithLongSig() {
print(arguments.callee.name);
const callee_inputs = 10;
// Tail call from a function with less, as many, or more parameters than the
// callee.
for (caller_inputs = 9; caller_inputs <= 11; ++caller_inputs) {
let builder = new WasmModuleBuilder();
// f just returns its arguments in reverse order.
const f_params = new Array(callee_inputs).fill(kWasmI32);
const f_returns = f_params;
const f_sig = builder.addType(makeSig(f_params, f_returns));
let f_body = [];
for (i = 0; i < callee_inputs; ++i) {
f_body.push(kExprLocalGet, callee_inputs - i - 1);
}
const f = builder.addFunction("f", f_sig).addBody(f_body);
// Slice or pad the caller inputs to match the callee.
const main_params = new Array(caller_inputs).fill(kWasmI32);
const main_sig = builder.addType(makeSig(main_params, f_returns));
let main_body = [];
for (i = 0; i < callee_inputs; ++i) {
main_body.push(kExprLocalGet, Math.min(caller_inputs - 1, i));
}
main_body.push(kExprReturnCall, f.index);
builder.addFunction("main", main_sig).addBody(main_body).exportFunc();
let module = builder.instantiate();
inputs = [];
for (i = 0; i < caller_inputs; ++i) {
inputs.push(i);
}
let expect = inputs.slice(0, callee_inputs);
while (expect.length < callee_inputs) {
expect.push(inputs[inputs.length - 1]);
}
expect.reverse();
assertEquals(expect, module.exports.main(...inputs));
}
})();