text: // Copyright 2011 the V8 project authors. All rights reserved.
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are
  // met:
  //
  //     * Redistributions of source code must retain the above copyright
  //       notice, this list of conditions and the following disclaimer.
  //     * Redistributions in binary form must reproduce the above
  //       copyright notice, this list of conditions and the following
  //       disclaimer in the documentation and/or other materials provided
  //       with the distribution.
  //     * Neither the name of Google Inc. nor the names of its
  //       contributors may be used to endorse or promote products derived
  //       from this software without specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
  // Flags: --harmony-scoping --allow-natives-syntax --noparallel-recompilation
  
  // TODO(ES6): properly activate extended mode
  "use strict";
  
  // Check that the following functions are optimizable.
  var functions = [ f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14,
                    f15, f16, f17, f18, f19, f20, f21, f22, f23 ];
  
  for (var i = 0; i < functions.length; ++i) {
    var func = functions[i];
    print("Testing:");
    print(func);
    for (var j = 0; j < 10; ++j) {
      func(12);
    }
    %OptimizeFunctionOnNextCall(func);
    func(12);
    assertTrue(%GetOptimizationStatus(func) != 2);
  }
  
  function f1() { }
  
  function f2(x) { }
  
  function f3() {
    let x;
  }
  
  function f4() {
    function foo() {
    }
  }
  
  function f5() {
    let x = 1;
  }
  
  function f6() {
    const x = 1;
  }
  
  function f7(x) {
    return x;
  }
  
  function f8() {
    let x;
    return x;
  }
  
  function f9() {
    function x() {
    }
    return x;
  }
  
  function f10(x) {
    x = 1;
  }
  
  function f11() {
    let x;
    x = 1;
  }
  
  function f12() {
    function x() {};
    x = 1;
  }
  
  function f13(x) {
    (function() { x; });
  }
  
  function f14() {
    let x;
    (function() { x; });
  }
  
  function f15() {
    function x() {
    }
    (function() { x; });
  }
  
  function f16() {
    let x = 1;
    (function() { x; });
  }
  
  function f17() {
    const x = 1;
    (function() { x; });
  }
  
  function f18(x) {
    return x;
    (function() { x; });
  }
  
  function f19() {
    let x;
    return x;
    (function() { x; });
  }
  
  function f20() {
    function x() {
    }
    return x;
    (function() { x; });
  }
  
  function f21(x) {
    x = 1;
    (function() { x; });
  }
  
  function f22() {
    let x;
    x = 1;
    (function() { x; });
  }
  
  function f23() {
    function x() { }
    x = 1;
    (function() { x; });
  }
  
  
  // Test that temporal dead zone semantics for function and block scoped
  // let bindings are handled by the optimizing compiler.
  
  function TestFunctionLocal(s) {
    'use strict';
    var func = eval("(function baz(){" + s + "; })");
    print("Testing:");
    print(func);
    for (var i = 0; i < 5; ++i) {
      try {
        func();
        assertUnreachable();
      } catch (e) {
        assertInstanceof(e, ReferenceError);
      }
    }
    %OptimizeFunctionOnNextCall(func);
    try {
      func();
      assertUnreachable();
    } catch (e) {
      assertInstanceof(e, ReferenceError);
    }
  }
  
  function TestFunctionContext(s) {
    'use strict';
    var func = eval("(function baz(){ " + s + "; (function() { x; }); })");
    print("Testing:");
    print(func);
    for (var i = 0; i < 5; ++i) {
      print(i);
      try {
        func();
        assertUnreachable();
      } catch (e) {
        assertInstanceof(e, ReferenceError);
      }
    }
    print("optimize");
    %OptimizeFunctionOnNextCall(func);
    try {
      print("call");
      func();
      assertUnreachable();
    } catch (e) {
      print("catch");
      assertInstanceof(e, ReferenceError);
    }
  }
  
  function TestAll(s) {
    TestFunctionLocal(s);
    TestFunctionContext(s);
  }
  
  // Use before initialization in declaration statement.
  TestAll('let x = x + 1');
  TestAll('let x = x += 1');
  TestAll('let x = x++');
  TestAll('let x = ++x');
  TestAll('const x = x + 1');
  
  // Use before initialization in prior statement.
  TestAll('x + 1; let x;');
  TestAll('x = 1; let x;');
  TestAll('x += 1; let x;');
  TestAll('++x; let x;');
  TestAll('x++; let x;');
  TestAll('let y = x; const x = 1;');
  
  
  function f(x, b) {
    let y = (b ? y : x) + 42;
    return y;
  }
  
  function g(x, b) {
    {
      let y = (b ? y : x) + 42;
      return y;
    }
  }
  
  for (var i=0; i<10; i++) {
    f(i, false);
    g(i, false);
  }
  
  %OptimizeFunctionOnNextCall(f);
  %OptimizeFunctionOnNextCall(g);
  
  try {
    f(42, true);
  } catch (e) {
    assertInstanceof(e, ReferenceError);
  }
  
  try {
    g(42, true);
  } catch (e) {
    assertInstanceof(e, ReferenceError);
  }
  