1// Copyright 2012 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28// Flags: --allow-natives-syntax
29// Flags: --nostress-opt
30
31// Ensure that ElementsKind transitions in various situations are hoisted (or
32// not hoisted) correctly, don't change the semantics programs and don't trigger
33// deopt through hoisting in important situations.
34
35function test_wrapper() {
36  // Make sure that a simple elements array transitions inside a loop before
37  // stores to an array gets hoisted in a way that doesn't generate a deopt in
38  // simple cases.}
39  function testDoubleConversion4(a) {
40    var object = new Object();
41    a[0] = 0;
42    var count = 3;
43    do {
44      a[0] = object;
45    } while (--count > 0);
46  }
47
48  testDoubleConversion4(new Array(5));
49  testDoubleConversion4(new Array(5));  // Call twice to make sure that second
50                                        // store is a transition and not
51                                        // optimistically MONOMORPHIC
52  %OptimizeFunctionOnNextCall(testDoubleConversion4);
53  testDoubleConversion4(new Array(5));
54  testDoubleConversion4(new Array(5));
55  assertOptimized(testDoubleConversion4);
56  %ClearFunctionTypeFeedback(testDoubleConversion4);
57
58  // Make sure that non-element related map checks that are not preceded by
59  // transitions in a loop still get hoisted in a way that doesn't generate a
60  // deopt in simple cases.
61  function testExactMapHoisting(a) {
62    var object = new Object();
63    a.foo = {};
64    a[0] = 0;
65    a[1] = 1;
66    var count = 3;
67    do {
68      a.foo = object;  // This map check should be hoistable
69      a[1] = object;
70      result = a.foo == object && a[1] == object;
71    } while (--count > 0);
72  }
73
74  testExactMapHoisting(new Array(5));
75  testExactMapHoisting(new Array(5));  // Call twice to make sure that second
76                                       // store is a transition and not
77                                       // optimistically MONOMORPHIC
78  %OptimizeFunctionOnNextCall(testExactMapHoisting);
79  testExactMapHoisting(new Array(5));
80  testExactMapHoisting(new Array(5));
81  assertOptimized(testExactMapHoisting);
82  %ClearFunctionTypeFeedback(testExactMapHoisting);
83
84  // Make sure that non-element related map checks do NOT get hoisted if they
85  // depend on an elements transition before them and it's not possible to hoist
86  // that transition.
87  function testExactMapHoisting2(a) {
88    var object = new Object();
89    a.foo = 0;
90    a[0] = 0;
91    a[1] = 1;
92    var count = 3;
93    do {
94      if (a.bar === undefined) {
95        a[1] = 2.5;
96      }
97      a.foo = object;  // This map check should NOT be hoistable because it
98                       // includes a check for the FAST_ELEMENTS map as well as
99                       // the FAST_DOUBLE_ELEMENTS map, which depends on the
100                       // double transition above in the if, which cannot be
101                       // hoisted.
102    } while (--count > 0);
103  }
104
105  testExactMapHoisting2(new Array(5));
106  testExactMapHoisting2(new Array(5));  // Call twice to make sure that second
107                                        // store is a transition and not
108                                        // optimistically MONOMORPHIC
109  %OptimizeFunctionOnNextCall(testExactMapHoisting2);
110  testExactMapHoisting2(new Array(5));
111  testExactMapHoisting2(new Array(5));
112  // Temporarily disabled - see bug 2176.
113  // assertOptimized(testExactMapHoisting2);
114  %ClearFunctionTypeFeedback(testExactMapHoisting2);
115
116  // Make sure that non-element related map checks do get hoisted if they use
117  // the transitioned map for the check and all transitions that they depend
118  // upon can hoisted, too.
119  function testExactMapHoisting3(a) {
120    var object = new Object();
121    a.foo = null;
122    a[0] = 0;
123    a[1] = 1;
124    var count = 3;
125    do {
126      a[1] = 2.5;
127      a.foo = object;  // This map check should be hoistable because all elements
128                       // transitions in the loop can also be hoisted.
129    } while (--count > 0);
130  }
131
132  var add_transition = new Array(5);
133  add_transition.foo = 0;
134  add_transition[0] = new Object();  // For FAST_ELEMENT transition to be created
135  testExactMapHoisting3(new Array(5));
136  testExactMapHoisting3(new Array(5));  // Call twice to make sure that second
137                                        // store is a transition and not
138                                        // optimistically MONOMORPHIC
139  %OptimizeFunctionOnNextCall(testExactMapHoisting3);
140  testExactMapHoisting3(new Array(5));
141  testExactMapHoisting3(new Array(5));
142  assertOptimized(testExactMapHoisting3);
143  %ClearFunctionTypeFeedback(testExactMapHoisting3);
144
145  function testDominatingTransitionHoisting1(a) {
146    var object = new Object();
147    a[0] = 0;
148    var count = 3;
149    do {
150      if (a.baz != true) {
151        a[1] = 2.5;
152      }
153      a[0] = object;
154    } while (--count > 3);
155  }
156
157  /*
158  testDominatingTransitionHoisting1(new Array(5));
159  testDominatingTransitionHoisting1(new Array(5));  // Call twice to make sure
160                                                    // that second store is a
161                                                    // transition and not
162                                                    // optimistically MONOMORPHIC
163  %OptimizeFunctionOnNextCall(testDominatingTransitionHoisting1);
164  testDominatingTransitionHoisting1(new Array(5));
165  testDominatingTransitionHoisting1(new Array(5));
166  // TODO(verwaest) With current changes the elements transition gets hoisted
167  // above the access, causing a deopt. We should update the type of access
168  // rather than forbid hoisting the transition.
169  assertOptimized(testDominatingTransitionHoisting1);
170  %ClearFunctionTypeFeedback(testDominatingTransitionHoisting1);
171  */
172
173  function testHoistingWithSideEffect(a) {
174    var object = new Object();
175    a[0] = 0;
176    var count = 3;
177    do {
178      assertTrue(true);
179      a[0] = object;
180    } while (--count > 3);
181  }
182
183  testHoistingWithSideEffect(new Array(5));
184  testHoistingWithSideEffect(new Array(5));  // Call twice to make sure that
185                                             // second store is a transition and
186                                             // not optimistically MONOMORPHIC
187  %OptimizeFunctionOnNextCall(testHoistingWithSideEffect);
188  testHoistingWithSideEffect(new Array(5));
189  testHoistingWithSideEffect(new Array(5));
190  assertOptimized(testHoistingWithSideEffect);
191  %ClearFunctionTypeFeedback(testHoistingWithSideEffect);
192
193  function testStraightLineDupeElinination(a,b,c,d,e,f) {
194    var count = 3;
195    do {
196      assertTrue(true);
197      a[0] = b;
198      a[1] = c;
199      a[2] = d;
200      assertTrue(true);
201      a[3] = e;  // TransitionElementsKind should be eliminated despite call.
202      a[4] = f;
203    } while (--count > 3);
204  }
205
206  testStraightLineDupeElinination(new Array(0, 0, 0, 0, 0),0,0,0,0,.5);
207  testStraightLineDupeElinination(new Array(0, 0, 0, 0, 0),0,0,0,.5,0);
208  testStraightLineDupeElinination(new Array(0, 0, 0, 0, 0),0,0,.5,0,0);
209  testStraightLineDupeElinination(new Array(0, 0, 0, 0, 0),0,.5,0,0,0);
210  testStraightLineDupeElinination(new Array(0, 0, 0, 0, 0),.5,0,0,0,0);
211  testStraightLineDupeElinination(new Array(.1,.1,.1,.1,.1),0,0,0,0,.5);
212  testStraightLineDupeElinination(new Array(.1,.1,.1,.1,.1),0,0,0,.5,0);
213  testStraightLineDupeElinination(new Array(.1,.1,.1,.1,.1),0,0,.5,0,0);
214  testStraightLineDupeElinination(new Array(.1,.1,.1,.1,.1),0,.5,0,0,0);
215  testStraightLineDupeElinination(new Array(.1,.1,.1,.1,.1),.5,0,0,0,0);
216  testStraightLineDupeElinination(new Array(5),.5,0,0,0,0);
217  testStraightLineDupeElinination(new Array(5),0,.5,0,0,0);
218  testStraightLineDupeElinination(new Array(5),0,0,.5,0,0);
219  testStraightLineDupeElinination(new Array(5),0,0,0,.5,0);
220  testStraightLineDupeElinination(new Array(5),0,0,0,0,.5);
221  testStraightLineDupeElinination(new Array(5),.5,0,0,0,0);
222  testStraightLineDupeElinination(new Array(5),0,.5,0,0,0);
223  testStraightLineDupeElinination(new Array(5),0,0,.5,0,0);
224  testStraightLineDupeElinination(new Array(5),0,0,0,.5,0);
225  testStraightLineDupeElinination(new Array(5),0,0,0,0,.5);
226  %OptimizeFunctionOnNextCall(testStraightLineDupeElinination);
227  testStraightLineDupeElinination(new Array(5),0,0,0,0,0);
228  testStraightLineDupeElinination(new Array(5),0,0,0,0,0);
229  assertOptimized(testStraightLineDupeElinination);
230  %ClearFunctionTypeFeedback(testStraightLineDupeElinination);
231}
232
233// The test is called in a test wrapper that has type feedback cleared to
234// prevent the influence of allocation-sites, which learn from transitions.
235test_wrapper();
236%ClearFunctionTypeFeedback(test_wrapper);
237