Source code

Revision control

Copy as Markdown

Other Tools

// |jit-test| --fast-warmup; --no-threads
// Bailing out from inside a call to a bound function must reconstruct |this| and
// the full argument list (bound arguments followed by actual arguments), for
// each combination of bound and actual argument counts.
//
// The bailout has to happen while the target is inlined into its caller, so it
// is triggered by reshaping |bail| after the callers are compiled: the shape
// guard for |bail.x| then fails inside the inlined target.
//
// Note: the call sites below are deliberately fixed-arity. Spread calls are not
// optimized by CallIRGenerator::tryAttachBoundFunction, so a spread call site
// would not exercise the bound function stubs at all.
const obj = {tag: "obj"};
const bail = {x: 1};
// No bound arguments.
function t0(a, b) {
const r = bail.x;
assertEq(this, obj);
assertEq(a, 10);
assertEq(b, 11);
return r;
}
const b0 = t0.bind(obj);
function callB0() { return b0(10, 11); }
// One bound argument.
function t1(a, b, c) {
const r = bail.x;
assertEq(this, obj);
assertEq(a, 1);
assertEq(b, 10);
assertEq(c, 11);
return r;
}
const b1 = t1.bind(obj, 1);
function callB1() { return b1(10, 11); }
// MaxInlineBoundArgs bound arguments.
function t3(a, b, c, d, e) {
const r = bail.x;
assertEq(this, obj);
assertEq(a, 1);
assertEq(b, 2);
assertEq(c, 3);
assertEq(d, 10);
assertEq(e, 11);
return r;
}
const b3 = t3.bind(obj, 1, 2, 3);
function callB3() { return b3(10, 11); }
// More than MaxInlineBoundArgs, so the bound arguments live in an array.
function t4(a, b, c, d, e, f) {
const r = bail.x;
assertEq(this, obj);
assertEq(a, 1);
assertEq(b, 2);
assertEq(c, 3);
assertEq(d, 4);
assertEq(e, 10);
assertEq(f, 11);
return r;
}
const b4 = t4.bind(obj, 1, 2, 3, 4);
function callB4() { return b4(10, 11); }
// Fewer arguments than the target's arity.
function tUnderflow(a, b, c, d) {
const r = bail.x;
assertEq(this, obj);
assertEq(a, 1);
assertEq(b, undefined);
assertEq(c, undefined);
assertEq(d, undefined);
return r;
}
const bUnderflow = tUnderflow.bind(obj, 1);
function callBUnderflow() { return bUnderflow(); }
// More arguments than the target's arity. Reading |arguments| here forces the
// overflow-argument path in InlineFrameIterator::readFrameArgsAndLocals.
function tOverflow(a) {
const r = bail.x;
assertEq(this, obj);
assertEq(a, 1);
assertEq(arguments.length, 4);
assertEq(arguments[1], 2);
assertEq(arguments[2], 10);
assertEq(arguments[3], 11);
return r;
}
const bOverflow = tOverflow.bind(obj, 1, 2);
function callBOverflow() { return bOverflow(10, 11); }
const cases = [callB0, callB1, callB3, callB4, callBUnderflow, callBOverflow];
with ({}) {}
for (var i = 0; i < 200; i++) {
for (var fn of cases) {
assertEq(fn(), 1);
}
}
bail.trigger = true;
for (var fn of cases) {
assertEq(fn(), 1);
}