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 --smi-only-arrays --notrack-allocation-sites
29
30// No tracking of allocation sites because it interfers with the semantics
31// the test is trying to ensure.
32
33// Ensure that ElementsKind transitions in various situations are hoisted (or
34// not hoisted) correctly, don't change the semantics programs and don't trigger
35// deopt through hoisting in important situations.
36
37support_smi_only_arrays = %HasFastSmiElements(new Array(1,2,3,4,5,6));
38
39if (support_smi_only_arrays) {
40  print("Tests include smi-only arrays.");
41} else {
42  print("Tests do NOT include smi-only arrays.");
43}
44
45if (support_smi_only_arrays) {
46  // Make sure that a simple elements array transitions inside a loop before
47  // stores to an array gets hoisted in a way that doesn't generate a deopt in
48  // simple cases.}
49  function testDoubleConversion4(a) {
50    var object = new Object();
51    a[0] = 0;
52    var count = 3;
53    do {
54      a[0] = object;
55    } while (--count > 0);
56  }
57
58  testDoubleConversion4(new Array(5));
59  testDoubleConversion4(new Array(5));  // Call twice to make sure that second
60                                        // store is a transition and not
61                                        // optimistically MONOMORPHIC
62  %OptimizeFunctionOnNextCall(testDoubleConversion4);
63  testDoubleConversion4(new Array(5));
64  testDoubleConversion4(new Array(5));
65  assertOptimized(testDoubleConversion4);
66  %ClearFunctionTypeFeedback(testDoubleConversion4);
67
68  // Make sure that non-element related map checks that are not preceded by
69  // transitions in a loop still get hoisted in a way that doesn't generate a
70  // deopt in simple cases.
71  function testExactMapHoisting(a) {
72    var object = new Object();
73    a.foo = {};
74    a[0] = 0;
75    a[1] = 1;
76    var count = 3;
77    do {
78      a.foo = object;  // This map check should be hoistable
79      a[1] = object;
80      result = a.foo == object && a[1] == object;
81    } while (--count > 0);
82  }
83
84  testExactMapHoisting(new Array(5));
85  testExactMapHoisting(new Array(5));  // Call twice to make sure that second
86                                       // store is a transition and not
87                                       // optimistically MONOMORPHIC
88  %OptimizeFunctionOnNextCall(testExactMapHoisting);
89  testExactMapHoisting(new Array(5));
90  testExactMapHoisting(new Array(5));
91  assertOptimized(testExactMapHoisting);
92  %ClearFunctionTypeFeedback(testExactMapHoisting);
93
94  // Make sure that non-element related map checks do NOT get hoisted if they
95  // depend on an elements transition before them and it's not possible to hoist
96  // that transition.
97  function testExactMapHoisting2(a) {
98    var object = new Object();
99    a.foo = 0;
100    a[0] = 0;
101    a[1] = 1;
102    var count = 3;
103    do {
104      if (a.bar === undefined) {
105        a[1] = 2.5;
106      }
107      a.foo = object;  // This map check should NOT be hoistable because it
108                       // includes a check for the FAST_ELEMENTS map as well as
109                       // the FAST_DOUBLE_ELEMENTS map, which depends on the
110                       // double transition above in the if, which cannot be
111                       // hoisted.
112    } while (--count > 0);
113  }
114
115  testExactMapHoisting2(new Array(5));
116  testExactMapHoisting2(new Array(5));  // Call twice to make sure that second
117                                        // store is a transition and not
118                                        // optimistically MONOMORPHIC
119  %OptimizeFunctionOnNextCall(testExactMapHoisting2);
120  testExactMapHoisting2(new Array(5));
121  testExactMapHoisting2(new Array(5));
122  // Temporarily disabled - see bug 2176.
123  // assertOptimized(testExactMapHoisting2);
124  %ClearFunctionTypeFeedback(testExactMapHoisting2);
125
126  // Make sure that non-element related map checks do get hoisted if they use
127  // the transitioned map for the check and all transitions that they depend
128  // upon can hoisted, too.
129  function testExactMapHoisting3(a) {
130    var object = new Object();
131    a.foo = null;
132    a[0] = 0;
133    a[1] = 1;
134    var count = 3;
135    do {
136      a[1] = 2.5;
137      a.foo = object;  // This map check should be hoistable because all elements
138                       // transitions in the loop can also be hoisted.
139    } while (--count > 0);
140  }
141
142  var add_transition = new Array(5);
143  add_transition.foo = 0;
144  add_transition[0] = new Object();  // For FAST_ELEMENT transition to be created
145  testExactMapHoisting3(new Array(5));
146  testExactMapHoisting3(new Array(5));  // Call twice to make sure that second
147                                        // store is a transition and not
148                                        // optimistically MONOMORPHIC
149  %OptimizeFunctionOnNextCall(testExactMapHoisting3);
150  testExactMapHoisting3(new Array(5));
151  testExactMapHoisting3(new Array(5));
152  assertOptimized(testExactMapHoisting3);
153  %ClearFunctionTypeFeedback(testExactMapHoisting3);
154
155  function testDominatingTransitionHoisting1(a) {
156    var object = new Object();
157    a[0] = 0;
158    var count = 3;
159    do {
160      if (a.baz != true) {
161        a[1] = 2.5;
162      }
163      a[0] = object;
164    } while (--count > 3);
165  }
166
167  /*
168  testDominatingTransitionHoisting1(new Array(5));
169  testDominatingTransitionHoisting1(new Array(5));  // Call twice to make sure
170                                                    // that second store is a
171                                                    // transition and not
172                                                    // optimistically MONOMORPHIC
173  %OptimizeFunctionOnNextCall(testDominatingTransitionHoisting1);
174  testDominatingTransitionHoisting1(new Array(5));
175  testDominatingTransitionHoisting1(new Array(5));
176  // TODO(verwaest) With current changes the elements transition gets hoisted
177  // above the access, causing a deopt. We should update the type of access
178  // rather than forbid hoisting the transition.
179  assertOptimized(testDominatingTransitionHoisting1);
180  %ClearFunctionTypeFeedback(testDominatingTransitionHoisting1);
181  */
182
183  function testHoistingWithSideEffect(a) {
184    var object = new Object();
185    a[0] = 0;
186    var count = 3;
187    do {
188      assertTrue(true);
189      a[0] = object;
190    } while (--count > 3);
191  }
192
193  testHoistingWithSideEffect(new Array(5));
194  testHoistingWithSideEffect(new Array(5));  // Call twice to make sure that
195                                             // second store is a transition and
196                                             // not optimistically MONOMORPHIC
197  %OptimizeFunctionOnNextCall(testHoistingWithSideEffect);
198  testHoistingWithSideEffect(new Array(5));
199  testHoistingWithSideEffect(new Array(5));
200  assertOptimized(testHoistingWithSideEffect);
201  %ClearFunctionTypeFeedback(testHoistingWithSideEffect);
202
203  function testStraightLineDupeElinination(a,b,c,d,e,f) {
204    var count = 3;
205    do {
206      assertTrue(true);
207      a[0] = b;
208      a[1] = c;
209      a[2] = d;
210      assertTrue(true);
211      a[3] = e;  // TransitionElementsKind should be eliminated despite call.
212      a[4] = f;
213    } while (--count > 3);
214  }
215
216  testStraightLineDupeElinination(new Array(0, 0, 0, 0, 0),0,0,0,0,.5);
217  testStraightLineDupeElinination(new Array(0, 0, 0, 0, 0),0,0,0,.5,0);
218  testStraightLineDupeElinination(new Array(0, 0, 0, 0, 0),0,0,.5,0,0);
219  testStraightLineDupeElinination(new Array(0, 0, 0, 0, 0),0,.5,0,0,0);
220  testStraightLineDupeElinination(new Array(0, 0, 0, 0, 0),.5,0,0,0,0);
221  testStraightLineDupeElinination(new Array(.1,.1,.1,.1,.1),0,0,0,0,.5);
222  testStraightLineDupeElinination(new Array(.1,.1,.1,.1,.1),0,0,0,.5,0);
223  testStraightLineDupeElinination(new Array(.1,.1,.1,.1,.1),0,0,.5,0,0);
224  testStraightLineDupeElinination(new Array(.1,.1,.1,.1,.1),0,.5,0,0,0);
225  testStraightLineDupeElinination(new Array(.1,.1,.1,.1,.1),.5,0,0,0,0);
226  testStraightLineDupeElinination(new Array(5),.5,0,0,0,0);
227  testStraightLineDupeElinination(new Array(5),0,.5,0,0,0);
228  testStraightLineDupeElinination(new Array(5),0,0,.5,0,0);
229  testStraightLineDupeElinination(new Array(5),0,0,0,.5,0);
230  testStraightLineDupeElinination(new Array(5),0,0,0,0,.5);
231  testStraightLineDupeElinination(new Array(5),.5,0,0,0,0);
232  testStraightLineDupeElinination(new Array(5),0,.5,0,0,0);
233  testStraightLineDupeElinination(new Array(5),0,0,.5,0,0);
234  testStraightLineDupeElinination(new Array(5),0,0,0,.5,0);
235  testStraightLineDupeElinination(new Array(5),0,0,0,0,.5);
236  %OptimizeFunctionOnNextCall(testStraightLineDupeElinination);
237  testStraightLineDupeElinination(new Array(5),0,0,0,0,0);
238  testStraightLineDupeElinination(new Array(5),0,0,0,0,0);
239  assertOptimized(testStraightLineDupeElinination);
240  %ClearFunctionTypeFeedback(testStraightLineDupeElinination);
241}
242