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