Source code

Revision control

Copy as Markdown

Other Tools

var ins = wasmEvalText(`(module
(func $fac-acc (export "fac-acc") (param i64 i64) (result i64)
(if (result i64) (i64.eqz (local.get 0))
(then (local.get 1))
(else
(return_call $fac-acc
(i64.sub (local.get 0) (i64.const 1))
(i64.mul (local.get 0) (local.get 1))
)
)
)
)
(func (export "main") (param i64) (result i64)
(call $fac-acc (local.get 0) (i64.const 1))
)
)`);
// Check return call via wasm function
assertEq(ins.exports.main(5n), 120n);
// Check return call directly via interpreter stub
const fac = ins.exports["fac-acc"];
assertEq(fac(4n, 1n), 24n);
// Check return call directly via jit stub
check_stub1: {
let options = getJitCompilerOptions();
if (!options["baseline.enable"]) break check_stub1;
const check = function() {
fac(4n, 1n);
};
for (let i = options["baseline.warmup.trigger"] + 1; i--;)
check();
}
// Return call of an import
var ins0 = wasmEvalText(`(module
(func $fac-acc (export "fac-acc") (param i64 i64) (result i64)
(if (result i64) (i64.eqz (local.get 0))
(then (local.get 1))
(else
(return_call $fac-acc
(i64.sub (local.get 0) (i64.const 1))
(i64.mul (local.get 0) (local.get 1))
)
)
)
)
)`);
var ins = wasmEvalText(`(module
(import "" "fac-acc" (func $fac-acc (param i64 i64) (result i64)))
(func (export "fac") (param i64) (result i64)
local.get 0
i64.const 1
return_call $fac-acc
)
(func (export "main") (result i64)
i64.const 4
call 1
)
)`, {"": {"fac-acc": ins0.exports["fac-acc"],}});
assertEq(ins.exports.main(), 24n);
assertEq(ins.exports.fac(3n, 1n), 6n);
check_stub2: {
let options = getJitCompilerOptions();
if (!options["baseline.enable"]) break check_stub2;
const check = function() {
ins.exports.fac(3n, 1n)
};
for (let i = options["baseline.warmup.trigger"] + 1; i--;)
check();
}
// Check with parameters area growth
var ins0 = wasmEvalText(`(module
(func $fac-acc (export "fac-acc") (param i64 i64 i64 i64 i64 i64 i64 i64) (result i64)
(if (result i64) (i64.eqz (local.get 0))
(then (local.get 1))
(else
(return_call $fac-acc
(i64.sub (local.get 0) (i64.const 1))
(i64.mul (local.get 0) (local.get 1))
i64.const 1 i64.const 2 i64.const 3 i64.const 4 i64.const 5 i64.const 6
)
)
)
)
)`);
var ins = wasmEvalText(`(module
(import "" "fac-acc" (func $fac-acc (param i64 i64 i64 i64 i64 i64 i64 i64) (result i64)))
(func (export "fac") (param i64) (result i64)
local.get 0
i64.const 1
i64.const 1 i64.const 2 i64.const 3 i64.const 4 i64.const 5 i64.const 6
return_call $fac-acc
)
(func (export "main") (result i64)
i64.const 5
call 1
)
)`, {"": {"fac-acc": ins0.exports["fac-acc"],}});
assertEq(ins.exports.main(), 120n);
assertEq(ins.exports.fac(3n, 1n), 6n);
check_stub3: {
let options = getJitCompilerOptions();
if (!options["baseline.enable"]) break check_stub3;
const check = function() {
ins.exports.fac(4n, 1n)
};
for (let i = options["baseline.warmup.trigger"] + 1; i--;)
check();
}
// Test multi-value returns.
var ins = wasmEvalText(`(module
(memory (export "memory") 1 1)
(func $rec (export "rec") (param i32 i32 i32 i32 i32 i32 i32) (result i32 i32 f32 f32)
(local f32 i32)
(if (result i32 i32 f32 f32) (i32.ge_u (local.get 0) (local.get 1))
(then
(local.get 5)
(local.get 6)
(local.tee 7 (f32.div (f32.convert_i32_u (local.get 3)) (f32.convert_i32_u (local.get 2))))
(f32.sqrt
(f32.sub
(f32.div (f32.convert_i32_u (local.get 4)) (f32.convert_i32_u (local.get 2)))
(f32.mul (local.get 7) (local.get 7))
)
)
)
(else
(return_call $rec
(i32.add (local.get 0) (i32.const 1))
(local.get 1)
(i32.add (local.get 2) (i32.const 1))
(i32.add (local.get 3) (local.tee 8 (i32.load8_u (local.get 0))))
(i32.add (local.get 4) (i32.mul (local.get 8) (local.get 8)))
(if (result i32) (i32.gt_s (local.get 5) (local.get 8))
(then (local.get 8)) (else (local.get 5))
)
(if (result i32) (i32.lt_s (local.get 6) (local.get 8))
(then (local.get 8)) (else (local.get 6))
)
)
)
)
)
(func $main (export "main") (result i32 i32 f32 f32)
(call $rec
(i32.const 0)
(i32.const 6)
(i32.const 0)
(i32.const 0)
(i32.const 0)
(i32.const 1000)
(i32.const -1000)
)
)
(data (i32.const 0) "\\02\\13\\22\\04\\08\\30")
)`);
const main = ins.exports["main"];
assertEq(""+ main(), "2,48,19.16666603088379,16.836633682250977");
assertEq("" + ins.exports.rec(1, 5, 0, 0, 0, 1000, -1000), "4,34,16.25,11.627016067504883");
check_stub3: {
let options = getJitCompilerOptions();
if (!options["baseline.enable"]) break check_stub3;
const check = function() {
ins.exports.rec(1, 5, 0, 0, 0, 1000, -1000);
};
for (let i = options["baseline.warmup.trigger"] + 1; i--;)
check();
}
// Handling trap.
var ins = wasmEvalText(`(module
(func $fac-acc (export "fac") (param i64 i64) (result i64)
(if (result i64) (i64.eqz (local.get 0))
(then (unreachable))
(else
(return_call $fac-acc
(i64.sub (local.get 0) (i64.const 1))
(i64.mul (local.get 0) (local.get 1))
)
)
)
)
(func (export "main") (param i64) (result i64)
(call $fac-acc (local.get 0) (i64.const 1))
)
)`);
assertErrorMessage(() => ins.exports.main(4n), WebAssembly.RuntimeError, /unreachable executed/);
assertErrorMessage(() => ins.exports.fac(3n, 1n), WebAssembly.RuntimeError, /unreachable executed/);
// Performance and stack growth: calculating sum of numbers 1..40000000
var ins = wasmEvalText(`(module
(func $sum (param i32 i64) (result i64)
local.get 0
i32.eqz
if
local.get 1
return
else
local.get 0
i32.const 1
i32.sub
local.get 1
local.get 0
i64.extend_i32_s
i64.add
return_call $sum
end
unreachable
)
(func (export "main") (param i32) (result i64)
local.get 0
i64.const 0
call $sum
)
)`);
if (getBuildConfiguration("simulator")) {
assertEq(ins.exports.main(400000), 80000200000n);
} else {
assertEq(ins.exports.main(40000000), 800000020000000n);
}
// GC/externref shall not cling to the trampoline frame.
// The `return_call` caller will create a trampoline because the callee is
// an import. The caller will create a GC object and will hold in its frame
// and a WeakMap.
// Test if the created object is in the WeakMap even after gc().
var wm = new WeakMap();
var ins = wasmEvalText(`(module
(import "" "test" (func $test))
(func $sum (param i32 i64) (result i64)
local.get 0
i32.eqz
if
call $test
local.get 1
return
else
local.get 0
i32.const 1
i32.sub
local.get 1
local.get 0
i64.extend_i32_s
i64.add
return_call $sum
end
unreachable
)
(export "sum" (func $sum))
)`, {"": {
test() {
gc();
assertEq(nondeterministicGetWeakMapKeys(wm).length, 0);
}
}});
var ins2 = wasmEvalText(`(module
(import "" "add_ref" (func $add_ref (result externref)))
(import "" "use_ref" (func $use_ref (param externref)))
(import "" "sum" (func $sum (param i32 i64) (result i64)))
(global $g1 (mut i32) (i32.const 0))
(func (export "main_gc") (param i32) (result i64)
(local $ref externref)
call $add_ref
local.set $ref
local.get $ref
call $use_ref
block
global.get $g1
br_if 0
local.get 0
i64.const 0
return_call $sum
end
local.get $ref
call $use_ref
i64.const -1
)
)`, {"": {
sum: ins.exports.sum,
add_ref() {
const obj = {}; wm.set(obj, 'foo'); return obj;
},
use_ref(obj) {
assertEq(nondeterministicGetWeakMapKeys(wm).length, 1);
},
}});
assertEq(ins2.exports.main_gc(400000), 80000200000n);
assertEq(nondeterministicGetWeakMapKeys(wm).length, 0);