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) %OptimizeOsr();
255      }
256      r += x;
257    }
258  }
259  return r;
260}
261
262function osr_outer(t, osr_after) {
263  var r = 1;
264  for (var x in t) {
265    for (var i = 0; i < t[x].length; i++) {
266      r += t[x][i];
267    }
268    if (x === osr_after) %OptimizeOsr();
269    r += x;
270  }
271  return r;
272}
273
274function osr_outer_and_deopt(t, osr_after) {
275  var r = 1;
276  for (var x in t) {
277    r += x;
278    if (x == osr_after) %OptimizeOsr();
279  }
280  return r;
281}
282
283function test_osr() {
284  with ({}) {}  // Disable optimizations of this function.
285  var arr = new Array(20);
286  for (var i = 0; i < arr.length; i++) {
287    arr[i] = i + 1;
288  }
289  arr.push(":");  // Force deopt at the end of the loop.
290  assertEquals("211:x1234567891011121314151617181920:y", osr_inner({x: arr, y: arr}, (arr.length / 2) | 0));
291  assertEquals("7x456y", osr_outer({x: [1,2,3], y: [4,5,6]}, "x"));
292  assertEquals("101234567", osr_outer_and_deopt([1,2,3,4,5,6,7,8], "5"));
293}
294
295test_osr();
296