зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1319203: Add tests; r=luke
MozReview-Commit-ID: 5Xf6NZRpQ4M --HG-- extra : rebase_source : 971bc1c9c6e9c87fdc3e9f75eaaab868a85800ad
This commit is contained in:
Родитель
f229366eba
Коммит
65b5cadd76
|
@ -172,3 +172,141 @@ function wasmGetScriptBreakpoints(wasmScript) {
|
|||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
const WasmHelpers = {};
|
||||
|
||||
(function() {
|
||||
let enabled = false;
|
||||
try {
|
||||
enableSingleStepProfiling();
|
||||
disableSingleStepProfiling();
|
||||
enabled = true;
|
||||
} catch (e) {
|
||||
print(e.message);
|
||||
}
|
||||
WasmHelpers.isSingleStepProfilingEnabled = enabled;
|
||||
})();
|
||||
|
||||
WasmHelpers._normalizeStack = (stack, preciseStacks) => {
|
||||
var wasmFrameTypes = [
|
||||
{re:/^jit call to int64 wasm function$/, sub:"i64>"},
|
||||
{re:/^out-of-line coercion for jit entry arguments \(in wasm\)$/, sub:"ool>"},
|
||||
{re:/^wasm-function\[(\d+)\] \(.*\)$/, sub:"$1"},
|
||||
{re:/^(fast|slow) exit trampoline (to native )?\(in wasm\)$/, sub:"<"},
|
||||
{re:/^call to[ asm.js]? native (.*) \(in wasm\)$/, sub:"$1"},
|
||||
{re:/ \(in wasm\)$/, sub:""}
|
||||
];
|
||||
|
||||
let entryRegexps;
|
||||
if (preciseStacks) {
|
||||
entryRegexps = [
|
||||
{re:/^slow entry trampoline \(in wasm\)$/, sub:"!>"},
|
||||
{re:/^fast entry trampoline \(in wasm\)$/, sub:">"},
|
||||
];
|
||||
} else {
|
||||
entryRegexps = [
|
||||
{re:/^(fast|slow) entry trampoline \(in wasm\)$/, sub:">"}
|
||||
];
|
||||
}
|
||||
wasmFrameTypes = entryRegexps.concat(wasmFrameTypes);
|
||||
|
||||
var framesIn = stack.split(',');
|
||||
var framesOut = [];
|
||||
for (let frame of framesIn) {
|
||||
for (let {re, sub} of wasmFrameTypes) {
|
||||
if (re.test(frame)) {
|
||||
framesOut.push(frame.replace(re, sub));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return framesOut.join(',');
|
||||
};
|
||||
|
||||
WasmHelpers._removeAdjacentDuplicates = array => {
|
||||
if (array.length < 2)
|
||||
return;
|
||||
let i = 0;
|
||||
for (let j = 1; j < array.length; j++) {
|
||||
if (array[i] !== array[j])
|
||||
array[++i] = array[j];
|
||||
}
|
||||
array.length = i + 1;
|
||||
}
|
||||
|
||||
WasmHelpers.normalizeStacks = (stacks, preciseStacks = false) => {
|
||||
let observed = [];
|
||||
for (let i = 0; i < stacks.length; i++)
|
||||
observed[i] = WasmHelpers._normalizeStack(stacks[i], preciseStacks);
|
||||
WasmHelpers._removeAdjacentDuplicates(observed);
|
||||
return observed;
|
||||
};
|
||||
|
||||
WasmHelpers._compareStacks = (got, expect) => {
|
||||
if (got.length != expect.length) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < got.length; i++) {
|
||||
if (got[i] !== expect[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
WasmHelpers.assertEqImpreciseStacks = (got, expect) => {
|
||||
let observed = WasmHelpers.normalizeStacks(got, /* precise */ false);
|
||||
let same = WasmHelpers._compareStacks(observed, expect);
|
||||
if (!same) {
|
||||
if (observed.length != expect.length) {
|
||||
print(`Got:\n${observed.toSource()}\nExpect:\n${expect.toSource()}`);
|
||||
assertEq(observed.length, expect.length);
|
||||
}
|
||||
for (let i = 0; i < observed.length; i++) {
|
||||
if (observed[i] !== expect[i]) {
|
||||
print(`On stack ${i}, Got:\n${observed[i]}\nExpect:\n${expect[i]}`);
|
||||
assertEq(observed[i], expect[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WasmHelpers.assertStackTrace = (exception, expected) => {
|
||||
let callsites = exception.stack.trim().split('\n').map(line => line.split('@')[0]);
|
||||
assertEq(callsites.length, expected.length);
|
||||
for (let i = 0; i < callsites.length; i++) {
|
||||
assertEq(callsites[i], expected[i]);
|
||||
}
|
||||
};
|
||||
|
||||
WasmHelpers.nextLineNumber = (n=1) => {
|
||||
return +(new Error().stack).split('\n')[1].split(':')[1] + n;
|
||||
}
|
||||
|
||||
WasmHelpers.startProfiling = () => {
|
||||
if (!WasmHelpers.isSingleStepProfilingEnabled)
|
||||
return;
|
||||
enableSingleStepProfiling();
|
||||
}
|
||||
|
||||
WasmHelpers.endProfiling = () => {
|
||||
if (!WasmHelpers.isSingleStepProfilingEnabled)
|
||||
return;
|
||||
return disableSingleStepProfiling();
|
||||
}
|
||||
|
||||
WasmHelpers.assertEqPreciseStacks = (observed, expectedStacks) => {
|
||||
if (!WasmHelpers.isSingleStepProfilingEnabled)
|
||||
return null;
|
||||
|
||||
observed = WasmHelpers.normalizeStacks(observed, /* precise */ true);
|
||||
|
||||
for (let i = 0; i < expectedStacks.length; i++) {
|
||||
if (WasmHelpers._compareStacks(observed, expectedStacks[i]))
|
||||
return i;
|
||||
}
|
||||
|
||||
throw new Error(`no plausible stacks found, observed: ${observed.join('/')}
|
||||
Expected one of:
|
||||
${expectedStacks.map(stacks => stacks.join("/")).join('\n')}`);
|
||||
}
|
||||
|
|
|
@ -37,10 +37,10 @@ function assertStackContainsSeq(got, expect)
|
|||
for (var j = 0; j < parts.length; j++) {
|
||||
var frame = parts[j];
|
||||
frame = frame.replace(/ \([^\)]*\)/g, "");
|
||||
frame = frame.replace(/fast FFI trampoline to native/g, "N");
|
||||
frame = frame.replace(/fast exit trampoline to native/g, "N");
|
||||
frame = frame.replace(/^call to( asm.js)? native .*\(in wasm\)$/g, "N");
|
||||
frame = frame.replace(/(fast|slow) FFI trampoline/g, "<");
|
||||
frame = frame.replace(/slow entry trampoline/g, ">");
|
||||
frame = frame.replace(/(fast|slow) exit trampoline/g, "<");
|
||||
frame = frame.replace(/(fast|slow) entry trampoline/g, ">");
|
||||
frame = frame.replace(/(\/[^\/,<]+)*\/testProfiling.js/g, "");
|
||||
frame = frame.replace(/testBuiltinD2D/g, "");
|
||||
frame = frame.replace(/testBuiltinF2F/g, "");
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
let { exports } = wasmEvalText(`(module
|
||||
(func (export "i32") (result i32) (param i32)
|
||||
get_local 0
|
||||
)
|
||||
|
||||
(func (export "f32") (result f32) (param f32)
|
||||
get_local 0
|
||||
)
|
||||
|
||||
(func (export "f64") (result f64) (param f64)
|
||||
get_local 0
|
||||
)
|
||||
)`);
|
||||
|
||||
const options = getJitCompilerOptions();
|
||||
const jitThreshold = options['ion.warmup.trigger'] * 2;
|
||||
|
||||
let coercions = {
|
||||
i32(x) { return x|0; },
|
||||
f32(x) { return Math.fround(x); },
|
||||
f64(x) { return +x; }
|
||||
}
|
||||
|
||||
function call(func, coercion, arg) {
|
||||
let expected;
|
||||
try {
|
||||
expected = coercion(arg);
|
||||
} catch(e) {
|
||||
expected = e.message;
|
||||
}
|
||||
|
||||
for (var i = jitThreshold; i --> 0;) {
|
||||
try {
|
||||
assertEq(func(arg), expected);
|
||||
} catch(e) {
|
||||
assertEq(e.message, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const inputs = [
|
||||
42,
|
||||
3.5,
|
||||
-0,
|
||||
-Infinity,
|
||||
2**32,
|
||||
true,
|
||||
Symbol(),
|
||||
undefined,
|
||||
null,
|
||||
{},
|
||||
{ valueOf() { return 13.37; } },
|
||||
"bonjour"
|
||||
];
|
||||
|
||||
for (let arg of inputs) {
|
||||
for (let func of ['i32', 'f32', 'f64']) {
|
||||
call(exports[func], coercions[func], arg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
if (typeof evaluate === 'undefined')
|
||||
quit();
|
||||
|
||||
evaluate(`
|
||||
var f = (function module() {
|
||||
"use asm";
|
||||
function f(i) {
|
||||
i=i|0;
|
||||
if (!i)
|
||||
return;
|
||||
}
|
||||
return f;
|
||||
})();
|
||||
evaluate(\`new f({}, {});\`);
|
||||
`);
|
|
@ -0,0 +1,18 @@
|
|||
var g = newGlobal();
|
||||
g.parent = this;
|
||||
g.eval("Debugger(parent).onExceptionUnwind = function () {};");
|
||||
lfModule = new WebAssembly.Module(wasmTextToBinary(`
|
||||
(module
|
||||
(export "f" $func0)
|
||||
(func $func0 (result i32)
|
||||
i32.const -1
|
||||
)
|
||||
)
|
||||
`));
|
||||
processModule(lfModule);
|
||||
function processModule(module, jscode) {
|
||||
for (let i = 0; i < 2; ++i) {
|
||||
imports = {}
|
||||
instance = new WebAssembly.Instance(module, imports);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
const options = getJitCompilerOptions();
|
||||
|
||||
// These tests need at least baseline to make sense.
|
||||
if (!options['baseline.enable'])
|
||||
quit();
|
||||
|
||||
const { nextLineNumber, startProfiling, endProfiling, assertEqPreciseStacks } = WasmHelpers;
|
||||
|
||||
const TRIGGER = options['ion.warmup.trigger'] + 10;
|
||||
const ITER = 2 * TRIGGER;
|
||||
const EXCEPTION_ITER = ITER - 2;
|
||||
|
||||
enableGeckoProfiling();
|
||||
|
||||
var instance = wasmEvalText(`(module
|
||||
(func $add (export "add") (result i32) (param i32) (param i32)
|
||||
get_local 0
|
||||
get_local 1
|
||||
i32.add
|
||||
)
|
||||
|
||||
(func $addi64 (export "add64") (result i64) (param i32) (param i32)
|
||||
get_local 0
|
||||
get_local 1
|
||||
call $add
|
||||
i64.extend_s/i32
|
||||
)
|
||||
)`).exports;
|
||||
|
||||
var callToMain;
|
||||
|
||||
function main() {
|
||||
var arr = [instance.add, (x,y)=>x+y];
|
||||
var arrayCallLine = nextLineNumber(6);
|
||||
for (var i = 0; i < ITER; i++) {
|
||||
var caught = null;
|
||||
|
||||
startProfiling();
|
||||
try {
|
||||
arr[i%2](i, i);
|
||||
} catch(e) {
|
||||
caught = e;
|
||||
}
|
||||
let profilingStack = endProfiling();
|
||||
|
||||
if (i === EXCEPTION_ITER - 1) {
|
||||
arr[0] = instance.add64;
|
||||
} else if (i === EXCEPTION_ITER) {
|
||||
arr[0] = instance.add;
|
||||
}
|
||||
|
||||
assertEq(!!caught, i === EXCEPTION_ITER);
|
||||
if (caught) {
|
||||
assertEqPreciseStacks(profilingStack, [
|
||||
// Error stack: control flow is redirected to a builtin thunk
|
||||
// then calling into C++ from the wasm entry before jumping to
|
||||
// the wasm jit entry exception handler.
|
||||
['', '>', '<,>', 'i64>,>', '<,>', '>', ''],
|
||||
[''] // the jit path wasn't taken (interpreter/baseline only).
|
||||
]);
|
||||
|
||||
assertEq(caught.message, 'cannot pass i64 to or from JS');
|
||||
|
||||
let stack = caught.stack.split('\n');
|
||||
|
||||
// Which callsites appear on the error stack.
|
||||
let callsites = stack.map(s => s.split('@')[0]);
|
||||
assertEq(callsites[0], 'main');
|
||||
assertEq(callsites[1], ''); // global scope
|
||||
|
||||
// Which line numbers appear in the error stack.
|
||||
let lines = stack.map(s => s.split(':')[1]);
|
||||
assertEq(+lines[0], arrayCallLine);
|
||||
assertEq(+lines[1], callToMain);
|
||||
} else if ((i % 2) == 0) {
|
||||
assertEqPreciseStacks(profilingStack, [
|
||||
['', '>', '0,>', '>', ''], // fast path
|
||||
['', '!>', '0,!>', '!>', ''], // slow path
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
callToMain = nextLineNumber();
|
||||
main();
|
|
@ -0,0 +1,78 @@
|
|||
const options = getJitCompilerOptions();
|
||||
|
||||
// These tests need at least baseline to make sense.
|
||||
if (!options['baseline.enable'])
|
||||
quit();
|
||||
|
||||
const { assertStackTrace, startProfiling, endProfiling, assertEqPreciseStacks } = WasmHelpers;
|
||||
|
||||
const TRIGGER = options['baseline.warmup.trigger'] + 10;
|
||||
const ITER = 2 * TRIGGER;
|
||||
const EXCEPTION_ITER = TRIGGER + 5;
|
||||
|
||||
const SLOW_ENTRY_STACK = ['', '!>', '0,!>', '!>', ''];
|
||||
const FAST_ENTRY_STACK = ['', '>', '0,>', '>', ''];
|
||||
const FAST_OOL_ENTRY_STACK = ['', '>', '<,>', 'ool>,>', '<,>', '>', '0,>', '>', ''];
|
||||
const EXCEPTION_ENTRY_STACK = ['', '>', '<,>', 'ool>,>', '<,>', '>', ''];
|
||||
|
||||
enableGeckoProfiling();
|
||||
|
||||
for (let type of ['i32', 'f32', 'f64']) {
|
||||
var instance = wasmEvalText(`(module
|
||||
(func $add (export "add") (result ${type}) (param ${type}) (param ${type})
|
||||
get_local 0
|
||||
get_local 1
|
||||
${type}.add
|
||||
)
|
||||
)`).exports;
|
||||
|
||||
function loopBody(a, b) {
|
||||
var caught = null;
|
||||
try {
|
||||
instance.add(a, b);
|
||||
} catch(e) {
|
||||
assertEq(e.message, "ph34r");
|
||||
assertStackTrace(e, ['innerValueOf', 'outerValueOf', 'loopBody', 'main', '']);
|
||||
caught = e;
|
||||
}
|
||||
assertEq(!!caught, b === EXCEPTION_ITER);
|
||||
}
|
||||
|
||||
var x = 0;
|
||||
function main() {
|
||||
let observedStacks = [0, 0, 0];
|
||||
for (var i = 0; i < ITER; i++) {
|
||||
startProfiling();
|
||||
loopBody(i + 1, i + EXCEPTION_ITER + 1);
|
||||
assertEqPreciseStacks(endProfiling(), [FAST_ENTRY_STACK, SLOW_ENTRY_STACK]);
|
||||
|
||||
if (i === EXCEPTION_ITER) {
|
||||
x = { valueOf: function innerValueOf() { throw new Error("ph34r"); }};
|
||||
} else {
|
||||
x = i;
|
||||
}
|
||||
|
||||
startProfiling();
|
||||
loopBody({valueOf: function outerValueOf() { return x|0; }}, i);
|
||||
let stack = endProfiling();
|
||||
let which = assertEqPreciseStacks(stack, [FAST_OOL_ENTRY_STACK, SLOW_ENTRY_STACK, EXCEPTION_ENTRY_STACK]);
|
||||
if (which !== null) {
|
||||
if (i === EXCEPTION_ITER) {
|
||||
assertEq(which, 2);
|
||||
}
|
||||
observedStacks[which]++;
|
||||
}
|
||||
}
|
||||
|
||||
let sum = observedStacks.reduce((acc, x) => acc + x);
|
||||
assertEq(sum === 0 || sum === ITER, true);
|
||||
if (sum === ITER) {
|
||||
assertEq(observedStacks[0] > 0, true, "the fast entry should have been taken at least once");
|
||||
assertEq(observedStacks[2], 1, "the error path should have been taken exactly once");
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
}
|
||||
|
||||
disableGeckoProfiling();
|
|
@ -0,0 +1,126 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// FIRST TEST /////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
(function() {
|
||||
|
||||
function debug() {
|
||||
throw new Error('gotcha');
|
||||
}
|
||||
|
||||
var imports = {
|
||||
numCalls:0,
|
||||
main: {
|
||||
f() {
|
||||
debug();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var instance = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(`(module
|
||||
(import $main "main" "f" (func))
|
||||
(func $lol (export "add") (result i32) (param i32) (param i32)
|
||||
get_local 0
|
||||
get_local 1
|
||||
call $add
|
||||
)
|
||||
(func $add (result i32) (param i32) (param i32)
|
||||
get_local 0
|
||||
i32.const 5000
|
||||
i32.eq
|
||||
if
|
||||
call $main
|
||||
end
|
||||
|
||||
get_local 0
|
||||
get_local 1
|
||||
i32.add
|
||||
)
|
||||
)`)), imports).exports;
|
||||
|
||||
function loopBody(i) {
|
||||
var caught = null;
|
||||
try {
|
||||
assertEq(instance.add(i, i), 2 * i);
|
||||
} catch(e) {
|
||||
// TODO check stack trace
|
||||
print(e.stack);
|
||||
caught = e;
|
||||
}
|
||||
assertEq(!!caught, i === 5000);
|
||||
}
|
||||
|
||||
function main() {
|
||||
for (var i = 0; i < 100000; i++) {
|
||||
loopBody(i);
|
||||
}
|
||||
assertEq(i, 100000);
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
})();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SECOND TEST ////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
(function() {
|
||||
|
||||
function debug() {
|
||||
gc();
|
||||
}
|
||||
|
||||
var imports = {
|
||||
numCalls:0,
|
||||
main: {
|
||||
f() {
|
||||
debug();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var instance = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(`(module
|
||||
(import $main "main" "f" (func))
|
||||
(func $lol (export "add") (result i32) (param i32) (param i32)
|
||||
get_local 0
|
||||
get_local 1
|
||||
call $add
|
||||
)
|
||||
(func $add (result i32) (param i32) (param i32)
|
||||
get_local 0
|
||||
i32.const 5000
|
||||
i32.eq
|
||||
if
|
||||
call $main
|
||||
unreachable
|
||||
end
|
||||
|
||||
get_local 0
|
||||
get_local 1
|
||||
i32.add
|
||||
)
|
||||
)`)), imports).exports;
|
||||
|
||||
function loopBody(i) {
|
||||
var caught = null;
|
||||
try {
|
||||
assertEq(instance.add(i, i), 2 * i);
|
||||
} catch(e) {
|
||||
// TODO check stack trace
|
||||
print(e.stack);
|
||||
caught = e;
|
||||
}
|
||||
assertEq(!!caught, i === 5000);
|
||||
}
|
||||
|
||||
function main() {
|
||||
for (var i = 0; i < 100000; i++) {
|
||||
loopBody(i);
|
||||
}
|
||||
assertEq(i, 100000);
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
})();
|
|
@ -0,0 +1,55 @@
|
|||
const options = getJitCompilerOptions();
|
||||
|
||||
// These tests need at least baseline to make sense.
|
||||
if (!options['baseline.enable'])
|
||||
quit();
|
||||
|
||||
const TRIGGER = options['baseline.warmup.trigger'] + 10;
|
||||
const ITER = 2 * TRIGGER;
|
||||
const EXCEPTION_ITER = TRIGGER + 5;
|
||||
|
||||
for (let type of ['i32', 'f32', 'f64']) {
|
||||
var instance = wasmEvalText(`(module
|
||||
(func $add (export "add") (result ${type}) (param ${type}) (param ${type})
|
||||
get_local 0
|
||||
get_local 1
|
||||
${type}.add
|
||||
)
|
||||
)`).exports;
|
||||
|
||||
function loopBody(a, b) {
|
||||
var caught = null;
|
||||
try {
|
||||
instance.add(a, b);
|
||||
} catch(e) {
|
||||
caught = e;
|
||||
}
|
||||
assertEq(!!caught, b === EXCEPTION_ITER);
|
||||
}
|
||||
|
||||
var x = 0;
|
||||
function main() {
|
||||
for (var i = 0; i <= EXCEPTION_ITER; i++) {
|
||||
loopBody(i + 1, i + EXCEPTION_ITER + 1);
|
||||
|
||||
let otherArg = { valueOf() { return i|0; } };
|
||||
|
||||
if (i === EXCEPTION_ITER) {
|
||||
x = { valueOf: function innerValueOf() {
|
||||
// Supress callee.
|
||||
instance = null;
|
||||
// Suppress other arguments.
|
||||
otherArg = null;
|
||||
gc();
|
||||
return 42;
|
||||
}};
|
||||
} else {
|
||||
x = i;
|
||||
}
|
||||
|
||||
loopBody({valueOf: function outerValueOf() { return x|0; }}, otherArg);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
var ITERATIONS = 10;
|
||||
var INNER_ITERATIONS = 100;
|
||||
|
||||
let instance = wasmEvalText(`(module
|
||||
(func (export "add") (result i32) (param i32) (param i32)
|
||||
get_local 0
|
||||
get_local 1
|
||||
i32.add
|
||||
)
|
||||
|
||||
(func (export "no_arg") (result i32)
|
||||
i32.const 42
|
||||
i32.const 58
|
||||
i32.add
|
||||
)
|
||||
|
||||
(global $g (mut i32) (i32.const 0))
|
||||
|
||||
(func (export "set_global_one") (param i32)
|
||||
get_local 0
|
||||
set_global $g
|
||||
)
|
||||
|
||||
(func (export "set_global_two") (param i32) (param i32)
|
||||
get_local 0
|
||||
get_local 1
|
||||
i32.add
|
||||
set_global $g
|
||||
)
|
||||
|
||||
(func (export "glob") (result i32)
|
||||
get_global $g
|
||||
)
|
||||
)`).exports;
|
||||
|
||||
function run(name, func) {
|
||||
for (let i = ITERATIONS; i --> 0;) {
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
function testCallKnown() {
|
||||
for (let i = 0; i < INNER_ITERATIONS; i++) {
|
||||
assertEq(instance.add(i, i + 1), 2*i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
function testCallKnownRectifying() {
|
||||
for (let i = 0; i < INNER_ITERATIONS; i++) {
|
||||
assertEq(instance.add(i + 1), i+1);
|
||||
}
|
||||
}
|
||||
|
||||
function jsAdd(x, y) {
|
||||
return (x|0) + (y|0) | 0;
|
||||
}
|
||||
|
||||
function testCallGeneric() {
|
||||
var arr = [instance.add, jsAdd];
|
||||
for (let i = 0; i < INNER_ITERATIONS; i++) {
|
||||
assertEq(arr[i%2](i, i+1), 2*i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
function testCallGenericRectifying() {
|
||||
var arr = [instance.add, jsAdd];
|
||||
for (let i = 0; i < INNER_ITERATIONS; i++) {
|
||||
assertEq(arr[i%2](i+1), i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
function testCallScriptedGetter() {
|
||||
var obj = {};
|
||||
Object.defineProperty(obj, 'x', {
|
||||
get: instance.no_arg
|
||||
});
|
||||
for (let i = 0; i < INNER_ITERATIONS; i++) {
|
||||
assertEq(obj.x, 100);
|
||||
}
|
||||
}
|
||||
|
||||
function testCallScriptedGetterRectifying() {
|
||||
var obj = {};
|
||||
Object.defineProperty(obj, 'x', {
|
||||
// Missing two arguments.
|
||||
get: instance.add
|
||||
});
|
||||
for (let i = 0; i < INNER_ITERATIONS; i++) {
|
||||
assertEq(obj.x, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function testCallScriptedSetter() {
|
||||
var obj = {};
|
||||
Object.defineProperty(obj, 'x', {
|
||||
set: instance.set_global_one
|
||||
});
|
||||
for (let i = 0; i < INNER_ITERATIONS; i++) {
|
||||
obj.x = i;
|
||||
}
|
||||
assertEq(instance.glob(), INNER_ITERATIONS-1);
|
||||
}
|
||||
|
||||
function testCallScriptedSetterRectifying() {
|
||||
var obj = {};
|
||||
Object.defineProperty(obj, 'x', {
|
||||
set: instance.set_global_two
|
||||
});
|
||||
for (let i = 0; i < INNER_ITERATIONS; i++) {
|
||||
obj.x = i;
|
||||
}
|
||||
assertEq(instance.glob(), INNER_ITERATIONS-1);
|
||||
}
|
||||
|
||||
function testFunctionApplyArray() {
|
||||
for (let i = 0; i < INNER_ITERATIONS; i++) {
|
||||
assertEq(instance.add.apply(null, [i, i + 1]), 2*i+1);
|
||||
}
|
||||
}
|
||||
|
||||
function testFunctionApplyArrayRectifying() {
|
||||
for (let i = 0; i < INNER_ITERATIONS; i++) {
|
||||
assertEq(instance.add.apply(null, [i + 1]), i+1);
|
||||
}
|
||||
}
|
||||
|
||||
function testFunctionApplyArgs() {
|
||||
function wrapper() {
|
||||
assertEq(instance.add.apply(null, arguments), 2*arguments[0]+1);
|
||||
}
|
||||
for (let i = 0; i < INNER_ITERATIONS; i++) {
|
||||
wrapper(i, i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
function testFunctionApplyArgsRectifying() {
|
||||
function wrapper() {
|
||||
assertEq(instance.add.apply(null, arguments), arguments[0]);
|
||||
}
|
||||
for (let i = 0; i < INNER_ITERATIONS; i++) {
|
||||
wrapper(i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
function testFunctionCall() {
|
||||
for (let i = 0; i < INNER_ITERATIONS; i++) {
|
||||
assertEq(instance.add.call(null, i, i + 1), 2*i+1);
|
||||
}
|
||||
}
|
||||
|
||||
function testFunctionCallRectifying() {
|
||||
for (let i = 0; i < INNER_ITERATIONS; i++) {
|
||||
assertEq(instance.add.call(null, i + 1), i+1);
|
||||
}
|
||||
}
|
||||
|
||||
run('call known', testCallKnown);
|
||||
run('call known rectifying', testCallKnownRectifying);
|
||||
|
||||
run('call generic', testCallGeneric);
|
||||
run('call generic rectifying', testCallGenericRectifying);
|
||||
|
||||
run('scripted getter', testCallScriptedGetter);
|
||||
run('scripted getter rectifiying', testCallScriptedGetterRectifying);
|
||||
run('scripted setter', testCallScriptedSetter);
|
||||
run('scripted setter rectifiying', testCallScriptedSetterRectifying);
|
||||
|
||||
run('function.apply array', testFunctionApplyArray);
|
||||
run('function.apply array rectifying', testFunctionApplyArrayRectifying);
|
||||
run('function.apply args', testFunctionApplyArgs);
|
||||
run('function.apply args rectifying', testFunctionApplyArgsRectifying);
|
||||
|
||||
run('function.call', testFunctionCall);
|
||||
run('function.call rectifying', testFunctionCallRectifying);
|
|
@ -1,78 +1,20 @@
|
|||
try {
|
||||
enableSingleStepProfiling();
|
||||
disableSingleStepProfiling();
|
||||
} catch(e) {
|
||||
// Single step profiling not supported here.
|
||||
if (!WasmHelpers.isSingleStepProfilingEnabled)
|
||||
quit();
|
||||
}
|
||||
|
||||
const Module = WebAssembly.Module;
|
||||
const Instance = WebAssembly.Instance;
|
||||
const Table = WebAssembly.Table;
|
||||
|
||||
function normalize(stack)
|
||||
{
|
||||
var wasmFrameTypes = [
|
||||
{re:/^slow entry trampoline \(in wasm\)$/, sub:">"},
|
||||
{re:/^wasm-function\[(\d+)\] \(.*\)$/, sub:"$1"},
|
||||
{re:/^(fast|slow) FFI trampoline (to native )?\(in wasm\)$/, sub:"<"},
|
||||
{re:/^call to[ asm.js]? native (.*) \(in wasm\)$/, sub:"$1"},
|
||||
{re:/ \(in wasm\)$/, sub:""}
|
||||
];
|
||||
const { assertEqImpreciseStacks, startProfiling, endProfiling } = WasmHelpers;
|
||||
|
||||
var framesIn = stack.split(',');
|
||||
var framesOut = [];
|
||||
for (let frame of framesIn) {
|
||||
for (let {re, sub} of wasmFrameTypes) {
|
||||
if (re.test(frame)) {
|
||||
framesOut.push(frame.replace(re, sub));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return framesOut.join(',');
|
||||
}
|
||||
|
||||
function removeAdjacentDuplicates(array) {
|
||||
if (array.length < 2)
|
||||
return;
|
||||
let i = 0;
|
||||
for (let j = 1; j < array.length; j++) {
|
||||
if (array[i] !== array[j])
|
||||
array[++i] = array[j];
|
||||
}
|
||||
array.length = i + 1;
|
||||
}
|
||||
|
||||
function assertEqStacks(got, expect)
|
||||
{
|
||||
for (let i = 0; i < got.length; i++)
|
||||
got[i] = normalize(got[i]);
|
||||
|
||||
removeAdjacentDuplicates(got);
|
||||
|
||||
if (got.length != expect.length) {
|
||||
print(`Got:\n${got.toSource()}\nExpect:\n${expect.toSource()}`);
|
||||
assertEq(got.length, expect.length);
|
||||
}
|
||||
|
||||
for (let i = 0; i < got.length; i++) {
|
||||
if (got[i] !== expect[i]) {
|
||||
print(`On stack ${i}, Got:\n${got[i]}\nExpect:\n${expect[i]}`);
|
||||
assertEq(got[i], expect[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function test(code, importObj, expect)
|
||||
function test(code, importObj, expectedStacks)
|
||||
{
|
||||
enableGeckoProfiling();
|
||||
|
||||
var f = wasmEvalText(code, importObj).exports[""];
|
||||
enableSingleStepProfiling();
|
||||
startProfiling();
|
||||
f();
|
||||
assertEqStacks(disableSingleStepProfiling(), expect);
|
||||
assertEqImpreciseStacks(endProfiling(), expectedStacks);
|
||||
|
||||
disableGeckoProfiling();
|
||||
}
|
||||
|
@ -137,7 +79,8 @@ if (getBuildConfiguration()["arm-simulator"]) {
|
|||
)
|
||||
)`,
|
||||
this,
|
||||
["", ">", "0,>", "<,0,>", `i64.${op},0,>`, "<,0,>", "0,>", ">", ""]);
|
||||
["", ">", "0,>", "<,0,>", `i64.${op},0,>`, "<,0,>", "0,>", ">", ""],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,7 +92,8 @@ test(`(module
|
|||
)
|
||||
)`,
|
||||
this,
|
||||
["", ">", "0,>", "<,0,>", "current_memory,0,>", "<,0,>", "0,>", ">", ""]);
|
||||
["", ">", "0,>", "<,0,>", "current_memory,0,>", "<,0,>", "0,>", ">", ""],
|
||||
);
|
||||
|
||||
// grow_memory is a callout.
|
||||
test(`(module
|
||||
|
@ -160,7 +104,8 @@ test(`(module
|
|||
)
|
||||
)`,
|
||||
this,
|
||||
["", ">", "0,>", "<,0,>", "grow_memory,0,>", "<,0,>", "0,>", ">", ""]);
|
||||
["", ">", "0,>", "<,0,>", "grow_memory,0,>", "<,0,>", "0,>", ">", ""],
|
||||
);
|
||||
|
||||
// A few math builtins.
|
||||
for (let type of ['f32', 'f64']) {
|
||||
|
@ -184,7 +129,7 @@ for (let type of ['f32', 'f64']) {
|
|||
var f = wasmEvalText(code).exports[""];
|
||||
enableSingleStepProfiling();
|
||||
assertThrowsInstanceOf(f, error);
|
||||
assertEqStacks(disableSingleStepProfiling(), expect);
|
||||
assertEqImpreciseStacks(disableSingleStepProfiling(), expect);
|
||||
disableGeckoProfiling();
|
||||
}
|
||||
|
||||
|
@ -230,7 +175,7 @@ for (let type of ['f32', 'f64']) {
|
|||
enableGeckoProfiling();
|
||||
enableSingleStepProfiling();
|
||||
assertEq(e.tbl.get(0)(), 42);
|
||||
assertEqStacks(disableSingleStepProfiling(), ["", ">", "0,>", ">", ""]);
|
||||
assertEqImpreciseStacks(disableSingleStepProfiling(), ["", ">", "0,>", ">", ""]);
|
||||
disableGeckoProfiling();
|
||||
|
||||
assertEq(e.foo(), 42);
|
||||
|
@ -240,7 +185,7 @@ for (let type of ['f32', 'f64']) {
|
|||
enableGeckoProfiling();
|
||||
enableSingleStepProfiling();
|
||||
assertEq(e.tbl.get(1)(), 13);
|
||||
assertEqStacks(disableSingleStepProfiling(), ["", ">", "1,>", ">", ""]);
|
||||
assertEqImpreciseStacks(disableSingleStepProfiling(), ["", ">", "1,>", ">", ""]);
|
||||
disableGeckoProfiling();
|
||||
|
||||
assertEq(e.tbl.get(0)(), 42);
|
||||
|
@ -251,7 +196,7 @@ for (let type of ['f32', 'f64']) {
|
|||
enableSingleStepProfiling();
|
||||
assertEq(e.foo(), 42);
|
||||
assertEq(e.tbl.get(1)(), 13);
|
||||
assertEqStacks(disableSingleStepProfiling(), ["", ">", "0,>", ">", "", ">", "1,>", ">", ""]);
|
||||
assertEqImpreciseStacks(disableSingleStepProfiling(), ["", ">", "0,>", ">", "", ">", "1,>", ">", ""]);
|
||||
disableGeckoProfiling();
|
||||
|
||||
var e2 = wasmEvalText(`
|
||||
|
@ -267,19 +212,19 @@ for (let type of ['f32', 'f64']) {
|
|||
enableGeckoProfiling();
|
||||
enableSingleStepProfiling();
|
||||
assertEq(e2.baz(0), 42);
|
||||
assertEqStacks(disableSingleStepProfiling(), ["", ">", "1,>", "0,1,>", "1,>", ">", ""]);
|
||||
assertEqImpreciseStacks(disableSingleStepProfiling(), ["", ">", "1,>", "0,1,>", "1,>", ">", ""]);
|
||||
disableGeckoProfiling();
|
||||
|
||||
enableGeckoProfiling();
|
||||
enableSingleStepProfiling();
|
||||
assertEq(e2.baz(1), 13);
|
||||
assertEqStacks(disableSingleStepProfiling(), ["", ">", "1,>", "1,1,>", "1,>", ">", ""]);
|
||||
assertEqImpreciseStacks(disableSingleStepProfiling(), ["", ">", "1,>", "1,1,>", "1,>", ">", ""]);
|
||||
disableGeckoProfiling();
|
||||
|
||||
enableGeckoProfiling();
|
||||
enableSingleStepProfiling();
|
||||
assertEq(e2.baz(2), 99);
|
||||
assertEqStacks(disableSingleStepProfiling(), ["", ">", "1,>", "0,1,>", "1,>", ">", ""]);
|
||||
assertEqImpreciseStacks(disableSingleStepProfiling(), ["", ">", "1,>", "0,1,>", "1,>", ">", ""]);
|
||||
disableGeckoProfiling();
|
||||
})();
|
||||
|
||||
|
@ -301,7 +246,7 @@ for (let type of ['f32', 'f64']) {
|
|||
enableGeckoProfiling();
|
||||
enableSingleStepProfiling();
|
||||
assertEq(e2.bar(), 42);
|
||||
assertEqStacks(disableSingleStepProfiling(), ["", ">", "1,>", "0,1,>", "1,>", ">", ""]);
|
||||
assertEqImpreciseStacks(disableSingleStepProfiling(), ["", ">", "1,>", "0,1,>", "1,>", ">", ""]);
|
||||
disableGeckoProfiling();
|
||||
assertEq(e2.bar(), 42);
|
||||
|
||||
|
@ -311,7 +256,7 @@ for (let type of ['f32', 'f64']) {
|
|||
var e4 = new Instance(m2, {a:e3}).exports;
|
||||
enableSingleStepProfiling();
|
||||
assertEq(e4.bar(), 42);
|
||||
assertEqStacks(disableSingleStepProfiling(), ["", ">", "1,>", "0,1,>", "1,>", ">", ""]);
|
||||
assertEqImpreciseStacks(disableSingleStepProfiling(), ["", ">", "1,>", "0,1,>", "1,>", ">", ""]);
|
||||
disableGeckoProfiling();
|
||||
assertEq(e4.bar(), 42);
|
||||
})();
|
||||
|
@ -377,7 +322,7 @@ for (let type of ['f32', 'f64']) {
|
|||
// Test normal conditions.
|
||||
enableSingleStepProfiling();
|
||||
assertEq(i.foo(0), 42);
|
||||
assertEqStacks(disableSingleStepProfiling(), ["", ">", "2,>", "<,2,>",
|
||||
assertEqImpreciseStacks(disableSingleStepProfiling(), ["", ">", "2,>", "<,2,>",
|
||||
// Losing stack information while the JIT func prologue sets profiler
|
||||
// virtual FP.
|
||||
"",
|
||||
|
@ -394,7 +339,7 @@ for (let type of ['f32', 'f64']) {
|
|||
// Test rectifier frame.
|
||||
enableSingleStepProfiling();
|
||||
assertEq(i.id(100), 100);
|
||||
assertEqStacks(disableSingleStepProfiling(), ["", ">", "3,>", "<,3,>",
|
||||
assertEqImpreciseStacks(disableSingleStepProfiling(), ["", ">", "3,>", "<,3,>",
|
||||
// Rectifier frame time is spent here (lastProfilingFrame has not been
|
||||
// set).
|
||||
"",
|
||||
|
@ -409,7 +354,7 @@ for (let type of ['f32', 'f64']) {
|
|||
|
||||
enableSingleStepProfiling();
|
||||
assertEq(i.foo(1337), -(2**31));
|
||||
assertEqStacks(disableSingleStepProfiling(), ["", ">", "2,>", "<,2,>", "", "<,2,>", "",
|
||||
assertEqImpreciseStacks(disableSingleStepProfiling(), ["", ">", "2,>", "<,2,>", "", "<,2,>", "",
|
||||
// Back into the jit exit (frame info has been recovered).
|
||||
// Inline conversion fails, we skip to the OOL path, call from there
|
||||
// and get back to the jit exit.
|
||||
|
|
Загрузка…
Ссылка в новой задаче