| // Copyright 2011 the V8 project authors. All rights reserved. | 
 | // Redistribution and use in source and binary forms, with or without | 
 | // modification, are permitted provided that the following conditions are | 
 | // met: | 
 | // | 
 | //     * Redistributions of source code must retain the above copyright | 
 | //       notice, this list of conditions and the following disclaimer. | 
 | //     * Redistributions in binary form must reproduce the above | 
 | //       copyright notice, this list of conditions and the following | 
 | //       disclaimer in the documentation and/or other materials provided | 
 | //       with the distribution. | 
 | //     * Neither the name of Google Inc. nor the names of its | 
 | //       contributors may be used to endorse or promote products derived | 
 | //       from this software without specific prior written permission. | 
 | // | 
 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
 |  | 
 | // Flags: --allow-natives-syntax | 
 |  | 
 | function A() { | 
 | } | 
 |  | 
 | A.prototype.X = function (a, b, c) { | 
 |   assertTrue(this instanceof A); | 
 |   assertEquals(1, a); | 
 |   assertEquals(2, b); | 
 |   assertEquals(3, c); | 
 | }; | 
 |  | 
 | A.prototype.Y = function () { | 
 |   this.X.apply(this, arguments); | 
 | }; | 
 |  | 
 | A.prototype.Z = function () { | 
 |   this.Y(1,2,3); | 
 | }; | 
 |  | 
 | var a = new A(); | 
 | a.Z(4,5,6); | 
 | a.Z(4,5,6); | 
 | %OptimizeFunctionOnNextCall(a.Z); | 
 | a.Z(4,5,6); | 
 | A.prototype.X.apply = function (receiver, args) { | 
 |   return Function.prototype.apply.call(this, receiver, args); | 
 | }; | 
 | a.Z(4,5,6); | 
 |  | 
 |  | 
 | // Ensure that HArgumentsObject is inserted in a correct place | 
 | // and dominates all uses. | 
 | function F1() { } | 
 | function F2() { F1.apply(this, arguments); } | 
 | function F3(x, y) { | 
 |   if (x) { | 
 |     F2(y); | 
 |   } | 
 | } | 
 |  | 
 | function F31() { | 
 |   return F1.apply(this, arguments); | 
 | } | 
 |  | 
 | function F4() { | 
 |   F3(true, false); | 
 |   return F31(1); | 
 | } | 
 |  | 
 | F4(1); | 
 | F4(1); | 
 | F4(1); | 
 | %OptimizeFunctionOnNextCall(F4); | 
 | F4(1); | 
 |  | 
 |  | 
 | // Test correct adapation of arguments. | 
 | // Strict mode prevents arguments object from shadowing parameters. | 
 | (function () { | 
 |   "use strict"; | 
 |  | 
 |   function G2() { | 
 |     assertArrayEquals([1,2], arguments); | 
 |   } | 
 |  | 
 |   function G4() { | 
 |     assertArrayEquals([1,2,3,4], arguments); | 
 |   } | 
 |  | 
 |   function adapt2to4(a, b, c, d) { | 
 |     G2.apply(this, arguments); | 
 |   } | 
 |  | 
 |   function adapt4to2(a, b) { | 
 |     G4.apply(this, arguments); | 
 |   } | 
 |  | 
 |   function test_adaptation() { | 
 |     adapt2to4(1, 2); | 
 |     adapt4to2(1, 2, 3, 4); | 
 |   } | 
 |  | 
 |   test_adaptation(); | 
 |   test_adaptation(); | 
 |   %OptimizeFunctionOnNextCall(test_adaptation); | 
 |   test_adaptation(); | 
 | })(); | 
 |  | 
 | // Test arguments access from the inlined function. | 
 | %NeverOptimizeFunction(uninlinable); | 
 | function uninlinable(v) { | 
 |   assertEquals(0, v); | 
 |   return 0; | 
 | } | 
 |  | 
 | function toarr_inner() { | 
 |   var a = arguments; | 
 |   var marker = a[0]; | 
 |   uninlinable(uninlinable(0, 0), marker.x); | 
 |  | 
 |   var r = new Array(); | 
 |   for (var i = a.length - 1; i >= 1; i--) { | 
 |     r.push(a[i]); | 
 |   } | 
 |  | 
 |   return r; | 
 | } | 
 |  | 
 | function toarr1(marker, a, b, c) { | 
 |   return toarr_inner(marker, a / 2, b / 2, c / 2); | 
 | } | 
 |  | 
 | function toarr2(marker, a, b, c) { | 
 |   var x = 0; | 
 |   return uninlinable(uninlinable(0, 0), | 
 |                      x = toarr_inner(marker, a / 2, b / 2, c / 2)), x; | 
 | } | 
 |  | 
 | function test_toarr(toarr) { | 
 |   var marker = { x: 0 }; | 
 |   assertArrayEquals([3, 2, 1], toarr(marker, 2, 4, 6)); | 
 |   assertArrayEquals([3, 2, 1], toarr(marker, 2, 4, 6)); | 
 |   %OptimizeFunctionOnNextCall(toarr); | 
 |   assertArrayEquals([3, 2, 1], toarr(marker, 2, 4, 6)); | 
 |   delete marker.x; | 
 |   assertArrayEquals([3, 2, 1], toarr(marker, 2, 4, 6)); | 
 | } | 
 |  | 
 | test_toarr(toarr1); | 
 | test_toarr(toarr2); | 
 |  | 
 |  | 
 | // Test that arguments access from inlined function uses correct values. | 
 | (function () { | 
 |   function inner(x, y) { | 
 |     "use strict"; | 
 |     x = 10; | 
 |     y = 20; | 
 |     for (var i = 0; i < 1; i++) { | 
 |       for (var j = 1; j <= arguments.length; j++) { | 
 |         return arguments[arguments.length - j]; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   function outer(x, y) { | 
 |     return inner(x, y); | 
 |   } | 
 |  | 
 |   %OptimizeFunctionOnNextCall(outer); | 
 |   %OptimizeFunctionOnNextCall(inner); | 
 |   assertEquals(2, outer(1, 2)); | 
 | })(); | 
 |  | 
 |  | 
 | (function () { | 
 |   function inner(x, y) { | 
 |     "use strict"; | 
 |     x = 10; | 
 |     y = 20; | 
 |     for (var i = 0; i < 1; i++) { | 
 |       for (var j = 1; j <= arguments.length; j++) { | 
 |         return arguments[arguments.length - j]; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   function outer(x, y) { | 
 |     return inner(x, y); | 
 |   } | 
 |  | 
 |   assertEquals(2, outer(1, 2)); | 
 |   assertEquals(2, outer(1, 2)); | 
 |   assertEquals(2, outer(1, 2)); | 
 |   %OptimizeFunctionOnNextCall(outer); | 
 |   assertEquals(2, outer(1, 2)); | 
 | })(); | 
 |  | 
 |  | 
 | // Test inlining and deoptimization of functions accessing and modifying | 
 | // the arguments object in strict mode with mismatched arguments count. | 
 | (function () { | 
 |   "use strict"; | 
 |   function test(outerCount, middleCount, innerCount) { | 
 |     var forceDeopt = { deopt:false }; | 
 |     function inner(x,y) { | 
 |       x = 0; y = 0; | 
 |       forceDeopt.deopt; | 
 |       assertSame(innerCount, arguments.length); | 
 |       for (var i = 0; i < arguments.length; i++) { | 
 |         assertSame(30 + i, arguments[i]); | 
 |       } | 
 |     } | 
 |  | 
 |     function middle(x,y) { | 
 |       x = 0; y = 0; | 
 |       if (innerCount == 1) inner(30); | 
 |       if (innerCount == 2) inner(30, 31); | 
 |       if (innerCount == 3) inner(30, 31, 32); | 
 |       assertSame(middleCount, arguments.length); | 
 |       for (var i = 0; i < arguments.length; i++) { | 
 |         assertSame(20 + i, arguments[i]); | 
 |       } | 
 |     } | 
 |  | 
 |     function outer(x,y) { | 
 |       x = 0; y = 0; | 
 |       if (middleCount == 1) middle(20); | 
 |       if (middleCount == 2) middle(20, 21); | 
 |       if (middleCount == 3) middle(20, 21, 22); | 
 |       assertSame(outerCount, arguments.length); | 
 |       for (var i = 0; i < arguments.length; i++) { | 
 |         assertSame(10 + i, arguments[i]); | 
 |       } | 
 |     } | 
 |  | 
 |     for (var step = 0; step < 4; step++) { | 
 |       if (outerCount == 1) outer(10); | 
 |       if (outerCount == 2) outer(10, 11); | 
 |       if (outerCount == 3) outer(10, 11, 12); | 
 |       if (step == 1) %OptimizeFunctionOnNextCall(outer); | 
 |       if (step == 2) delete forceDeopt.deopt; | 
 |     } | 
 |  | 
 |     %DeoptimizeFunction(outer); | 
 |     %DeoptimizeFunction(middle); | 
 |     %DeoptimizeFunction(inner); | 
 |     %ClearFunctionFeedback(outer); | 
 |     %ClearFunctionFeedback(middle); | 
 |     %ClearFunctionFeedback(inner); | 
 |   } | 
 |  | 
 |   for (var a = 1; a <= 3; a++) { | 
 |     for (var b = 1; b <= 3; b++) { | 
 |       for (var c = 1; c <= 3; c++) { | 
 |         test(a,b,c); | 
 |       } | 
 |     } | 
 |   } | 
 | })(); | 
 |  | 
 |  | 
 | // Test materialization of arguments object with values in registers. | 
 | (function () { | 
 |   "use strict"; | 
 |   var forceDeopt = { deopt:false }; | 
 |   function inner(a,b,c,d,e,f,g,h,i,j) { | 
 |     var args = arguments; | 
 |     forceDeopt.deopt; | 
 |     assertSame(10, args.length); | 
 |     assertSame(a, args[0]); | 
 |     assertSame(b, args[1]); | 
 |     assertSame(c, args[2]); | 
 |     assertSame(d, args[3]); | 
 |     assertSame(e, args[4]); | 
 |     assertSame(f, args[5]); | 
 |     assertSame(g, args[6]); | 
 |     assertSame(h, args[7]); | 
 |     assertSame(i, args[8]); | 
 |     assertSame(j, args[9]); | 
 |   } | 
 |  | 
 |   var a = 0.5; | 
 |   var b = 1.7; | 
 |   var c = 123; | 
 |   function outer() { | 
 |     inner( | 
 |       a - 0.3,  // double in double register | 
 |       b + 2.3,  // integer in double register | 
 |       c + 321,  // integer in general register | 
 |       c - 456,  // integer in stack slot | 
 |       a + 0.1, a + 0.2, a + 0.3, a + 0.4, a + 0.5, | 
 |       a + 0.6   // double in stack slot | 
 |     ); | 
 |   } | 
 |  | 
 |   outer(); | 
 |   outer(); | 
 |   %OptimizeFunctionOnNextCall(outer); | 
 |   outer(); | 
 |   delete forceDeopt.deopt; | 
 |   outer(); | 
 | })(); |