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