blob: e00aada8f158971584149b906f32091794680102 [file] [log] [blame]
import * as assert from '../assert.js'
import Builder from '../Builder.js'
const verbose = false;
const maxInstructionCount = 500;
const instancesTotal = 8;
const invocationsTotal = 8;
const tierUpCalls = 20000; // Call enough to trigger tier up and get it to compile.
// This test starts running with a few bytes of executable memory available. Try
// to create and instantiate a module which will fail to fit.
const randomProgram = instructionCount => {
let b = new Builder()
.Type().End()
.Function().End()
.Export()
.Function("foo")
.Function("bar")
.End()
.Code()
.Function("foo", { params: [], ret: "f32" })
.F32Const(2.0)
.Return()
.End()
.Function("bar", { params: ["f32", "f32"], ret: "f32" })
.GetLocal(0);
// Insert a bunch of dependent instructions in a single basic block so that
// our compiler won't be able to strength-reduce.
const actions = [
b => b.GetLocal(0).F32Sub(),
b => b.GetLocal(1).F32Sub(),
b => b.GetLocal(0).F32Add(),
b => b.GetLocal(1).F32Add(),
b => b.GetLocal(0).F32Mul(),
b => b.GetLocal(1).F32Mul(),
];
while (--instructionCount)
b = actions[(Math.random() * actions.length) | 0](b);
b = b.Return().End().End();
return b.WebAssembly().get();
}
let failCount = 0;
let callCount = 0;
let instances = [];
const invoke = (instance, count) => {
if (verbose)
print(`Invoking`);
for (let i = 0; i < count; ++i)
assert.eq(instance.exports["foo"](), 2.0);
for (let i = 0; i < count; ++i)
instance.exports["bar"](2.0, 6.0);
++callCount;
};
while (failCount === 0) {
const instructionCount = (Math.random() * maxInstructionCount + 1) | 0;
if (verbose)
print(`Trying module with ${instructionCount} instructions.`);
const buf = randomProgram(instructionCount);
let module;
try {
module = new WebAssembly.Module(buf);
} catch (e) {
if (e instanceof WebAssembly.CompileError) {
if (verbose)
print(`Caught: ${e}`);
++failCount;
}
else
throw new Error(`Expected a WebAssembly.CompileError, got ${e}`);
}
if (module !== undefined) {
if (verbose)
print(`Creating instance`);
let instance;
try {
instance = new WebAssembly.Instance(module);
} catch (e) {
if (e instanceof WebAssembly.LinkError) {
if (verbose)
print(`Caught: ${e}`);
++failCount;
}
else
throw new Error(`Expected a WebAssembly.LinkError, got ${e}`);
}
if (instance !== undefined) {
instances.push(instance);
invoke(instance, 1);
}
}
}
if (callCount === 0)
throw new Error(`Expected to be able to allocate a WebAssembly module, instantiate it, and call its exports at least once`);
// Make sure we can still call all the instances we create, even after going
// OOM. This will try to force tier-up as well, which should fail.
if (verbose)
print(`Invoking all previously created instances`);
for (let instance of instances)
invoke(instance, tierUpCalls);
// Do it twice to revisit what should have gotten tiered up.
for (let instance of instances)
invoke(instance, 1);