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