mirror of
				https://github.com/tc39/test262.git
				synced 2025-11-04 05:33:50 +01:00 
			
		
		
		
	sourceRevisionAtLastExport: 33f2fb0e53d135f0ee17cfccd9d993eb2a6f47de targetRevisionAtLastExport: 31340cbd9add103f586d501b0c3354b7b182abc0
		
			
				
	
	
		
			306 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			306 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
// Copyright 2015 the V8 project authors. All rights reserved.
 | 
						|
// Use of this source code is governed by a BSD-style license that can be
 | 
						|
// found in the LICENSE file.
 | 
						|
 | 
						|
// Flags: --harmony-do-expressions --allow-natives-syntax --no-always-opt --opt
 | 
						|
 | 
						|
function returnValue(v) { return v; }
 | 
						|
function MyError() {}
 | 
						|
var global = this;
 | 
						|
 | 
						|
function TestBasic() {
 | 
						|
  // Looping and lexical declarations
 | 
						|
  assertEquals(512, returnValue(do {
 | 
						|
    let n = 2;
 | 
						|
    for (let i = 0; i < 4; i++) n <<= 2;
 | 
						|
  }));
 | 
						|
 | 
						|
  // Strings do the right thing
 | 
						|
  assertEquals("spooky halloween", returnValue(do {
 | 
						|
    "happy halloween".replace('happy', 'spooky');
 | 
						|
  }));
 | 
						|
 | 
						|
  // Do expressions with no completion produce an undefined value
 | 
						|
  assertEquals(undefined, returnValue(do {}));
 | 
						|
  assertEquals(undefined, returnValue(do { var x = 99; }));
 | 
						|
  assertEquals(undefined, returnValue(do { function f() {}; }));
 | 
						|
  assertEquals(undefined, returnValue(do { let z = 33; }));
 | 
						|
 | 
						|
  // Propagation of exception
 | 
						|
  assertThrows(function() {
 | 
						|
    (do {
 | 
						|
      throw new MyError();
 | 
						|
      "potatoes";
 | 
						|
    });
 | 
						|
  }, MyError);
 | 
						|
 | 
						|
  assertThrows(function() {
 | 
						|
    return do {
 | 
						|
      throw new MyError();
 | 
						|
      "potatoes";
 | 
						|
    };
 | 
						|
  }, MyError);
 | 
						|
 | 
						|
  // Return value within do-block overrides `return |do-expression|`
 | 
						|
  assertEquals("inner-return", (function() {
 | 
						|
    return "outer-return" + do {
 | 
						|
      return "inner-return";
 | 
						|
      "";
 | 
						|
    };
 | 
						|
  })());
 | 
						|
 | 
						|
  var count = 0, n = 1;
 | 
						|
  // Breaking out |do-expression|
 | 
						|
  assertEquals(3, (function() {
 | 
						|
    for (var i = 0; i < 10; ++i) (count += 2 * do { if (i === 3) break; ++n });
 | 
						|
    return i;
 | 
						|
  })());
 | 
						|
  // (2 * 2) + (2 * 3) + (2 * 4)
 | 
						|
  assertEquals(18, count);
 | 
						|
 | 
						|
  // Continue in |do-expression|
 | 
						|
  count = 0, n = 1;
 | 
						|
  assertEquals([1, 3, 5, 7, 9], (function() {
 | 
						|
    var values = [];
 | 
						|
    for (var i = 0; i < 10; ++i) {
 | 
						|
      count += 2 * (do {
 | 
						|
        if ((i & 1) === 0) continue;
 | 
						|
        values.push(i);
 | 
						|
        ++n;
 | 
						|
      }) + 1;
 | 
						|
    }
 | 
						|
    // (2*2) + 1 + (2*3) + 1 + (2*4) + 1 + (2*5) + 1 + (2*6) + 1
 | 
						|
    return values;
 | 
						|
  })());
 | 
						|
  assertEquals(count, 45);
 | 
						|
 | 
						|
  assertThrows("(do { break; });", SyntaxError);
 | 
						|
  assertThrows("(do { continue; });", SyntaxError);
 | 
						|
 | 
						|
  // Real-world use case for desugaring
 | 
						|
  var array = [1, 2, 3, 4, 5], iterable = [6, 7, 8,9];
 | 
						|
  assertEquals([1, 2, 3, 4, 5, 6, 7, 8, 9], do {
 | 
						|
    for (var element of iterable) array.push(element);
 | 
						|
    array;
 | 
						|
  });
 | 
						|
 | 
						|
  // Nested do-expressions
 | 
						|
  assertEquals(125, do { (do { (do { 5 * 5 * 5 }) }) });
 | 
						|
 | 
						|
  // Directives are not honoured
 | 
						|
  (do {
 | 
						|
    "use strict";
 | 
						|
    foo = 80;
 | 
						|
    assertEquals(foo, 80);
 | 
						|
  });
 | 
						|
 | 
						|
  // Non-empty operand stack testing
 | 
						|
  var O = {
 | 
						|
    method1() {
 | 
						|
      let x = 256;
 | 
						|
      return x + do {
 | 
						|
        for (var i = 0; i < 4; ++i) x += i;
 | 
						|
      } + 17;
 | 
						|
    },
 | 
						|
    method2() {
 | 
						|
      let x = 256;
 | 
						|
      this.reset();
 | 
						|
      return x + do {
 | 
						|
        for (var i = 0; i < this.length(); ++i) x += this.index() * 2;
 | 
						|
      };
 | 
						|
    },
 | 
						|
    _index: 0,
 | 
						|
    index() {
 | 
						|
      return ++this._index;
 | 
						|
    },
 | 
						|
    _length: 4,
 | 
						|
    length() { return this._length; },
 | 
						|
    reset() { this._index = 0; }
 | 
						|
  };
 | 
						|
  assertEquals(535, O["method" + do { 1 } + ""]());
 | 
						|
  assertEquals(532, O["method" + do { ({ valueOf() { return "2"; } }); }]());
 | 
						|
  assertEquals(532, O[
 | 
						|
      do { let s = ""; for (let c of "method") s += c; } + "2"]());
 | 
						|
}
 | 
						|
