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: --optimize-for-in --allow-natives-syntax
29
30// Test for-in support in Crankshaft.  For simplicity this tests assumes certain
31// fixed iteration order for properties and will have to be adjusted if V8
32// stops following insertion order.
33
34
35function a(t) {
36  var result = [];
37  for (var i in t) {
38    result.push(i + t[i]);
39  }
40  return result.join('');
41}
42
43// Check that we correctly deoptimize on map check.
44function b(t) {
45  var result = [];
46  for (var i in t) {
47    result.push(i + t[i]);
48    delete t[i];
49  }
50  return result.join('');
51}
52
53// Check that we correctly deoptimize during preparation step.
54function c(t) {
55  var result = [];
56  for (var i in t) {
57    result.push(i + t[i]);
58  }
59  return result.join('');
60}
61
62// Check that we deoptimize to the place after side effect in the right state.
63function d(t) {
64  var result = [];
65  var o;
66  for (var i in (o = t())) {
67    result.push(i + o[i]);
68  }
69  return result.join('');
70}
71
72// Check that we correctly deoptimize on map check inserted for fused load.
73function e(t) {
74  var result = [];
75  for (var i in t) {
76    delete t[i];
77    t[i] = i;
78    result.push(i + t[i]);
79  }
80  return result.join('');
81}
82
83// Nested for-in loops.
84function f(t) {
85  var result = [];
86  for (var i in t) {
87    for (var j in t) {
88      result.push(i + j + t[i] + t[j]);
89    }
90  }
91  return result.join('');
92}
93
94// Deoptimization from the inner for-in loop.
95function g(t) {
96  var result = [];
97  for (var i in t) {
98    for (var j in t) {
99      result.push(i + j + t[i] + t[j]);
100      var v = t[i];
101      delete t[i];
102      t[i] = v;
103    }
104  }
105  return result.join('');
106}
107
108
109// Break from the inner for-in loop.
110function h(t, deopt) {
111  var result = [];
112  for (var i in t) {
113    for (var j in t) {
114      result.push(i + j + t[i] + t[j]);
115      break;
116    }
117  }
118  deopt.deopt;
119  return result.join('');
120}
121
122// Continue in the inner loop.
123function j(t, deopt) {
124  var result = [];
125  for (var i in t) {
126    for (var j in t) {
127      result.push(i + j + t[i] + t[j]);
128      continue;
129    }
130  }
131  deopt.deopt;
132  return result.join('');
133}
134
135// Continue of the outer loop.
136function k(t, deopt) {
137  var result = [];
138  outer: for (var i in t) {
139    for (var j in t) {
140      result.push(i + j + t[i] + t[j]);
141      continue outer;
142    }
143  }
144  deopt.deopt;
145  return result.join('');
146}
147
148// Break of the outer loop.
149function l(t, deopt) {
150  var result = [];
151  outer: for (var i in t) {
152    for (var j in t) {
153      result.push(i + j + t[i] + t[j]);
154      break outer;
155    }
156  }
157  deopt.deopt;
158  return result.join('');
159}
160
161// Test deoptimization from inlined frame (currently it is not inlined).
162function m0(t, deopt) {
163  for (var i in t) {
164    for (var j in t) {
165      deopt.deopt;
166      return i + j + t[i] + t[j];
167    }
168  }
169}
170
171function m(t, deopt) {
172  return m0(t, deopt);
173}
174
175
176function tryFunction(s, mkT, f) {
177  var d = {deopt: false};
178  assertEquals(s, f(mkT(), d));
179  assertEquals(s, f(mkT(), d));
180  assertEquals(s, f(mkT(), d));
181  %OptimizeFunctionOnNextCall(f);
182  assertEquals(s, f(mkT(), d));
183  assertEquals(s, f(mkT(), {}));
184}
185
186var s = "a1b2c3d4";
187function mkTable() { return { a: "1", b: "2", c: "3", d: "4" }; }
188
189
190tryFunction(s, mkTable, a);
191tryFunction(s, mkTable, b);
192tryFunction("0a1b2c3d", function () { return "abcd"; }, c);
193tryFunction("0a1b2c3d", function () {
194  var cnt = false;
195  return function () {
196    cnt = true;
197    return "abcd";
198  }
199}, d);
200tryFunction("aabbccdd", mkTable, e);
201
202function mkSmallTable() { return { a: "1", b: "2" }; }
203
204tryFunction("aa11ab12ba21bb22", mkSmallTable, f);
205tryFunction("aa11ab12bb22ba21", mkSmallTable, g);
206tryFunction("aa11ba21", mkSmallTable, h);
207tryFunction("aa11ab12ba21bb22", mkSmallTable, j);
208tryFunction("aa11ba21", mkSmallTable, h);
209tryFunction("aa11ba21", mkSmallTable, k);
210tryFunction("aa11", mkSmallTable, l);
211tryFunction("aa11", mkSmallTable, m);
212
213// Test handling of null.
214tryFunction("", function () {
215  return function () { return null; }
216}, function (t) {
217  for (var i in t()) { return i; }
218  return "";
219});
220
221// Test smis.
222tryFunction("", function () {
223  return function () { return 11; }
224}, function (t) {
225  for (var i in t()) { return i; }
226  return "";
227});
228
229// Test LoadFieldByIndex for out of object properties.
230function O() { this.a = 1; }
231for (var i = 0; i < 10; i++) new O();
232tryFunction("a1b2c3d4e5f6", function () {
233  var o = new O();
234  o.b = 2;
235  o.c = 3;
236  o.d = 4;
237  o.e = 5;
238  o.f = 6;
239  return o;
240}, function (t) {
241  var r = [];
242  for (var i in t) r.push(i + t[i]);
243  return r.join('');
244});
245
246// Test OSR inside for-in.
247function osr_inner(t, limit) {
248  var r = 1;
249  for (var x in t) {
250    if (t.hasOwnProperty(x)) {
251      for (var i = 0; i < t[x].length; i++) {
252        r += t[x][i];
253        if (i === limit) {
254          %OptimizeFunctionOnNextCall(osr_inner, "osr");
255        }
256      }
257      r += x;
258    }
259  }
260  return r;
261}
262
263function osr_outer(t, osr_after) {
264  var r = 1;
265  for (var x in t) {
266    for (var i = 0; i < t[x].length; i++) {
267      r += t[x][i];
268    }
269    if (x === osr_after) {
270      %OptimizeFunctionOnNextCall(osr_outer, "osr");
271    }
272    r += x;
273  }
274  return r;
275}
276
277function osr_outer_and_deopt(t, osr_after) {
278  var r = 1;
279  for (var x in t) {
280    r += x;
281    if (x == osr_after) {
282      %OptimizeFunctionOnNextCall(osr_outer_and_deopt, "osr");
283    }
284  }
285  return r;
286}
287
288function test_osr() {
289  with ({}) {}  // Disable optimizations of this function.
290  var arr = new Array(20);
291  for (var i = 0; i < arr.length; i++) {
292    arr[i] = i + 1;
293  }
294  arr.push(":");  // Force deopt at the end of the loop.
295  assertEquals("211:x1234567891011121314151617181920:y", osr_inner({x: arr, y: arr}, (arr.length / 2) | 0));
296  assertEquals("7x456y", osr_outer({x: [1,2,3], y: [4,5,6]}, "x"));
297  assertEquals("101234567", osr_outer_and_deopt([1,2,3,4,5,6,7,8], "5"));
298}
299
300test_osr();
301