| // Copyright 2012 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 | 
 | // Flags: --nostress-opt --opt | 
 |  | 
 | // Ensure that ElementsKind transitions in various situations are hoisted (or | 
 | // not hoisted) correctly, don't change the semantics programs and don't trigger | 
 | // deopt through hoisting in important situations. | 
 |  | 
 | function test_wrapper() { | 
 |   // Make sure that a simple elements array transitions inside a loop before | 
 |   // stores to an array gets hoisted in a way that doesn't generate a deopt in | 
 |   // simple cases.} | 
 |   function testDoubleConversion4(a) { | 
 |     var object = new Object(); | 
 |     a[0] = 0; | 
 |     var count = 3; | 
 |     do { | 
 |       a[0] = object; | 
 |     } while (--count > 0); | 
 |   } | 
 |  | 
 |   testDoubleConversion4(new Array(5)); | 
 |   testDoubleConversion4(new Array(5));  // Call twice to make sure that second | 
 |                                         // store is a transition and not | 
 |                                         // optimistically MONOMORPHIC | 
 |   %OptimizeFunctionOnNextCall(testDoubleConversion4); | 
 |   testDoubleConversion4(new Array(5)); | 
 |   testDoubleConversion4(new Array(5)); | 
 |   assertOptimized(testDoubleConversion4); | 
 |   %ClearFunctionFeedback(testDoubleConversion4); | 
 |  | 
 |   // Make sure that non-element related map checks that are not preceded by | 
 |   // transitions in a loop still get hoisted in a way that doesn't generate a | 
 |   // deopt in simple cases. | 
 |   function testExactMapHoisting(a) { | 
 |     var object = new Object(); | 
 |     a.foo = {}; | 
 |     a[0] = 0; | 
 |     a[1] = 1; | 
 |     var count = 3; | 
 |     do { | 
 |       a.foo = object;  // This map check should be hoistable | 
 |       a[1] = object; | 
 |       result = a.foo == object && a[1] == object; | 
 |     } while (--count > 0); | 
 |   } | 
 |  | 
 |   testExactMapHoisting(new Array(5)); | 
 |   testExactMapHoisting(new Array(5));  // Call twice to make sure that second | 
 |                                        // store is a transition and not | 
 |                                        // optimistically MONOMORPHIC | 
 |   %OptimizeFunctionOnNextCall(testExactMapHoisting); | 
 |   testExactMapHoisting(new Array(5)); | 
 |   testExactMapHoisting(new Array(5)); | 
 |   assertOptimized(testExactMapHoisting); | 
 |   %ClearFunctionFeedback(testExactMapHoisting); | 
 |  | 
 |   // Make sure that non-element related map checks do NOT get hoisted if they | 
 |   // depend on an elements transition before them and it's not possible to hoist | 
 |   // that transition. | 
 |   function testExactMapHoisting2(a) { | 
 |     var object = new Object(); | 
 |     a.foo = 0; | 
 |     a[0] = 0; | 
 |     a[1] = 1; | 
 |     var count = 3; | 
 |     do { | 
 |       if (a.bar === undefined) { | 
 |         a[1] = 2.5; | 
 |       } | 
 |       a.foo = object;  // This map check should NOT be hoistable because it | 
 |                        // includes a check for the PACKED_ELEMENTS map as well as | 
 |                        // the PACKED_DOUBLE_ELEMENTS map, which depends on the | 
 |                        // double transition above in the if, which cannot be | 
 |                        // hoisted. | 
 |     } while (--count > 0); | 
 |   } | 
 |  | 
 |   testExactMapHoisting2(new Array(5)); | 
 |   testExactMapHoisting2(new Array(5));  // Call twice to make sure that second | 
 |                                         // store is a transition and not | 
 |                                         // optimistically MONOMORPHIC | 
 |   %OptimizeFunctionOnNextCall(testExactMapHoisting2); | 
 |   testExactMapHoisting2(new Array(5)); | 
 |   testExactMapHoisting2(new Array(5)); | 
 |   // Temporarily disabled - see bug 2176. | 
 |   // assertOptimized(testExactMapHoisting2); | 
 |   %ClearFunctionFeedback(testExactMapHoisting2); | 
 |  | 
 |   // Make sure that non-element related map checks do get hoisted if they use | 
 |   // the transitioned map for the check and all transitions that they depend | 
 |   // upon can hoisted, too. | 
 |   function testExactMapHoisting3(a) { | 
 |     var object = new Object(); | 
 |     a.foo = null; | 
 |     a[0] = 0; | 
 |     a[1] = 1; | 
 |     var count = 3; | 
 |     do { | 
 |       a[1] = 2.5; | 
 |       a.foo = object;  // This map check should be hoistable because all elements | 
 |                        // transitions in the loop can also be hoisted. | 
 |     } while (--count > 0); | 
 |   } | 
 |  | 
 |   var add_transition = new Array(5); | 
 |   add_transition.foo = 0; | 
 |   add_transition[0] = new Object();  // For FAST_ELEMENT transition to be created | 
 |   testExactMapHoisting3(new Array(5)); | 
 |   testExactMapHoisting3(new Array(5));  // Call twice to make sure that second | 
 |                                         // store is a transition and not | 
 |                                         // optimistically MONOMORPHIC | 
 |   %OptimizeFunctionOnNextCall(testExactMapHoisting3); | 
 |   testExactMapHoisting3(new Array(5)); | 
 |   testExactMapHoisting3(new Array(5)); | 
 |   assertOptimized(testExactMapHoisting3); | 
 |   %ClearFunctionFeedback(testExactMapHoisting3); | 
 |  | 
 |   function testDominatingTransitionHoisting1(a) { | 
 |     var object = new Object(); | 
 |     a[0] = 0; | 
 |     var count = 3; | 
 |     do { | 
 |       if (a.baz != true) { | 
 |         a[1] = 2.5; | 
 |       } | 
 |       a[0] = object; | 
 |     } while (--count > 3); | 
 |   } | 
 |  | 
 |   /* | 
 |   testDominatingTransitionHoisting1(new Array(5)); | 
 |   testDominatingTransitionHoisting1(new Array(5));  // Call twice to make sure | 
 |                                                     // that second store is a | 
 |                                                     // transition and not | 
 |                                                     // optimistically MONOMORPHIC | 
 |   %OptimizeFunctionOnNextCall(testDominatingTransitionHoisting1); | 
 |   testDominatingTransitionHoisting1(new Array(5)); | 
 |   testDominatingTransitionHoisting1(new Array(5)); | 
 |   // TODO(verwaest) With current changes the elements transition gets hoisted | 
 |   // above the access, causing a deopt. We should update the type of access | 
 |   // rather than forbid hoisting the transition. | 
 |   assertOptimized(testDominatingTransitionHoisting1); | 
 |   %ClearFunctionFeedback(testDominatingTransitionHoisting1); | 
 |   */ | 
 |  | 
 |   function testHoistingWithSideEffect(a) { | 
 |     var object = new Object(); | 
 |     a[0] = 0; | 
 |     var count = 3; | 
 |     do { | 
 |       assertTrue(true); | 
 |       a[0] = object; | 
 |     } while (--count > 3); | 
 |   } | 
 |  | 
 |   testHoistingWithSideEffect(new Array(5)); | 
 |   testHoistingWithSideEffect(new Array(5));  // Call twice to make sure that | 
 |                                              // second store is a transition and | 
 |                                              // not optimistically MONOMORPHIC | 
 |   %OptimizeFunctionOnNextCall(testHoistingWithSideEffect); | 
 |   testHoistingWithSideEffect(new Array(5)); | 
 |   testHoistingWithSideEffect(new Array(5)); | 
 |   assertOptimized(testHoistingWithSideEffect); | 
 |   %ClearFunctionFeedback(testHoistingWithSideEffect); | 
 |  | 
 |   function testStraightLineDupeElinination(a,b,c,d,e,f) { | 
 |     var count = 3; | 
 |     do { | 
 |       assertTrue(true); | 
 |       a[0] = b; | 
 |       a[1] = c; | 
 |       a[2] = d; | 
 |       assertTrue(true); | 
 |       a[3] = e;  // TransitionElementsKind should be eliminated despite call. | 
 |       a[4] = f; | 
 |     } while (--count > 3); | 
 |   } | 
 |  | 
 |   testStraightLineDupeElinination(new Array(0, 0, 0, 0, 0),0,0,0,0,.5); | 
 |   testStraightLineDupeElinination(new Array(0, 0, 0, 0, 0),0,0,0,.5,0); | 
 |   testStraightLineDupeElinination(new Array(0, 0, 0, 0, 0),0,0,.5,0,0); | 
 |   testStraightLineDupeElinination(new Array(0, 0, 0, 0, 0),0,.5,0,0,0); | 
 |   testStraightLineDupeElinination(new Array(0, 0, 0, 0, 0),.5,0,0,0,0); | 
 |   testStraightLineDupeElinination(new Array(.1,.1,.1,.1,.1),0,0,0,0,.5); | 
 |   testStraightLineDupeElinination(new Array(.1,.1,.1,.1,.1),0,0,0,.5,0); | 
 |   testStraightLineDupeElinination(new Array(.1,.1,.1,.1,.1),0,0,.5,0,0); | 
 |   testStraightLineDupeElinination(new Array(.1,.1,.1,.1,.1),0,.5,0,0,0); | 
 |   testStraightLineDupeElinination(new Array(.1,.1,.1,.1,.1),.5,0,0,0,0); | 
 |   testStraightLineDupeElinination(new Array(5),.5,0,0,0,0); | 
 |   testStraightLineDupeElinination(new Array(5),0,.5,0,0,0); | 
 |   testStraightLineDupeElinination(new Array(5),0,0,.5,0,0); | 
 |   testStraightLineDupeElinination(new Array(5),0,0,0,.5,0); | 
 |   testStraightLineDupeElinination(new Array(5),0,0,0,0,.5); | 
 |   testStraightLineDupeElinination(new Array(5),.5,0,0,0,0); | 
 |   testStraightLineDupeElinination(new Array(5),0,.5,0,0,0); | 
 |   testStraightLineDupeElinination(new Array(5),0,0,.5,0,0); | 
 |   testStraightLineDupeElinination(new Array(5),0,0,0,.5,0); | 
 |   testStraightLineDupeElinination(new Array(5),0,0,0,0,.5); | 
 |   %OptimizeFunctionOnNextCall(testStraightLineDupeElinination); | 
 |   testStraightLineDupeElinination(new Array(5),0,0,0,0,0); | 
 |   testStraightLineDupeElinination(new Array(5),0,0,0,0,0); | 
 |   assertOptimized(testStraightLineDupeElinination); | 
 |   %ClearFunctionFeedback(testStraightLineDupeElinination); | 
 | } | 
 |  | 
 | // The test is called in a test wrapper that has type feedback cleared to | 
 | // prevent the influence of allocation-sites, which learn from transitions. | 
 | test_wrapper(); | 
 | %ClearFunctionFeedback(test_wrapper); |