TestBasic();
 | 
						|
 | 
						|
 | 
						|
function TestDeoptimization1() {
 | 
						|
  function f(v) {
 | 
						|
    return 88 + do {
 | 
						|
      v.a * v.b + v.c;
 | 
						|
    };
 | 
						|
  }
 | 
						|
 | 
						|
  var o1 = {};
 | 
						|
  o1.a = 10;
 | 
						|
  o1.b = 5;
 | 
						|
  o1.c = 50;
 | 
						|
 | 
						|
  var o2 = {};
 | 
						|
  o2.c = 100;
 | 
						|
  o2.a = 10;
 | 
						|
  o2.b = 10;
 | 
						|
 | 
						|
  assertEquals(188, f(o1));
 | 
						|
  assertEquals(188, f(o1));
 | 
						|
  %OptimizeFunctionOnNextCall(f);
 | 
						|
  assertEquals(188, f(o1));
 | 
						|
  assertOptimized(f);
 | 
						|
  assertEquals(288, f(o2));
 | 
						|
  assertUnoptimized(f);
 | 
						|
  assertEquals(288, f(o2));
 | 
						|
}
 | 
						|
TestDeoptimization1();
 | 
						|
 | 
						|
 | 
						|
function TestInParameterInitializers() {
 | 
						|
  var first_name = "George";
 | 
						|
  var last_name = "Jetson";
 | 
						|
  function fn1(name = do { first_name + " " + last_name }) {
 | 
						|
    return name;
 | 
						|
  }
 | 
						|
  assertEquals("George Jetson", fn1());
 | 
						|
 | 
						|
  var _items = [1, 2, 3, NaN, 4, 5];
 | 
						|
  function fn2(items = do {
 | 
						|
    let items = [];
 | 
						|
    for (var el of _items) {
 | 
						|
      if (el !== el) {
 | 
						|
        items;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      items.push(el), items;
 | 
						|
    }
 | 
						|
  }) {
 | 
						|
    return items;
 | 
						|
  }
 | 
						|
  assertEquals([1, 2, 3], fn2());
 | 
						|
 | 
						|
  function thrower() { throw new MyError(); }
 | 
						|
  function fn3(exception = do {  try { thrower(); } catch (e) { e } }) {
 | 
						|
    return exception;
 | 
						|
  }
 | 
						|
  assertDoesNotThrow(fn3);
 | 
						|
  assertInstanceof(fn3(), MyError);
 | 
						|
 | 
						|
  function fn4(exception = do { throw new MyError() }) {}
 | 
						|
  function catcher(fn) {
 | 
						|
    try {
 | 
						|
      fn();
 | 
						|
      assertUnreachable("fn() initializer should throw");
 | 
						|
    } catch (e) {
 | 
						|
      assertInstanceof(e, MyError);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  catcher(fn4);
 | 
						|
}
 | 
						|
TestInParameterInitializers();
 | 
						|
 | 
						|
 | 
						|
function TestWithEval() {
 | 
						|
  (function sloppy1() {
 | 
						|
    assertEquals(do { eval("var x = 5"), x }, 5);
 | 
						|
    assertEquals(x, 5);
 | 
						|
  })();
 | 
						|
 | 
						|
  assertThrows(function strict1() {
 | 
						|
    "use strict";
 | 
						|
    (do { eval("var x = 5"), x }, 5);
 | 
						|
  }, ReferenceError);
 | 
						|
 | 
						|
  assertThrows(function strict2() {
 | 
						|
    (do { eval("'use strict'; var x = 5"), x }, 5);
 | 
						|
  }, ReferenceError);
 | 
						|
}
 | 
						|
TestWithEval();
 | 
						|
 | 
						|
 | 
						|
function TestHoisting() {
 | 
						|
  (do { var a = 1; });
 | 
						|
  assertEquals(a, 1);
 | 
						|
  assertEquals(global.a, undefined);
 | 
						|
 | 
						|
  (do {
 | 
						|
    for (let it of [1, 2, 3, 4, 5]) {
 | 
						|
      var b = it;
 | 
						|
    }
 | 
						|
  });
 | 
						|
  assertEquals(b, 5);
 | 
						|
  assertEquals(global.b, undefined);
 | 
						|
 | 
						|
  {
 | 
						|
    let x = 1
 | 
						|
 | 
						|
    // TODO(caitp): ensure VariableStatements in |do-expressions| in parameter
 | 
						|
    // initializers, are evaluated in the same VariableEnvironment as they would
 | 
						|
    // be for eval().
 | 
						|
    // function f1(a = do { var x = 2 }, b = x) { return b }
 | 
						|
    // assertEquals(1, f1())
 | 
						|
 | 
						|
    // function f2(a = x, b = do { var x = 2 }) { return a }
 | 
						|
    // assertEquals(1, f2())
 | 
						|
 | 
						|
    function f3({a = do { var x = 2 }, b = x}) { return b }
 | 
						|
    assertEquals(2, f3({}))
 | 
						|
 | 
						|
    function f4({a = x, b = do { var x = 2 }}) { return b }
 | 
						|
    assertEquals(undefined, f4({}))
 | 
						|
 | 
						|
    function f5(a = do { var y = 0 }) {}
 | 
						|
    assertThrows(() => y, ReferenceError)
 | 
						|
  }
 | 
						|
 | 
						|
  // TODO(caitp): Always block-scope function declarations in |do| expressions
 | 
						|
  //(do {
 | 
						|
  //  assertEquals(true, inner_func());
 | 
						|
  //  function inner_func() { return true; }
 | 
						|
  //});
 | 
						|
  //assertThrows(function() { return innerFunc(); }, ReferenceError);
 | 
						|
}
 | 
						|
TestHoisting();
 | 
						|
 | 
						|
 | 
						|
// v8:4661
 | 
						|
 | 
						|
function tryFinallySimple() { (do { try {} finally {} }); }
 | 
						|
tryFinallySimple();
 | 
						|
tryFinallySimple();
 | 
						|
tryFinallySimple();
 | 
						|
tryFinallySimple();
 | 
						|
 | 
						|
var finallyRanCount = 0;
 | 
						|
function tryFinallyDoExpr() {
 | 
						|
  return (do {
 | 
						|
    try {
 | 
						|
      throw "BOO";
 | 
						|
    } catch (e) {
 | 
						|
      "Caught: " + e + " (" + finallyRanCount + ")"
 | 
						|
    } finally {
 | 
						|
      ++finallyRanCount;
 | 
						|
    }
 | 
						|
  });
 | 
						|
}
 | 
						|
assertEquals("Caught: BOO (0)", tryFinallyDoExpr());
 | 
						|
assertEquals(1, finallyRanCount);
 | 
						|
assertEquals("Caught: BOO (1)", tryFinallyDoExpr());
 | 
						|
assertEquals(2, finallyRanCount);
 | 
						|
assertEquals("Caught: BOO (2)", tryFinallyDoExpr());
 | 
						|
assertEquals(3, finallyRanCount);
 | 
						|
assertEquals("Caught: BOO (3)", tryFinallyDoExpr());
 | 
						|
assertEquals(4, finallyRanCount);
 | 
						|
 | 
						|
 | 
						|
function TestOSR() {
 | 
						|
  var numbers = do {
 | 
						|
    let nums = [];
 | 
						|
    for (let i = 0; i < 1000; ++i) {
 | 
						|
      let value = (Math.random() * 100) | 0;
 | 
						|
      nums.push(value === 0 ? 1 : value), nums;
 | 
						|
    }
 | 
						|
  };
 | 
						|
  assertEquals(numbers.length, 1000);
 | 
						|
}
 | 
						|
 | 
						|
for (var i = 0; i < 64; ++i) TestOSR();
 |