Source code
Revision control
Copy as Markdown
Other Tools
// Prevent GC from cancelling/discarding Ion compilations.
gczeal(0);
// This function is used to force a bailout when it is inlined, and to recover
// the frame which is inlining this function.
var resumeHere = function (i) { if (i >= 99) bailout(); };
// This function is used to cause an invalidation after having removed a branch
// after DCE. This is made to check if we correctly recover an array
// allocation.
var uceFault = function (i) {
if (i > 98)
uceFault = function (i) { return true; };
return false;
};
function empty() {}
var globalArgs;
function escape(args) { globalArgs = args; }
// Check rest array length.
function length(i, ...rest) {
assertRecoveredOnBailout(rest, true);
return rest.length;
}
function lengthBail(i, ...rest) {
resumeHere(i);
assertRecoveredOnBailout(rest, true);
return rest.length;
}
// Check rest array content.
function content(...rest) {
assertEq(rest[0], rest[1]);
assertRecoveredOnBailout(rest, true);
return rest.length;
}
function contentBail(...rest) {
resumeHere(rest[0]);
assertEq(rest[0], rest[1]);
assertRecoveredOnBailout(rest, true);
return rest.length;
}
function contentExtraFormals(i, ...rest) {
assertEq(rest[0], i);
assertRecoveredOnBailout(rest, true);
return rest.length;
}
function contentExtraFormalsBail(i, ...rest) {
resumeHere(i);
assertEq(rest[0], i);
assertRecoveredOnBailout(rest, true);
return rest.length;
}
// No scalar replacement when the rest array is modified.
function setLength(i, ...rest) {
rest.length = 0;
assertRecoveredOnBailout(rest, false);
return rest.length;
}
function setLengthBail(i, ...rest) {
resumeHere(i);
rest.length = 0;
assertRecoveredOnBailout(rest, false);
return rest.length;
}
function setContent(i, ...rest) {
rest[0] = "bad";
assertRecoveredOnBailout(rest, false);
return rest.length;
}
function setContentBail(i, ...rest) {
resumeHere(i);
rest[0] = "bad";
assertRecoveredOnBailout(rest, false);
return rest.length;
}
function deleteContent(i, ...rest) {
delete rest[0];
assertRecoveredOnBailout(rest, false);
return rest.length;
}
function deleteContentBail(i, ...rest) {
resumeHere(i);
delete rest[0];
assertRecoveredOnBailout(rest, false);
return rest.length;
}
// No scalar replacement when the rest array escapes.
function escapes(i, ...rest) {
escape(rest);
assertRecoveredOnBailout(rest, false);
return rest.length;
}
function escapesBail(i, ...rest) {
resumeHere(i);
escape(rest);
assertRecoveredOnBailout(rest, false);
return rest.length;
}
// Check rest array with Function.prototype.apply.
function apply(...rest) {
empty.apply(null, rest);
assertRecoveredOnBailout(rest, true);
return rest.length;
}
function applyBail(...rest) {
resumeHere(rest[0]);
empty.apply(null, rest);
assertRecoveredOnBailout(rest, true);
return rest.length;
}
function applyExtraFormals(i, ...rest) {
empty.apply(null, rest);
assertRecoveredOnBailout(rest, true);
return rest.length;
}
function applyExtraFormalsBail(i, ...rest) {
resumeHere(i);
empty.apply(null, rest);
assertRecoveredOnBailout(rest, true);
return rest.length;
}
// Check rest array with spread.
function spread(...rest) {
empty(...rest);
assertRecoveredOnBailout(rest, true);
return rest.length;
}
function spreadBail(...rest) {
resumeHere(rest[0]);
empty(...rest);
assertRecoveredOnBailout(rest, true);
return rest.length;
}
function spreadExtraFormals(i, ...rest) {
empty(...rest);
assertRecoveredOnBailout(rest, true);
return rest.length;
}
function spreadExtraFormalsBail(i, ...rest) {
resumeHere(i);
empty(...rest);
assertRecoveredOnBailout(rest, true);
return rest.length;
}
// Extra args currently not supported.
function spreadExtraArgs(...rest) {
empty(0, ...rest);
assertRecoveredOnBailout(rest, false);
return rest.length;
}
function spreadExtraArgsBail(...rest) {
resumeHere(rest[0]);
empty(0, ...rest);
assertRecoveredOnBailout(rest, false);
return rest.length;
}
// Check rest array with new spread.
function newSpread(...rest) {
new empty(...rest);
assertRecoveredOnBailout(rest, true);
return rest.length;
}
function newSpreadBail(...rest) {
resumeHere(rest[0]);
new empty(...rest);
assertRecoveredOnBailout(rest, true);
return rest.length;
}
function newSpreadExtraFormals(i, ...rest) {
new empty(...rest);
assertRecoveredOnBailout(rest, true);
return rest.length;
}
function newSpreadExtraFormalsBail(i, ...rest) {
resumeHere(i);
new empty(...rest);
assertRecoveredOnBailout(rest, true);
return rest.length;
}
// Extra args currently not supported.
function newSpreadExtraArgs(...rest) {
new empty(0, ...rest);
assertRecoveredOnBailout(rest, false);
return rest.length;
}
function newSpreadExtraArgsBail(...rest) {
resumeHere(rest[0]);
new empty(0, ...rest);
assertRecoveredOnBailout(rest, false);
return rest.length;
}
// The arguments object isn't mapped.
function setArgs(i, ...rest) {
arguments[1] = "fail";
assertEq(rest[0], i);
assertRecoveredOnBailout(rest, true);
return rest.length;
}
function setArgsBail(i, ...rest) {
resumeHere(i);
arguments[1] = "fail";
assertEq(rest[0], i);
assertRecoveredOnBailout(rest, true);
return rest.length;
}
// Check that we correctly allocate the array after taking the recover path.
var uceFault_recoverLength = eval(`(${uceFault})`.replace('uceFault', 'uceFault_recoverLength'));
function recoverLength(i, ...rest) {
if (uceFault_recoverLength(i) || uceFault_recoverLength(i)) {
return rest.length;
}
assertRecoveredOnBailout(rest, true);
return 0;
}
var uceFault_recoverContent = eval(`(${uceFault})`.replace('uceFault', 'uceFault_recoverContent'));
function recoverContent(i, ...rest) {
if (uceFault_recoverContent(i) || uceFault_recoverContent(i)) {
return rest[0];
}
assertRecoveredOnBailout(rest, true);
return 0;
}
var uceFault_recoverApply = eval(`(${uceFault})`.replace('uceFault', 'uceFault_recoverApply'));
function recoverApply(i, ...rest) {
if (uceFault_recoverApply(i) || uceFault_recoverApply(i)) {
return empty.apply(null, rest);
}
assertRecoveredOnBailout(rest, true);
return 0;
}
var uceFault_recoverSpread = eval(`(${uceFault})`.replace('uceFault', 'uceFault_recoverSpread'));
function recoverSpread(i, ...rest) {
if (uceFault_recoverSpread(i) || uceFault_recoverSpread(i)) {
return empty(...rest);
}
assertRecoveredOnBailout(rest, true);
return 0;
}
var uceFault_recoverNewSpread = eval(`(${uceFault})`.replace('uceFault', 'uceFault_recoverNewSpread'));
function recoverNewSpread(i, ...rest) {
if (uceFault_recoverNewSpread(i) || uceFault_recoverNewSpread(i)) {
return new empty(...rest);
}
assertRecoveredOnBailout(rest, true);
return 0;
}
var uceFault_recoverSetArgs = eval(`(${uceFault})`.replace('uceFault', 'uceFault_recoverSetArgs'));
function recoverSetArgs(i, ...rest) {
arguments[1] = "fail";
if (uceFault_recoverSetArgs(i) || uceFault_recoverSetArgs(i)) {
// Ensure arguments[1] isn't mapped to rest[0].
assertEq(rest[0], "ok");
return 0;
}
assertRecoveredOnBailout(rest, true);
return 0;
}
// Prevent compilation of the top-level
eval(`(${resumeHere})`);
for (let i = 0; i < 100; i++) {
length(i);
lengthBail(i);
content(i, i);
contentBail(i, i);
contentExtraFormals(i, i);
contentExtraFormalsBail(i, i);
setLength(i);
setLengthBail(i);
setContent(i, i);
setContentBail(i, i);
deleteContent(i, i);
deleteContentBail(i, i);
escapes(i);
escapesBail(i);
apply(i);
applyBail(i);
applyExtraFormals(i);
applyExtraFormalsBail(i);
spread(i);
spreadBail(i);
spreadExtraFormals(i);
spreadExtraFormalsBail(i);
spreadExtraArgs(i);
spreadExtraArgsBail(i);
newSpread(i);
newSpreadBail(i);
newSpreadExtraFormals(i);
newSpreadExtraFormalsBail(i);
newSpreadExtraArgs(i);
newSpreadExtraArgsBail(i);
setArgs(i, i);
setArgsBail(i, i);
recoverLength(i);
recoverContent(i);
recoverApply(i);
recoverSpread(i);
recoverNewSpread(i);
recoverSetArgs(i, "ok");
}