| |
| var max = 40; |
| setJitCompilerOption("ion.warmup.trigger", max - 10); |
| |
| // This function is used to escape "g" which is a non-escaped inner function. |
| // As it is not escaped within "f", the lambda for "g" would be computed on the |
| // bailout path. Resolving the first ".caller" implies that we have to recover |
| // the lambda. Resolving the second ".caller" is needed such as we can build the |
| // test case without explicitly escaping "g", which would prevent this |
| // optimization. |
| |
| function return_f(i) { |
| if (i != max - 1) |
| return f; |
| |
| // return_f.caller == g |
| // return_f.caller.caller == f |
| return return_f.caller.caller; |
| } |
| |
| function f(i) { |
| function g() { |
| return return_f(i); |
| } |
| |
| assertRecoveredOnBailout(g, true); |
| return g(); |
| } |
| |
| // This function is used to cause an invalidation after having removed a branch. |
| // These functions are used to check if we correctly recover the lambda |
| // and its environment during a bailout. |
| var uceFault = function (i) { |
| if (i == max - 1) |
| uceFault = function (i) { return true; }; |
| return false; |
| }; |
| |
| var uceFault_lambdaCall = eval(uneval(uceFault).replace('uceFault', 'uceFault_lambdaCall')); |
| function lambdaCall(i) { |
| function g() { |
| return i; |
| } |
| |
| if (uceFault_lambdaCall(i) || uceFault_lambdaCall(i)) |
| assertEq(g(), i); |
| |
| assertRecoveredOnBailout(g, true); |
| }; |
| |
| |
| |
| for (var i = 0; i < max; i++) { |
| assertEq(f(i), f); |
| lambdaCall(i); |
| } |