1// Copyright 2011 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: --harmony-scoping --allow-natives-syntax
29
30"use strict";
31
32// Check that the following functions are optimizable.
33var functions = [ f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14,
34                  f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26,
35                  f27, f28, f29, f30, f31, f32, f33];
36
37for (var i = 0; i < functions.length; ++i) {
38  var func = functions[i];
39  print("Testing:");
40  print(func);
41  for (var j = 0; j < 10; ++j) {
42    func(12);
43  }
44  %OptimizeFunctionOnNextCall(func);
45  func(12);
46  assertOptimized(func);
47}
48
49function f1() { }
50
51function f2(x) { }
52
53function f3() {
54  let x;
55}
56
57function f4() {
58  function foo() {
59  }
60}
61
62function f5() {
63  let x = 1;
64}
65
66function f6() {
67  const x = 1;
68}
69
70function f7(x) {
71  return x;
72}
73
74function f8() {
75  let x;
76  return x;
77}
78
79function f9() {
80  function x() {
81  }
82  return x;
83}
84
85function f10(x) {
86  x = 1;
87}
88
89function f11() {
90  let x;
91  x = 1;
92}
93
94function f12() {
95  function x() {};
96  x = 1;
97}
98
99function f13(x) {
100  (function() { x; });
101}
102
103function f14() {
104  let x;
105  (function() { x; });
106}
107
108function f15() {
109  function x() {
110  }
111  (function() { x; });
112}
113
114function f16() {
115  let x = 1;
116  (function() { x; });
117}
118
119function f17() {
120  const x = 1;
121  (function() { x; });
122}
123
124function f18(x) {
125  return x;
126  (function() { x; });
127}
128
129function f19() {
130  let x;
131  return x;
132  (function() { x; });
133}
134
135function f20() {
136  function x() {
137  }
138  return x;
139  (function() { x; });
140}
141
142function f21(x) {
143  x = 1;
144  (function() { x; });
145}
146
147function f22() {
148  let x;
149  x = 1;
150  (function() { x; });
151}
152
153function f23() {
154  function x() { }
155  x = 1;
156  (function() { x; });
157}
158
159function f24() {
160  let x = 1;
161  {
162    let x = 2;
163    {
164      let x = 3;
165      assertEquals(3, x);
166    }
167    assertEquals(2, x);
168  }
169  assertEquals(1, x);
170}
171
172function f25() {
173  {
174    let x = 2;
175    L: {
176      let x = 3;
177      assertEquals(3, x);
178      break L;
179      assertTrue(false);
180    }
181    assertEquals(2, x);
182  }
183  assertTrue(true);
184}
185
186function f26() {
187  {
188    let x = 1;
189    L: {
190      let x = 2;
191      {
192        let x = 3;
193        assertEquals(3, x);
194        break L;
195        assertTrue(false);
196      }
197      assertTrue(false);
198    }
199    assertEquals(1, x);
200  }
201}
202
203
204function f27() {
205  do {
206    let x = 4;
207    assertEquals(4,x);
208    {
209      let x = 5;
210      assertEquals(5, x);
211      continue;
212      assertTrue(false);
213    }
214  } while (false);
215}
216
217function f28() {
218  label: for (var i = 0; i < 10; ++i) {
219    let x = 'middle' + i;
220    for (var j = 0; j < 10; ++j) {
221      let x = 'inner' + j;
222      continue label;
223    }
224  }
225}
226
227function f29() {
228  // Verify that the context is correctly set in the stack frame after exiting
229  // from with.
230
231  let x = 'outer';
232  label: {
233    let x = 'inner';
234    break label;
235  }
236  f();  // The context could be restored from the stack after the call.
237  assertEquals('outer', x);
238
239  function f() {
240    assertEquals('outer', x);
241  };
242}
243
244function f30() {
245  let x = 'outer';
246  for (var i = 0; i < 10; ++i) {
247    let x = 'inner';
248    continue;
249  }
250  f();
251  assertEquals('outer', x);
252
253  function f() {
254    assertEquals('outer', x);
255  };
256}
257
258function f31() {
259  {
260    let x = 'outer';
261    label: for (var i = 0; assertEquals('outer', x), i < 10; ++i) {
262      let x = 'middle' + i;
263      {
264        let x = 'inner' + j;
265        continue label;
266      }
267    }
268    assertEquals('outer', x);
269  }
270}
271
272var c = true;
273
274function f32() {
275  {
276    let x = 'outer';
277    L: {
278      {
279        let x = 'inner';
280        if (c) {
281          break L;
282        }
283      }
284      foo();
285    }
286  }
287
288  function foo() {
289    return 'bar';
290  }
291}
292
293function f33() {
294  {
295    let x = 'outer';
296    L: {
297      {
298        let x = 'inner';
299        if (c) {
300          break L;
301        }
302        foo();
303      }
304    }
305  }
306
307  function foo() {
308    return 'bar';
309  }
310}
311
312function TestThrow() {
313  function f() {
314    let x = 'outer';
315    {
316      let x = 'inner';
317      throw x;
318    }
319  }
320  for (var i = 0; i < 5; i++) {
321    try {
322      f();
323    } catch (e) {
324      assertEquals('inner', e);
325    }
326  }
327  %OptimizeFunctionOnNextCall(f);
328  try {
329    f();
330  } catch (e) {
331    assertEquals('inner', e);
332  }
333  assertOptimized(f);
334}
335
336TestThrow();
337
338// Test that temporal dead zone semantics for function and block scoped
339// let bindings are handled by the optimizing compiler.
340
341function TestFunctionLocal(s) {
342  'use strict';
343  var func = eval("(function baz(){" + s + "; })");
344  print("Testing:");
345  print(func);
346  for (var i = 0; i < 5; ++i) {
347    try {
348      func();
349      assertUnreachable();
350    } catch (e) {
351      assertInstanceof(e, ReferenceError);
352    }
353  }
354  %OptimizeFunctionOnNextCall(func);
355  try {
356    func();
357    assertUnreachable();
358  } catch (e) {
359    assertInstanceof(e, ReferenceError);
360  }
361}
362
363function TestFunctionContext(s) {
364  'use strict';
365  var func = eval("(function baz(){ " + s + "; (function() { x; }); })");
366  print("Testing:");
367  print(func);
368  for (var i = 0; i < 5; ++i) {
369    print(i);
370    try {
371      func();
372      assertUnreachable();
373    } catch (e) {
374      assertInstanceof(e, ReferenceError);
375    }
376  }
377  print("optimize");
378  %OptimizeFunctionOnNextCall(func);
379  try {
380    print("call");
381    func();
382    assertUnreachable();
383  } catch (e) {
384    print("catch");
385    assertInstanceof(e, ReferenceError);
386  }
387}
388
389function TestBlockLocal(s) {
390  'use strict';
391  var func = eval("(function baz(){ { " + s + "; } })");
392  print("Testing:");
393  print(func);
394  for (var i = 0; i < 5; ++i) {
395    try {
396      func();
397      assertUnreachable();
398    } catch (e) {
399      assertInstanceof(e, ReferenceError);
400    }
401  }
402  %OptimizeFunctionOnNextCall(func);
403  try {
404    func();
405    assertUnreachable();
406  } catch (e) {
407    assertInstanceof(e, ReferenceError);
408  }
409}
410
411function TestBlockContext(s) {
412  'use strict';
413  var func = eval("(function baz(){ { " + s + "; (function() { x; }); } })");
414  print("Testing:");
415  print(func);
416  for (var i = 0; i < 5; ++i) {
417    print(i);
418    try {
419      func();
420      assertUnreachable();
421    } catch (e) {
422      assertInstanceof(e, ReferenceError);
423    }
424  }
425  print("optimize");
426  %OptimizeFunctionOnNextCall(func);
427  try {
428    print("call");
429    func();
430    assertUnreachable();
431  } catch (e) {
432    print("catch");
433    assertInstanceof(e, ReferenceError);
434  }
435}
436
437function TestAll(s) {
438  TestFunctionLocal(s);
439  TestFunctionContext(s);
440  TestBlockLocal(s);
441  TestBlockContext(s);
442}
443
444// Use before initialization in declaration statement.
445TestAll('let x = x + 1');
446TestAll('let x = x += 1');
447TestAll('let x = x++');
448TestAll('let x = ++x');
449TestAll('const x = x + 1');
450
451// Use before initialization in prior statement.
452TestAll('x + 1; let x;');
453TestAll('x = 1; let x;');
454TestAll('x += 1; let x;');
455TestAll('++x; let x;');
456TestAll('x++; let x;');
457TestAll('let y = x; const x = 1;');
458
459
460function f(x) {
461  let y = x + 42;
462  return y;
463}
464
465function g(x) {
466  {
467    let y = x + 42;
468    return y;
469  }
470}
471
472for (var i=0; i<10; i++) {
473  f(i);
474  g(i);
475}
476
477%OptimizeFunctionOnNextCall(f);
478%OptimizeFunctionOnNextCall(g);
479
480f(12);
481g(12);
482
483assertTrue(%GetOptimizationStatus(f) != 2);
484assertTrue(%GetOptimizationStatus(g) != 2);
485