Merge V8 5.3.332.45. DO NOT MERGE
Test: Manual
FPIIM-449
Change-Id: Id3254828b068abdea3cb10442e0172a8c9a98e03
(cherry picked from commit 13e2dadd00298019ed862f2b2fc5068bba730bcf)
diff --git a/test/mjsunit/es6/array-species-constructor-accessor.js b/test/mjsunit/es6/array-species-constructor-accessor.js
new file mode 100644
index 0000000..7ebf328
--- /dev/null
+++ b/test/mjsunit/es6/array-species-constructor-accessor.js
@@ -0,0 +1,28 @@
+// Copyright 2016 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: --allow-natives-syntax
+
+// Overwriting the constructor of an instance updates the protector
+
+let x = [];
+
+assertEquals(Array, x.map(()=>{}).constructor);
+assertEquals(Array, x.filter(()=>{}).constructor);
+assertEquals(Array, x.slice().constructor);
+assertEquals(Array, x.splice().constructor);
+assertEquals(Array, x.concat([1]).constructor);
+assertEquals(1, x.concat([1])[0]);
+
+class MyArray extends Array { }
+
+Object.defineProperty(x, 'constructor', {get() { return MyArray; }});
+assertFalse(%SpeciesProtector());
+
+assertEquals(MyArray, x.map(()=>{}).constructor);
+assertEquals(MyArray, x.filter(()=>{}).constructor);
+assertEquals(MyArray, x.slice().constructor);
+assertEquals(MyArray, x.splice().constructor);
+assertEquals(MyArray, x.concat([1]).constructor);
+assertEquals(1, x.concat([1])[0]);
diff --git a/test/mjsunit/es6/array-species-constructor-delete.js b/test/mjsunit/es6/array-species-constructor-delete.js
new file mode 100644
index 0000000..fff22a2
--- /dev/null
+++ b/test/mjsunit/es6/array-species-constructor-delete.js
@@ -0,0 +1,29 @@
+// Copyright 2016 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: --allow-natives-syntax
+
+// Overwriting the constructor of an instance updates the protector
+
+let x = [];
+
+assertEquals(Array, x.map(()=>{}).constructor);
+assertEquals(Array, x.filter(()=>{}).constructor);
+assertEquals(Array, x.slice().constructor);
+assertEquals(Array, x.splice().constructor);
+assertEquals(Array, x.concat([1]).constructor);
+assertEquals(1, x.concat([1])[0]);
+
+class MyArray extends Array { }
+
+Object.prototype.constructor = MyArray;
+delete Array.prototype.constructor;
+assertFalse(%SpeciesProtector());
+
+assertEquals(MyArray, x.map(()=>{}).constructor);
+assertEquals(MyArray, x.filter(()=>{}).constructor);
+assertEquals(MyArray, x.slice().constructor);
+assertEquals(MyArray, x.splice().constructor);
+assertEquals(MyArray, x.concat([1]).constructor);
+assertEquals(1, x.concat([1])[0]);
diff --git a/test/mjsunit/es6/array-species-constructor.js b/test/mjsunit/es6/array-species-constructor.js
new file mode 100644
index 0000000..0d888f4
--- /dev/null
+++ b/test/mjsunit/es6/array-species-constructor.js
@@ -0,0 +1,28 @@
+// Copyright 2016 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: --allow-natives-syntax
+
+// Overwriting the constructor of an instance updates the protector
+
+let x = [];
+
+assertEquals(Array, x.map(()=>{}).constructor);
+assertEquals(Array, x.filter(()=>{}).constructor);
+assertEquals(Array, x.slice().constructor);
+assertEquals(Array, x.splice().constructor);
+assertEquals(Array, x.concat([1]).constructor);
+assertEquals(1, x.concat([1])[0]);
+
+class MyArray extends Array { }
+
+x.constructor = MyArray;
+assertFalse(%SpeciesProtector());
+
+assertEquals(MyArray, x.map(()=>{}).constructor);
+assertEquals(MyArray, x.filter(()=>{}).constructor);
+assertEquals(MyArray, x.slice().constructor);
+assertEquals(MyArray, x.splice().constructor);
+assertEquals(MyArray, x.concat([1]).constructor);
+assertEquals(1, x.concat([1])[0]);
diff --git a/test/mjsunit/es6/array-species-delete.js b/test/mjsunit/es6/array-species-delete.js
new file mode 100644
index 0000000..16a2fa2
--- /dev/null
+++ b/test/mjsunit/es6/array-species-delete.js
@@ -0,0 +1,29 @@
+// Copyright 2016 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: --allow-natives-syntax
+
+// Overwriting the constructor of an instance updates the protector
+
+let x = [];
+
+assertEquals(Array, x.map(()=>{}).constructor);
+assertEquals(Array, x.filter(()=>{}).constructor);
+assertEquals(Array, x.slice().constructor);
+assertEquals(Array, x.splice().constructor);
+assertEquals(Array, x.concat([1]).constructor);
+assertEquals(1, x.concat([1])[0]);
+
+class MyArray extends Array { }
+
+Object.prototype[Symbol.species] = MyArray;
+delete Array[Symbol.species];
+assertFalse(%SpeciesProtector());
+
+assertEquals(MyArray, x.map(()=>{}).constructor);
+assertEquals(MyArray, x.filter(()=>{}).constructor);
+assertEquals(MyArray, x.slice().constructor);
+assertEquals(MyArray, x.splice().constructor);
+assertEquals(MyArray, x.concat([1]).constructor);
+assertEquals(1, x.concat([1])[0]);
diff --git a/test/mjsunit/es6/array-species-modified.js b/test/mjsunit/es6/array-species-modified.js
new file mode 100644
index 0000000..58feb31
--- /dev/null
+++ b/test/mjsunit/es6/array-species-modified.js
@@ -0,0 +1,28 @@
+// Copyright 2016 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: --allow-natives-syntax
+
+// Overwriting Array[Symbol.species] updates the protector
+
+let x = [];
+
+assertEquals(Array, x.map(()=>{}).constructor);
+assertEquals(Array, x.filter(()=>{}).constructor);
+assertEquals(Array, x.slice().constructor);
+assertEquals(Array, x.splice().constructor);
+assertEquals(Array, x.concat([1]).constructor);
+assertEquals(1, x.concat([1])[0]);
+
+class MyArray extends Array { }
+
+Object.defineProperty(Array, Symbol.species, {value: MyArray});
+assertFalse(%SpeciesProtector());
+
+assertEquals(MyArray, x.map(()=>{}).constructor);
+assertEquals(MyArray, x.filter(()=>{}).constructor);
+assertEquals(MyArray, x.slice().constructor);
+assertEquals(MyArray, x.splice().constructor);
+assertEquals(MyArray, x.concat([1]).constructor);
+assertEquals(1, x.concat([1])[0]);
diff --git a/test/mjsunit/es6/array-species-parent-constructor.js b/test/mjsunit/es6/array-species-parent-constructor.js
new file mode 100644
index 0000000..b4fb1d5
--- /dev/null
+++ b/test/mjsunit/es6/array-species-parent-constructor.js
@@ -0,0 +1,28 @@
+// Copyright 2016 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: --allow-natives-syntax
+
+// Overwriting Array.prototype.constructor updates the protector
+
+let x = [];
+
+assertEquals(Array, x.map(()=>{}).constructor);
+assertEquals(Array, x.filter(()=>{}).constructor);
+assertEquals(Array, x.slice().constructor);
+assertEquals(Array, x.splice().constructor);
+assertEquals(Array, x.concat([1]).constructor);
+assertEquals(1, x.concat([1])[0]);
+
+class MyArray extends Array { }
+
+Array.prototype.constructor = MyArray;
+assertFalse(%SpeciesProtector());
+
+assertEquals(MyArray, x.map(()=>{}).constructor);
+assertEquals(MyArray, x.filter(()=>{}).constructor);
+assertEquals(MyArray, x.slice().constructor);
+assertEquals(MyArray, x.splice().constructor);
+assertEquals(MyArray, x.concat([1]).constructor);
+assertEquals(1, x.concat([1])[0]);
diff --git a/test/mjsunit/es6/array-species-proto.js b/test/mjsunit/es6/array-species-proto.js
new file mode 100644
index 0000000..6b55881
--- /dev/null
+++ b/test/mjsunit/es6/array-species-proto.js
@@ -0,0 +1,28 @@
+// Copyright 2016 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: --allow-natives-syntax
+
+// Overwriting an array instance's __proto__ updates the protector
+
+let x = [];
+
+assertEquals(Array, x.map(()=>{}).constructor);
+assertEquals(Array, x.filter(()=>{}).constructor);
+assertEquals(Array, x.slice().constructor);
+assertEquals(Array, x.splice().constructor);
+assertEquals(Array, x.concat([1]).constructor);
+assertEquals(1, x.concat([1])[0]);
+
+class MyArray extends Array { }
+
+x.__proto__ = MyArray.prototype;
+assertTrue(%SpeciesProtector());
+
+assertEquals(MyArray, x.map(()=>{}).constructor);
+assertEquals(MyArray, x.filter(()=>{}).constructor);
+assertEquals(MyArray, x.slice().constructor);
+assertEquals(MyArray, x.splice().constructor);
+assertEquals(MyArray, x.concat([1]).constructor);
+assertEquals(1, x.concat([1])[0]);
diff --git a/test/mjsunit/es6/array-species.js b/test/mjsunit/es6/array-species.js
new file mode 100644
index 0000000..25edf55
--- /dev/null
+++ b/test/mjsunit/es6/array-species.js
@@ -0,0 +1,171 @@
+// 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.
+
+// Test the ES2015 @@species feature
+
+'use strict';
+
+// Subclasses of Array construct themselves under map, etc
+
+class MyArray extends Array { }
+
+assertEquals(MyArray, new MyArray().map(()=>{}).constructor);
+assertEquals(MyArray, new MyArray().filter(()=>{}).constructor);
+assertEquals(MyArray, new MyArray().slice().constructor);
+assertEquals(MyArray, new MyArray().splice().constructor);
+assertEquals(MyArray, new MyArray().concat([1]).constructor);
+assertEquals(1, new MyArray().concat([1])[0]);
+
+// Subclasses can override @@species to return the another class
+
+class MyOtherArray extends Array {
+ static get [Symbol.species]() { return MyArray; }
+}
+
+assertEquals(MyArray, new MyOtherArray().map(()=>{}).constructor);
+assertEquals(MyArray, new MyOtherArray().filter(()=>{}).constructor);
+assertEquals(MyArray, new MyOtherArray().slice().constructor);
+assertEquals(MyArray, new MyOtherArray().splice().constructor);
+assertEquals(MyArray, new MyOtherArray().concat().constructor);
+
+// Array methods on non-arrays return arrays
+
+class MyNonArray extends Array {
+ static get [Symbol.species]() { return MyObject; }
+}
+
+class MyObject { }
+
+assertEquals(MyObject,
+ Array.prototype.map.call(new MyNonArray(), ()=>{}).constructor);
+assertEquals(MyObject,
+ Array.prototype.filter.call(new MyNonArray(), ()=>{}).constructor);
+assertEquals(MyObject,
+ Array.prototype.slice.call(new MyNonArray()).constructor);
+assertEquals(MyObject,
+ Array.prototype.splice.call(new MyNonArray()).constructor);
+assertEquals(MyObject,
+ Array.prototype.concat.call(new MyNonArray()).constructor);
+
+assertEquals(undefined,
+ Array.prototype.map.call(new MyNonArray(), ()=>{}).length);
+assertEquals(undefined,
+ Array.prototype.filter.call(new MyNonArray(), ()=>{}).length);
+assertEquals(undefined,
+ Array.prototype.concat.call(new MyNonArray(), ()=>{}).length);
+// slice and splice actually do explicitly define the length for some reason
+assertEquals(0, Array.prototype.slice.call(new MyNonArray()).length);
+assertEquals(0, Array.prototype.splice.call(new MyNonArray()).length);
+
+// Cross-realm Arrays build same-realm arrays
+
+var realm = Realm.create();
+assertEquals(Array,
+ Array.prototype.map.call(
+ Realm.eval(realm, "[]"), ()=>{}).constructor);
+assertFalse(Array === Realm.eval(realm, "[]").map(()=>{}).constructor);
+assertFalse(Array === Realm.eval(realm, "[].map(()=>{}).constructor"));
+assertEquals(Array,
+ Array.prototype.concat.call(
+ Realm.eval(realm, "[]")).constructor);
+
+// Defaults when constructor or @@species is missing or non-constructor
+
+class MyDefaultArray extends Array {
+ static get [Symbol.species]() { return undefined; }
+}
+assertEquals(Array, new MyDefaultArray().map(()=>{}).constructor);
+
+class MyOtherDefaultArray extends Array { }
+assertEquals(MyOtherDefaultArray,
+ new MyOtherDefaultArray().map(()=>{}).constructor);
+MyOtherDefaultArray.prototype.constructor = undefined;
+assertEquals(Array, new MyOtherDefaultArray().map(()=>{}).constructor);
+assertEquals(Array, new MyOtherDefaultArray().concat().constructor);
+
+// Exceptions propagated when getting constructor @@species throws
+
+class SpeciesError extends Error { }
+class ConstructorError extends Error { }
+class MyThrowingArray extends Array {
+ static get [Symbol.species]() { throw new SpeciesError; }
+}
+assertThrows(() => new MyThrowingArray().map(()=>{}), SpeciesError);
+Object.defineProperty(MyThrowingArray.prototype, 'constructor', {
+ get() { throw new ConstructorError; }
+});
+assertThrows(() => new MyThrowingArray().map(()=>{}), ConstructorError);
+
+// Previously unexpected errors from setting properties in arrays throw
+
+class FrozenArray extends Array {
+ constructor(...args) {
+ super(...args);
+ Object.freeze(this);
+ }
+}
+assertThrows(() => new FrozenArray([1]).map(()=>0), TypeError);
+assertThrows(() => new FrozenArray([1]).filter(()=>true), TypeError);
+assertThrows(() => new FrozenArray([1]).slice(0, 1), TypeError);
+assertThrows(() => new FrozenArray([1]).splice(0, 1), TypeError);
+assertThrows(() => new FrozenArray([]).concat([1]), TypeError);
+
+// Verify call counts and constructor parameters
+
+var count;
+var params;
+class MyObservedArray extends Array {
+ constructor(...args) {
+ super(...args);
+ params = args;
+ }
+ static get [Symbol.species]() {
+ count++
+ return this;
+ }
+}
+
+count = 0;
+params = undefined;
+assertEquals(MyObservedArray,
+ new MyObservedArray().map(()=>{}).constructor);
+assertEquals(1, count);
+assertArrayEquals([0], params);
+
+count = 0;
+params = undefined;
+assertEquals(MyObservedArray,
+ new MyObservedArray().filter(()=>{}).constructor);
+assertEquals(1, count);
+assertArrayEquals([0], params);
+
+count = 0;
+params = undefined;
+assertEquals(MyObservedArray,
+ new MyObservedArray().concat().constructor);
+assertEquals(1, count);
+assertArrayEquals([0], params);
+
+count = 0;
+params = undefined;
+assertEquals(MyObservedArray,
+ new MyObservedArray().slice().constructor);
+assertEquals(1, count);
+assertArrayEquals([0], params);
+
+count = 0;
+params = undefined;
+assertEquals(MyObservedArray,
+ new MyObservedArray().splice().constructor);
+assertEquals(1, count);
+assertArrayEquals([0], params);
+
+// @@species constructor can be a Proxy, and the realm access doesn't
+// crash
+
+class MyProxyArray extends Array { }
+let ProxyArray = new Proxy(MyProxyArray, {});
+MyProxyArray.constructor = ProxyArray;
+
+assertEquals(MyProxyArray, new ProxyArray().map(()=>{}).constructor);
diff --git a/test/mjsunit/es6/arraybuffer-species.js b/test/mjsunit/es6/arraybuffer-species.js
new file mode 100644
index 0000000..1ac6efb
--- /dev/null
+++ b/test/mjsunit/es6/arraybuffer-species.js
@@ -0,0 +1,34 @@
+// 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.
+
+// ArrayBuffer.prototype.slice makes subclass and checks length
+
+class MyArrayBuffer extends ArrayBuffer { }
+assertEquals(MyArrayBuffer, new MyArrayBuffer(0).slice().constructor);
+
+class MyShortArrayBuffer extends ArrayBuffer {
+ constructor(length) { super(length - 1); }
+}
+assertThrows(() => new MyShortArrayBuffer(5).slice(0, 4), TypeError);
+
+class SingletonArrayBuffer extends ArrayBuffer {
+ constructor(...args) {
+ if (SingletonArrayBuffer.cached) return SingletonArrayBuffer.cached;
+ super(...args);
+ SingletonArrayBuffer.cached = this;
+ }
+}
+assertThrows(() => new SingletonArrayBuffer(5).slice(0, 4), TypeError);
+
+class NonArrayBuffer extends ArrayBuffer {
+ constructor() {
+ return {};
+ }
+}
+assertThrows(() => new NonArrayBuffer(5).slice(0, 4), TypeError);
+
+// Species fallback is ArrayBuffer
+class UndefinedArrayBuffer extends ArrayBuffer { }
+UndefinedArrayBuffer.prototype.constructor = undefined;
+assertEquals(ArrayBuffer, new UndefinedArrayBuffer(0).slice().constructor);
diff --git a/test/mjsunit/es6/block-eval-var-over-let.js b/test/mjsunit/es6/block-eval-var-over-let.js
index febc83f..b68dbdd 100644
--- a/test/mjsunit/es6/block-eval-var-over-let.js
+++ b/test/mjsunit/es6/block-eval-var-over-let.js
@@ -8,13 +8,13 @@
assertThrows(function() {
let x = 1;
eval('var x');
-}, TypeError);
+}, SyntaxError);
// If the eval is in its own block scope, throws
assertThrows(function() {
let y = 1;
{ eval('var y'); }
-}, TypeError);
+}, SyntaxError);
// If the let is in its own block scope, with the eval, throws
assertThrows(function() {
@@ -22,7 +22,7 @@
let x = 1;
eval('var x');
}
-}, TypeError);
+}, SyntaxError);
// Legal if the let is no longer visible
assertDoesNotThrow(function() {
@@ -37,13 +37,13 @@
assertThrows(function() {
const x = 1;
eval('var x');
-}, TypeError);
+}, SyntaxError);
// If the eval is in its own block scope, throws
assertThrows(function() {
const y = 1;
{ eval('var y'); }
-}, TypeError);
+}, SyntaxError);
// If the const is in its own block scope, with the eval, throws
assertThrows(function() {
@@ -51,7 +51,7 @@
const x = 1;
eval('var x');
}
-}, TypeError);
+}, SyntaxError);
// Legal if the const is no longer visible
assertDoesNotThrow(function() {
diff --git a/test/mjsunit/es6/classes-subclass-builtins.js b/test/mjsunit/es6/classes-subclass-builtins.js
index 7669ef3..dca514c 100644
--- a/test/mjsunit/es6/classes-subclass-builtins.js
+++ b/test/mjsunit/es6/classes-subclass-builtins.js
@@ -2,8 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --allow-natives-syntax --harmony-regexp-subclass
-// Flags: --expose-gc
+// Flags: --allow-natives-syntax --expose-gc
"use strict";
diff --git a/test/mjsunit/es6/debug-promises/async-task-event.js b/test/mjsunit/es6/debug-promises/async-task-event.js
index 88030a2..0b0fa1e 100644
--- a/test/mjsunit/es6/debug-promises/async-task-event.js
+++ b/test/mjsunit/es6/debug-promises/async-task-event.js
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --expose-debug-as debug
+// Flags: --expose-debug-as debug --allow-natives-syntax
Debug = debug.Debug;
@@ -16,8 +16,8 @@
"didHandle #1",
"willHandle #2",
"then #2",
- "enqueue #3",
"didHandle #2",
+ "enqueue #3",
"willHandle #3",
"didHandle #3"
];
@@ -58,4 +58,6 @@
});
resolver();
+%RunMicrotasks();
+
assertNull(exception);
diff --git a/test/mjsunit/es6/debug-promises/evaluate-across-microtasks.js b/test/mjsunit/es6/debug-promises/evaluate-across-microtasks.js
new file mode 100644
index 0000000..73718ee
--- /dev/null
+++ b/test/mjsunit/es6/debug-promises/evaluate-across-microtasks.js
@@ -0,0 +1,66 @@
+// Copyright 2014 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: --expose-debug-as debug --allow-natives-syntax
+
+var Debug = debug.Debug;
+var listenerComplete = false;
+var exception = null;
+var count = 0;
+var log = [];
+var done = false;
+
+function LogX(x) {
+ var stored_count = count;
+ return function() {
+ log.push(`[${stored_count}] ${x}`);
+ };
+}
+
+function DebuggerStatement() {
+ log.push(`[${count}] debugger`);
+ if (count++ < 3) {
+ debugger;
+ }
+}
+
+function listener(event, exec_state, event_data, data) {
+ if (event != Debug.DebugEvent.Break) return;
+ try {
+ var p = Promise.resolve();
+ var q = p.then(LogX("then 1"));
+ p.then(LogX("then 2"));
+ q.then(LogX("then 3"));
+ q.then(DebuggerStatement);
+ var r = q.then(() => { throw 1; });
+ r.catch(LogX("catch"));
+ listenerComplete = true;
+ } catch (e) {
+ exception = e;
+ print(e, e.stack);
+ quit(1);
+ };
+};
+
+// Add the debug event listener.
+Debug.setListener(listener);
+
+DebuggerStatement();
+LogX("start")();
+
+// Make sure that the debug event listener was invoked.
+assertTrue(listenerComplete);
+
+%RunMicrotasks();
+
+var expectation =
+ [ "[0] debugger", "[1] start", "[1] then 1",
+ "[1] then 2", "[1] then 3", "[1] debugger",
+ "[2] then 1", "[2] then 2", "[1] catch",
+ "[2] then 3", "[2] debugger", "[3] then 1",
+ "[3] then 2", "[2] catch", "[3] then 3",
+ "[3] debugger", "[3] catch",
+ ];
+
+assertEquals(expectation, log);
diff --git a/test/mjsunit/es6/debug-step-into-regexp-subclass.js b/test/mjsunit/es6/debug-step-into-regexp-subclass.js
index 599fe05..5e5eb47 100644
--- a/test/mjsunit/es6/debug-step-into-regexp-subclass.js
+++ b/test/mjsunit/es6/debug-step-into-regexp-subclass.js
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --expose-debug-as debug --harmony-regexp-subclass
+// Flags: --expose-debug-as debug
Debug = debug.Debug
diff --git a/test/mjsunit/es6/debug-stepin-generators.js b/test/mjsunit/es6/debug-stepin-generators.js
index 081dfb7..6e548b4 100644
--- a/test/mjsunit/es6/debug-stepin-generators.js
+++ b/test/mjsunit/es6/debug-stepin-generators.js
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --expose-debug-as debug
+// Flags: --expose-debug-as debug --ignition-generators
Debug = debug.Debug
var exception = null;
diff --git a/test/mjsunit/es6/function-name.js b/test/mjsunit/es6/function-name.js
new file mode 100644
index 0000000..152a631
--- /dev/null
+++ b/test/mjsunit/es6/function-name.js
@@ -0,0 +1,370 @@
+// 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.
+
+(function testVariableDeclarationsFunction() {
+ 'use strict';
+ var a = function(){};
+ assertEquals('a', a.name);
+ let b = () => {};
+ assertEquals('b', b.name);
+ const c = ((function(){}));
+ assertEquals('c', c.name);
+
+ var x = function(){}, y = () => {}, z = function withName() {};
+ assertEquals('x', x.name);
+ assertEquals('y', y.name);
+ assertEquals('withName', z.name);
+})();
+
+(function testVariableDeclarationsClass() {
+ 'use strict';
+ var a = class {};
+ assertEquals('a', a.name);
+ let b = ((class {}));
+ assertEquals('b', b.name);
+ // Should not overwrite name property.
+ const c = class { static name() { } }
+ assertEquals('function', typeof c.name);
+
+ var x = class {}, y = class NamedClass {};
+ assertEquals('x', x.name);
+ assertEquals('NamedClass', y.name);
+})();
+
+(function testObjectProperties() {
+ 'use strict';
+ var obj = {
+ a: function() {},
+ b: () => {},
+ c() { },
+ get d() { },
+ set d(val) { },
+ x: function withName() { },
+ y: class { },
+ z: class ClassName { },
+ 42: function() {},
+ 4.2: function() {},
+ __proto__: function() {},
+ };
+
+ assertEquals('a', obj.a.name);
+ assertEquals('b', obj.b.name);
+ assertEquals('c', obj.c.name);
+ var dDescriptor = Object.getOwnPropertyDescriptor(obj, 'd');
+ assertEquals('get d', dDescriptor.get.name);
+ assertEquals('set d', dDescriptor.set.name);
+ assertEquals('withName', obj.x.name);
+ assertEquals('y', obj.y.name);
+ assertEquals('ClassName', obj.z.name);
+ assertEquals('42', obj[42].name);
+ assertEquals('4.2', obj[4.2].name);
+ assertEquals('', obj.__proto__.name);
+})();
+
+(function testClassProperties() {
+ 'use strict';
+ class C {
+ a() { }
+ static b() { }
+ get c() { }
+ set c(val) { }
+ 42() { }
+ static 43() { }
+ get 44() { }
+ set 44(val) { }
+ };
+
+ assertEquals('a', C.prototype.a.name);
+ assertEquals('b', C.b.name);
+ var descriptor = Object.getOwnPropertyDescriptor(C.prototype, 'c');
+ assertEquals('get c', descriptor.get.name);
+ assertEquals('set c', descriptor.set.name);
+ assertEquals('42', C.prototype[42].name);
+ assertEquals('43', C[43].name);
+ var descriptor = Object.getOwnPropertyDescriptor(C.prototype, '44');
+ assertEquals('get 44', descriptor.get.name);
+ assertEquals('set 44', descriptor.set.name);
+})();
+
+(function testComputedProperties() {
+ 'use strict';
+ var a = 'a';
+ var b = 'b';
+ var sym1 = Symbol('1');
+ var sym2 = Symbol('2');
+ var sym3 = Symbol('3');
+ var symNoDescription = Symbol();
+ var obj = {
+ [a]: function() {},
+ [sym1]: function() {},
+ [sym2]: function withName() {},
+ [symNoDescription]: function() {},
+
+ get [sym3]() {},
+ set [b](val) {},
+ };
+
+ assertEquals('a', obj[a].name);
+ assertEquals('[1]', obj[sym1].name);
+ assertEquals('withName', obj[sym2].name);
+ assertEquals('', obj[symNoDescription].name);
+
+ assertEquals('get [3]', Object.getOwnPropertyDescriptor(obj, sym3).get.name);
+ assertEquals('set b', Object.getOwnPropertyDescriptor(obj, 'b').set.name);
+
+ var objMethods = {
+ [a]() {},
+ [sym1]() {},
+ [symNoDescription]: function() {},
+ };
+
+ assertEquals('a', objMethods[a].name);
+ assertEquals('[1]', objMethods[sym1].name);
+ assertEquals('', objMethods[symNoDescription].name);
+
+ class C {
+ [a]() { }
+ [sym1]() { }
+ static [sym2]() { }
+ [symNoDescription]() { }
+
+ get [sym3]() { }
+ static set [b](val) { }
+ }
+
+ assertEquals('a', C.prototype[a].name);
+ assertEquals('[1]', C.prototype[sym1].name);
+ assertEquals('[2]', C[sym2].name);
+ assertEquals('', C.prototype[symNoDescription].name);
+
+ assertEquals('get [3]', Object.getOwnPropertyDescriptor(C.prototype, sym3).get.name);
+ assertEquals('set b', Object.getOwnPropertyDescriptor(C, 'b').set.name);
+})();
+
+
+(function testAssignment() {
+ var basicFn, arrowFn, generatorFn, classLit;
+
+ basicFn = function() { return true; };
+ assertEquals('basicFn', basicFn.name);
+ var basicFn2 = basicFn;
+ assertEquals('basicFn', basicFn2.name);
+ basicFn = function functionWithName() { };
+ assertEquals("functionWithName", basicFn.name);
+
+ arrowFn = x => x;
+ assertEquals('arrowFn', arrowFn.name);
+ var arrowFn2 = arrowFn;
+ assertEquals('arrowFn', arrowFn2.name);
+
+ generatorFn = function*() { yield true; };
+ assertEquals('generatorFn', generatorFn.name);
+ var generatorFn2 = generatorFn;
+ assertEquals('generatorFn', generatorFn2.name);
+ generatorFn = function* generatorWithName() { };
+ assertEquals("generatorWithName", generatorFn.name);
+
+ classLit = class { constructor() {} };
+ assertEquals('classLit', classLit.name);
+ var classLit2 = classLit;
+ assertEquals('classLit', classLit2.name);
+ classLit = class classWithName { constructor() {} };
+ assertEquals('classWithName', classLit.name);
+ classLit = class { constructor() {} static name() {} };
+ assertEquals('function', typeof classLit.name);
+ classLit = class { constructor() {} static get name() { return true; } };
+ assertTrue(classLit.name);
+ classLit = class { constructor() {} static ['name']() {} };
+ assertEquals('function', typeof classLit.name);
+ classLit = class { constructor() {} static get ['name']() { return true; } };
+ assertTrue(classLit.name);
+})();
+
+(function testObjectBindingPattern() {
+ var {
+ a = function() {},
+ b = () => {},
+ x = function withName() { },
+ y = class { },
+ z = class ClassName { },
+ q = class { static name() { return 42 } },
+ foo: bar = function() {},
+ inParens = (() => {}),
+ inManyParens = ((((() => {})))),
+ } = {};
+ assertEquals('a', a.name);
+ assertEquals('b', b.name);
+ assertEquals('withName', x.name);
+ assertEquals('y', y.name);
+ assertEquals('ClassName', z.name);
+ assertEquals('function', typeof q.name);
+ assertEquals('bar', bar.name);
+ assertEquals('inParens', inParens.name)
+ assertEquals('inManyParens', inManyParens.name)
+})();
+
+(function testArrayBindingPattern() {
+ var [
+ a = function() {},
+ b = () => {},
+ x = function withName() { },
+ y = class { },
+ z = class ClassName { },
+ q = class { static name() { return 42 } },
+ inParens = (() => {}),
+ inManyParens = ((((() => {})))),
+ ] = [];
+ assertEquals('a', a.name);
+ assertEquals('b', b.name);
+ assertEquals('withName', x.name);
+ assertEquals('y', y.name);
+ assertEquals('ClassName', z.name);
+ assertEquals('function', typeof q.name);
+ assertEquals('inParens', inParens.name)
+ assertEquals('inManyParens', inManyParens.name)
+})();
+
+(function testObjectAssignmentPattern() {
+ var a, b, x, y, z, q;
+ ({
+ a = function() {},
+ b = () => {},
+ x = function withName() { },
+ y = class { },
+ z = class ClassName { },
+ q = class { static name() { return 42 } },
+ foo: bar = function() {},
+ inParens = (() => {}),
+ inManyParens = ((((() => {})))),
+ } = {});
+ assertEquals('a', a.name);
+ assertEquals('b', b.name);
+ assertEquals('withName', x.name);
+ assertEquals('y', y.name);
+ assertEquals('ClassName', z.name);
+ assertEquals('function', typeof q.name);
+ assertEquals('bar', bar.name);
+ assertEquals('inParens', inParens.name)
+ assertEquals('inManyParens', inManyParens.name)
+})();
+
+(function testArrayAssignmentPattern() {
+ var a, b, x, y, z, q;
+ [
+ a = function() {},
+ b = () => {},
+ x = function withName() { },
+ y = class { },
+ z = class ClassName { },
+ q = class { static name() { return 42 } },
+ inParens = (() => {}),
+ inManyParens = ((((() => {})))),
+ ] = [];
+ assertEquals('a', a.name);
+ assertEquals('b', b.name);
+ assertEquals('withName', x.name);
+ assertEquals('y', y.name);
+ assertEquals('ClassName', z.name);
+ assertEquals('function', typeof q.name);
+ assertEquals('inParens', inParens.name)
+ assertEquals('inManyParens', inManyParens.name)
+})();
+
+(function testParameterDestructuring() {
+ (function({ a = function() {},
+ b = () => {},
+ x = function withName() { },
+ y = class { },
+ z = class ClassName { },
+ q = class { static name() { return 42 } },
+ foo: bar = function() {},
+ inParens = (() => {}),
+ inManyParens = ((((() => {})))) }) {
+ assertEquals('a', a.name);
+ assertEquals('b', b.name);
+ assertEquals('withName', x.name);
+ assertEquals('y', y.name);
+ assertEquals('ClassName', z.name);
+ assertEquals('function', typeof q.name);
+ assertEquals('bar', bar.name);
+ assertEquals('inParens', inParens.name)
+ assertEquals('inManyParens', inManyParens.name)
+ })({});
+
+ (function([ a = function() {},
+ b = () => {},
+ x = function withName() { },
+ y = class { },
+ z = class ClassName { },
+ q = class { static name() { return 42 } },
+ inParens = (() => {}),
+ inManyParens = ((((() => {})))) ]) {
+ assertEquals('a', a.name);
+ assertEquals('b', b.name);
+ assertEquals('withName', x.name);
+ assertEquals('y', y.name);
+ assertEquals('ClassName', z.name);
+ assertEquals('function', typeof q.name);
+ assertEquals('inParens', inParens.name)
+ assertEquals('inManyParens', inManyParens.name)
+ })([]);
+})();
+
+(function testDefaultParameters() {
+ (function(a = function() {},
+ b = () => {},
+ x = function withName() { },
+ y = class { },
+ z = class ClassName { },
+ q = class { static name() { return 42 } },
+ inParens = (() => {}),
+ inManyParens = ((((() => {}))))) {
+ assertEquals('a', a.name);
+ assertEquals('b', b.name);
+ assertEquals('withName', x.name);
+ assertEquals('y', y.name);
+ assertEquals('ClassName', z.name);
+ assertEquals('function', typeof q.name);
+ assertEquals('inParens', inParens.name)
+ assertEquals('inManyParens', inManyParens.name)
+ })();
+})();
+
+(function testComputedNameNotShared() {
+ function makeClass(propName) {
+ return class {
+ static [propName]() {}
+ }
+ }
+
+ var sym1 = Symbol('1');
+ var sym2 = Symbol('2');
+ var class1 = makeClass(sym1);
+ assertEquals('[1]', class1[sym1].name);
+ var class2 = makeClass(sym2);
+ assertEquals('[2]', class2[sym2].name);
+ assertEquals('[1]', class1[sym1].name);
+})();
+
+
+(function testComputedNamesOnlyAppliedSyntactically() {
+ function factory() { return () => {}; }
+
+ var obj = { ['foo']: factory() };
+ assertEquals('', obj.foo.name);
+})();
+
+
+(function testNameNotReflectedInToString() {
+ var f = function() {};
+ var g = function*() {};
+ var obj = {
+ ['h']: function() {},
+ i: () => {}
+ };
+ assertEquals('function () {}', f.toString());
+ assertEquals('function* () {}', g.toString());
+ assertEquals('function () {}', obj.h.toString());
+ assertEquals('() => {}', obj.i.toString());
+})();
diff --git a/test/mjsunit/es6/generators-debug-liveedit.js b/test/mjsunit/es6/generators-debug-liveedit.js
index 987a42c..2bbbfc2 100644
--- a/test/mjsunit/es6/generators-debug-liveedit.js
+++ b/test/mjsunit/es6/generators-debug-liveedit.js
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --expose-debug-as debug --allow-natives-syntax
+// Flags: --expose-debug-as debug --allow-natives-syntax --ignition-generators
var Debug = debug.Debug;
var LiveEdit = Debug.LiveEdit;
diff --git a/test/mjsunit/es6/generators-debug-scopes.js b/test/mjsunit/es6/generators-debug-scopes.js
index 126572d..b2a1ded 100644
--- a/test/mjsunit/es6/generators-debug-scopes.js
+++ b/test/mjsunit/es6/generators-debug-scopes.js
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --expose-debug-as debug
+// Flags: --expose-debug-as debug --ignition-generators
var Debug = debug.Debug;
diff --git a/test/mjsunit/es6/generators-iteration.js b/test/mjsunit/es6/generators-iteration.js
index ae4c682..8f0a774 100644
--- a/test/mjsunit/es6/generators-iteration.js
+++ b/test/mjsunit/es6/generators-iteration.js
@@ -25,7 +25,7 @@
// (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: --expose-gc
+// Flags: --expose-gc --ignition-generators
// Test generator iteration.
diff --git a/test/mjsunit/es6/generators-mirror.js b/test/mjsunit/es6/generators-mirror.js
index bf21f4d..62fbae0 100644
--- a/test/mjsunit/es6/generators-mirror.js
+++ b/test/mjsunit/es6/generators-mirror.js
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --expose-debug-as debug
+// Flags: --expose-debug-as debug --ignition-generators
// Test the mirror object for functions.
function *generator(f) {
diff --git a/test/mjsunit/es6/generators-objects.js b/test/mjsunit/es6/generators-objects.js
index 2d23841..9a07518 100644
--- a/test/mjsunit/es6/generators-objects.js
+++ b/test/mjsunit/es6/generators-objects.js
@@ -25,7 +25,7 @@
// (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: --allow-natives-syntax
+// Flags: --allow-natives-syntax --ignition-generators
// Test instantations of generators.
@@ -113,3 +113,17 @@
assertSame(generator_prototype, Object.getPrototypeOf(g()));
}
TestPrototype();
+
+
+function TestComputedPropertyNames() {
+ function* f1() { return {[yield]: 42} }
+ var g1 = f1();
+ g1.next();
+ assertEquals(42, g1.next('a').value.a);
+
+ function* f2() { return {['a']: yield} }
+ var g2 = f2();
+ g2.next();
+ assertEquals(42, g2.next(42).value.a);
+}
+TestComputedPropertyNames();
diff --git a/test/mjsunit/es6/generators-parsing.js b/test/mjsunit/es6/generators-parsing.js
index f3f8cad..143c3d7 100644
--- a/test/mjsunit/es6/generators-parsing.js
+++ b/test/mjsunit/es6/generators-parsing.js
@@ -25,6 +25,8 @@
// (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: --ignition-generators
+
// Test basic generator syntax.
// Yield statements.
diff --git a/test/mjsunit/es6/generators-poisoned-properties.js b/test/mjsunit/es6/generators-poisoned-properties.js
index e861022..5a0c652 100644
--- a/test/mjsunit/es6/generators-poisoned-properties.js
+++ b/test/mjsunit/es6/generators-poisoned-properties.js
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// Flags: --ignition-generators
+
(function testRestrictedPropertiesStrict() {
function* generator() { "use strict"; }
assertFalse(generator.hasOwnProperty("arguments"));
diff --git a/test/mjsunit/es6/generators-relocation.js b/test/mjsunit/es6/generators-relocation.js
index 2636f52..28311a8 100644
--- a/test/mjsunit/es6/generators-relocation.js
+++ b/test/mjsunit/es6/generators-relocation.js
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --expose-debug-as debug
+// Flags: --expose-debug-as debug --ignition-generators
var Debug = debug.Debug;
diff --git a/test/mjsunit/es6/generators-runtime.js b/test/mjsunit/es6/generators-runtime.js
index 5c426b2..0cdbfca 100644
--- a/test/mjsunit/es6/generators-runtime.js
+++ b/test/mjsunit/es6/generators-runtime.js
@@ -25,6 +25,8 @@
// (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: --ignition-generators
+
// Test aspects of the generator runtime.
// See:
diff --git a/test/mjsunit/es6/generators-states.js b/test/mjsunit/es6/generators-states.js
index 4e8c580..fb6b14a 100644
--- a/test/mjsunit/es6/generators-states.js
+++ b/test/mjsunit/es6/generators-states.js
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// Flags: --ignition-generators
+
// Test generator states.
function Foo() {}
diff --git a/test/mjsunit/es6/instanceof.js b/test/mjsunit/es6/instanceof.js
new file mode 100644
index 0000000..6bf2259
--- /dev/null
+++ b/test/mjsunit/es6/instanceof.js
@@ -0,0 +1,67 @@
+// Copyright 2016 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.
+
+// Make sure it's an error if @@hasInstance isn't a function.
+(function() {
+ var F = {};
+ F[Symbol.hasInstance] = null;
+ assertThrows(function() { 0 instanceof F; }, TypeError);
+})();
+
+// Make sure the result is coerced to boolean.
+(function() {
+ var F = {};
+ F[Symbol.hasInstance] = function() { return undefined; };
+ assertEquals(0 instanceof F, false);
+ F[Symbol.hasInstance] = function() { return null; };
+ assertEquals(0 instanceof F, false);
+ F[Symbol.hasInstance] = function() { return true; };
+ assertEquals(0 instanceof F, true);
+})();
+
+// Make sure if @@hasInstance throws, we catch it.
+(function() {
+ var F = {};
+ F[Symbol.hasInstance] = function() { throw new Error("always throws"); }
+ try {
+ 0 instanceof F;
+ } catch (e) {
+ assertEquals(e.message, "always throws");
+ }
+})();
+
+// @@hasInstance works for bound functions.
+(function() {
+ var BC = function() {};
+ var bc = new BC();
+ var bound = BC.bind();
+ assertEquals(bound[Symbol.hasInstance](bc), true);
+ assertEquals(bound[Symbol.hasInstance]([]), false);
+})();
+
+// if OrdinaryHasInstance is passed a non-callable receiver, return false.
+assertEquals(Function.prototype[Symbol.hasInstance].call(Array, []), true);
+assertEquals(Function.prototype[Symbol.hasInstance].call({}, {}), false);
+
+// OrdinaryHasInstance passed a non-object argument returns false.
+assertEquals(Function.prototype[Symbol.hasInstance].call(Array, 0), false);
+
+// Cannot assign to @@hasInstance with %FunctionPrototype%.
+(function() {
+ "use strict";
+ function F() {}
+ assertThrows(function() { F[Symbol.hasInstance] = (v) => v }, TypeError);
+})();
+
+// Check correct invocation of @@hasInstance handler on function instance.
+(function() {
+ function F() {}
+ var counter = 0;
+ var proto = Object.getPrototypeOf(F);
+ Object.setPrototypeOf(F, null);
+ F[Symbol.hasInstance] = function(v) { ++counter; return true };
+ Object.setPrototypeOf(F, proto);
+ assertTrue(1 instanceof F);
+ assertEquals(1, counter);
+})();
diff --git a/test/mjsunit/es6/iterator-close.js b/test/mjsunit/es6/iterator-close.js
new file mode 100644
index 0000000..1a96bee
--- /dev/null
+++ b/test/mjsunit/es6/iterator-close.js
@@ -0,0 +1,1370 @@
+// Copyright 2016 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.
+
+
+function* g() { yield 42; return 88 };
+
+
+// Return method is "undefined".
+{
+ g.prototype.return = null;
+
+
+ assertEquals(undefined, (() => {
+ for (var x of g()) { break; }
+ })());
+
+ assertEquals(undefined, (() => {
+ for (let x of g()) { break; }
+ })());
+
+ assertEquals(undefined, (() => {
+ for (const x of g()) { break; }
+ })());
+
+ assertEquals(undefined, (() => {
+ for (x of g()) { break; }
+ })());
+
+
+ assertThrowsEquals(() => {
+ for (var x of g()) { throw 42; }
+ }, 42);
+
+ assertThrowsEquals(() => {
+ for (let x of g()) { throw 42; }
+ }, 42);
+
+ assertThrowsEquals(() => {
+ for (const x of g()) { throw 42; }
+ }, 42);
+
+ assertThrowsEquals(() => {
+ for (x of g()) { throw 42; }
+ }, 42);
+
+
+ assertEquals(42, (() => {
+ for (var x of g()) { return 42; }
+ })());
+
+ assertEquals(42, (() => {
+ for (let x of g()) { return 42; }
+ })());
+
+ assertEquals(42, (() => {
+ for (const x of g()) { return 42; }
+ })());
+
+ assertEquals(42, (() => {
+ for (x of g()) { return 42; }
+ })());
+
+
+ assertEquals(42, eval('for (var x of g()) { x; }'));
+
+ assertEquals(42, eval('for (let x of g()) { x; }'));
+
+ assertEquals(42, eval('for (const x of g()) { x; }'));
+
+ assertEquals(42, eval('for (x of g()) { x; }'));
+
+
+ assertEquals(42, (() => {
+ var [x] = g(); return x;
+ })());
+
+ assertEquals(42, (() => {
+ let [x] = g(); return x;
+ })());
+
+ assertEquals(42, (() => {
+ const [x] = g(); return x;
+ })());
+
+ assertEquals(42, (() => {
+ [x] = g(); return x;
+ })());
+
+ assertEquals(42,
+ (([x]) => x)(g())
+ );
+}
+
+
+// Return method is not callable.
+{
+ g.prototype.return = 666;
+
+
+ assertThrows(() => {
+ for (var x of g()) { break; }
+ }, TypeError);
+
+ assertThrows(() => {
+ for (let x of g()) { break; }
+ }, TypeError);
+
+ assertThrows(() => {
+ for (const x of g()) { break; }
+ }, TypeError);
+
+ assertThrows(() => {
+ for (x of g()) { break; }
+ }, TypeError);
+
+
+ assertThrows(() => {
+ for (var x of g()) { throw 666; }
+ }, TypeError);
+
+ assertThrows(() => {
+ for (let x of g()) { throw 666; }
+ }, TypeError);
+
+ assertThrows(() => {
+ for (const x of g()) { throw 666; }
+ }, TypeError);
+
+ assertThrows(() => {
+ for (x of g()) { throw 666; }
+ }, TypeError);
+
+
+ assertThrows(() => {
+ for (var x of g()) { return 666; }
+ }, TypeError);
+
+ assertThrows(() => {
+ for (let x of g()) { return 666; }
+ }, TypeError);
+
+ assertThrows(() => {
+ for (const x of g()) { return 666; }
+ }, TypeError);
+
+ assertThrows(() => {
+ for (x of g()) { return 666; }
+ }, TypeError);
+
+
+ assertEquals(42, eval('for (var x of g()) { x; }'));
+
+ assertEquals(42, eval('for (let x of g()) { x; }'));
+
+ assertEquals(42, eval('for (const x of g()) { x; }'));
+
+ assertEquals(42, eval('for (x of g()) { x; }'));
+
+
+ assertThrows(() => {
+ var [x] = g(); return x;
+ }, TypeError);
+
+ assertThrows(() => {
+ let [x] = g(); return x;
+ }, TypeError);
+
+ assertThrows(() => {
+ const [x] = g(); return x;
+ }, TypeError);
+
+ assertThrows(() => {
+ [x] = g(); return x;
+ }, TypeError);
+
+ assertThrows(() => {
+ (([x]) => x)(g());
+ }, TypeError);
+}
+
+
+// Return method does not return an object.
+{
+ g.prototype.return = () => 666;
+
+
+ assertThrows(() => {
+ for (var x of g()) { break; }
+ }, TypeError);
+
+ assertThrows(() => {
+ for (let x of g()) { break; }
+ }, TypeError);
+
+ assertThrows(() => {
+ for (const x of g()) { break; }
+ }, TypeError);
+
+ assertThrows(() => {
+ for (x of g()) { break; }
+ }, TypeError);
+
+
+ // Throw from the body of a for loop 'wins' vs throw
+ // originating from a bad 'return' value.
+
+ assertThrowsEquals(() => {
+ for (var x of g()) { throw 666; }
+ }, 666);
+
+ assertThrowsEquals(() => {
+ for (let x of g()) { throw 666; }
+ }, 666);
+
+ assertThrowsEquals(() => {
+ for (const x of g()) { throw 666; }
+ }, 666);
+
+ assertThrowsEquals(() => {
+ for (x of g()) { throw 666; }
+ }, 666);
+
+
+ assertThrows(() => {
+ for (var x of g()) { return 666; }
+ }, TypeError);
+
+ assertThrows(() => {
+ for (let x of g()) { return 666; }
+ }, TypeError);
+
+ assertThrows(() => {
+ for (const x of g()) { return 666; }
+ }, TypeError);
+
+ assertThrows(() => {
+ for (x of g()) { return 666; }
+ }, TypeError);
+
+
+ assertEquals(42, eval('for (var x of g()) { x; }'));
+
+ assertEquals(42, eval('for (let x of g()) { x; }'));
+
+ assertEquals(42, eval('for (const x of g()) { x; }'));
+
+ assertEquals(42, eval('for (x of g()) { x; }'));
+
+
+ assertThrows(() => {
+ var [x] = g(); return x;
+ }, TypeError);
+
+ assertThrows(() => {
+ let [x] = g(); return x;
+ }, TypeError);
+
+ assertThrows(() => {
+ const [x] = g(); return x;
+ }, TypeError);
+
+ assertThrows(() => {
+ [x] = g(); return x;
+ }, TypeError);
+
+ assertThrows(() => {
+ (([x]) => x)(g());
+ }, TypeError);
+}
+
+
+// Return method returns an object.
+{
+ let log = [];
+ g.prototype.return = (...args) => { log.push(args); return {} };
+
+
+ log = [];
+ for (var x of g()) { break; }
+ assertEquals([[]], log);
+
+ log = [];
+ for (let x of g()) { break; }
+ assertEquals([[]], log);
+
+ log = [];
+ for (const x of g()) { break; }
+ assertEquals([[]], log);
+
+ log = [];
+ for (x of g()) { break; }
+ assertEquals([[]], log);
+
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (var x of g()) { throw 42; }
+ }, 42);
+ assertEquals([[]], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (let x of g()) { throw 42; }
+ }, 42);
+ assertEquals([[]], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (const x of g()) { throw 42; }
+ }, 42);
+ assertEquals([[]], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (x of g()) { throw 42; }
+ }, 42);
+ assertEquals([[]], log);
+
+
+ log = [];
+ assertEquals(42, (() => {
+ for (var x of g()) { return 42; }
+ })());
+ assertEquals([[]], log);
+
+ log = [];
+ assertEquals(42, (() => {
+ for (let x of g()) { return 42; }
+ })());
+ assertEquals([[]], log);
+
+ log = [];
+ assertEquals(42, (() => {
+ for (const x of g()) { return 42; }
+ })());
+ assertEquals([[]], log);
+
+ log = [];
+ assertEquals(42, (() => {
+ for (x of g()) { return 42; }
+ })());
+ assertEquals([[]], log);
+
+
+ log = [];
+ assertEquals(42, eval('for (var x of g()) { x; }'));
+ assertEquals([], log);
+
+ log = [];
+ assertEquals(42, eval('for (let x of g()) { x; }'));
+ assertEquals([], log);
+
+ log = [];
+ assertEquals(42, eval('for (const x of g()) { x; }'));
+ assertEquals([], log);
+
+ log = [];
+ assertEquals(42, eval('for (x of g()) { x; }'));
+ assertEquals([], log);
+
+
+ // Even if doing the assignment throws, still call return
+ log = [];
+ x = { set attr(_) { throw 1234; } };
+ assertThrowsEquals(() => {
+ for (x.attr of g()) { throw 456; }
+ }, 1234);
+ assertEquals([[]], log);
+
+
+ log = [];
+ assertEquals(42, (() => {
+ var [x] = g(); return x;
+ })());
+ assertEquals([[]], log);
+
+ log = [];
+ assertEquals(42, (() => {
+ let [x] = g(); return x;
+ })());
+ assertEquals([[]], log);
+
+ log = [];
+ assertEquals(42, (() => {
+ const [x] = g(); return x;
+ })());
+ assertEquals([[]], log);
+
+ log = [];
+ assertEquals(42, (() => {
+ [x] = g(); return x;
+ })());
+ assertEquals([[]], log);
+
+ log = []
+ assertEquals(42,
+ (([x]) => x)(g())
+ );
+ assertEquals([[]], log);
+
+
+ log = [];
+ assertEquals(42, (() => {
+ var [x,] = g(); return x;
+ })());
+ assertEquals([[]], log);
+
+ log = [];
+ assertEquals(42, (() => {
+ let [x,] = g(); return x;
+ })());
+ assertEquals([[]], log);
+
+ log = [];
+ assertEquals(42, (() => {
+ const [x,] = g(); return x;
+ })());
+ assertEquals([[]], log);
+
+ log = [];
+ assertEquals(42, (() => {
+ [x,] = g(); return x;
+ })());
+ assertEquals([[]], log);
+
+ log = []
+ assertEquals(42,
+ (([x,]) => x)(g())
+ );
+ assertEquals([[]], log);
+
+
+ log = [];
+ assertEquals(42, (() => {
+ var [x,,] = g(); return x;
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals(42, (() => {
+ let [x,,] = g(); return x;
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals(42, (() => {
+ const [x,,] = g(); return x;
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals(42, (() => {
+ [x,,] = g(); return x;
+ })());
+ assertEquals([], log);
+
+ log = []
+ assertEquals(42,
+ (([x,,]) => x)(g())
+ );
+ assertEquals([], log);
+
+
+ log = [];
+ assertEquals([42, undefined], (() => {
+ var [x, y] = g(); return [x, y];
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals([42, undefined], (() => {
+ let [x, y] = g(); return [x, y];
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals([42, undefined], (() => {
+ const [x, y] = g(); return [x, y];
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals([42, undefined], (() => {
+ [x, y] = g(); return [x, y];
+ })());
+ assertEquals([], log);
+
+ log = []
+ assertEquals([42, undefined],
+ (([x, y]) => [x, y])(g())
+ );
+ assertEquals([], log);
+
+
+ log = [];
+ assertEquals([42], (() => {
+ var [...x] = g(); return x;
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals([42], (() => {
+ let [...x] = g(); return x;
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals([42], (() => {
+ const [...x] = g(); return x;
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals([42], (() => {
+ [...x] = g(); return x;
+ })());
+ assertEquals([], log);
+
+ log = []
+ assertEquals([42],
+ (([...x]) => x)(g())
+ );
+ assertEquals([], log);
+
+
+ log = [];
+ assertEquals([42, []], (() => {
+ var [x, ...y] = g(); return [x, y];
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals([42, []], (() => {
+ let [x, ...y] = g(); return [x, y];
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals([42, []], (() => {
+ const [x, ...y] = g(); return [x, y];
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals([42, []], (() => {
+ [x, ...y] = g(); return [x, y];
+ })());
+ assertEquals([], log);
+
+ log = []
+ assertEquals([42, []],
+ (([x, ...y]) => [x, y])(g())
+ );
+ assertEquals([], log);
+
+
+ log = [];
+ assertEquals([], (() => {
+ var [] = g(); return [];
+ })());
+ assertEquals([[]], log);
+
+ log = [];
+ assertEquals([], (() => {
+ let [] = g(); return [];
+ })());
+ assertEquals([[]], log);
+
+ log = [];
+ assertEquals([], (() => {
+ const [] = g(); return [];
+ })());
+ assertEquals([[]], log);
+
+ log = [];
+ assertEquals([], (() => {
+ [] = g(); return [];
+ })());
+ assertEquals([[]], log);
+
+ log = []
+ assertEquals([],
+ (([]) => [])(g())
+ );
+ assertEquals([[]], log);
+
+
+ log = [];
+ assertEquals([], (() => {
+ var [...[]] = g(); return [];
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals([], (() => {
+ let [...[]] = g(); return [];
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals([], (() => {
+ const [...[]] = g(); return [];
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals([], (() => {
+ [...[]] = g(); return [];
+ })());
+ assertEquals([], log);
+
+ log = []
+ assertEquals([],
+ (([...[]]) => [])(g())
+ );
+ assertEquals([], log);
+
+
+ log = [];
+ assertEquals([42], (() => {
+ var [...[x]] = g(); return [x];
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals([42], (() => {
+ let [...[x]] = g(); return [x];
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals([42], (() => {
+ const [...[x]] = g(); return [x];
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals([42], (() => {
+ [...[x]] = g(); return [x];
+ })());
+ assertEquals([], log);
+
+ log = []
+ assertEquals([42],
+ (([...[x]]) => [x])(g())
+ );
+ assertEquals([], log);
+
+
+ log = [];
+ assertEquals([42, undefined], (() => {
+ var [...[x, y]] = g(); return [x, y];
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals([42, undefined], (() => {
+ let [...[x, y]] = g(); return [x, y];
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals([42, undefined], (() => {
+ const [...[x, y]] = g(); return [x, y];
+ })());
+ assertEquals([], log);
+
+ log = [];
+ assertEquals([42, undefined], (() => {
+ [...[x, y]] = g(); return [x, y];
+ })());
+ assertEquals([], log);
+
+ log = []
+ assertEquals([42, undefined],
+ (([...[x, y]]) => [x, y])(g())
+ );
+ assertEquals([], log);
+
+
+ log = []
+ assertThrowsEquals(() => {
+ let x = { set foo(_) { throw 666; } };
+ [x.foo] = g();
+ }, 666);
+ assertEquals([[]], log);
+
+
+ log = []
+ assertThrows(() => {
+ var [[]] = g();
+ }, TypeError);
+ assertEquals([[]], log);
+
+ log = []
+ assertThrows(() => {
+ let [[]] = g();
+ }, TypeError);
+ assertEquals([[]], log);
+
+ log = []
+ assertThrows(() => {
+ const [[]] = g();
+ }, TypeError);
+ assertEquals([[]], log);
+
+ log = []
+ assertThrows(() => {
+ [[]] = g();
+ }, TypeError);
+ assertEquals([[]], log);
+
+ log = []
+ assertThrows(() => {
+ (([[]]) => 0)(g());
+ }, TypeError);
+ assertEquals([[]], log);
+
+
+ log = []
+ assertThrows(() => {
+ var [...[[]]] = g();
+ }, TypeError);
+ assertEquals([], log);
+
+ log = []
+ assertThrows(() => {
+ let [...[[]]] = g();
+ }, TypeError);
+ assertEquals([], log);
+
+ log = []
+ assertThrows(() => {
+ const [...[[]]] = g();
+ }, TypeError);
+ assertEquals([], log);
+
+ log = []
+ assertThrows(() => {
+ [...[[]]] = g();
+ }, TypeError);
+ assertEquals([], log);
+
+ log = []
+ assertThrows(() => {
+ (([...[[]]]) => 0)(g());
+ }, TypeError);
+ assertEquals([], log);
+
+
+ {
+ let backup = Array.prototype[Symbol.iterator];
+ Array.prototype[Symbol.iterator] = () => g();
+
+
+ log = [];
+ assertDoesNotThrow(() => {
+ var [x, ...[y]] = [1, 2, 3]
+ });
+ assertEquals(log, [[]]);
+
+ log = [];
+ assertDoesNotThrow(() => {
+ let [x, ...[y]] = [1, 2, 3];
+ });
+ assertEquals(log, [[]]);
+
+ log = [];
+ assertDoesNotThrow(() => {
+ const [x, ...[y]] = [1, 2, 3];
+ });
+ assertEquals(log, [[]]);
+
+ log = [];
+ assertDoesNotThrow(() => {
+ (([x, ...[y]]) => {})([1, 2, 3]);
+ });
+ assertEquals(log, [[]]);
+
+
+ log = [];
+ assertThrows(() => {
+ var [x, ...[[]]] = [1, 2, 3];
+ }, TypeError);
+ assertEquals(log, [[]]);
+
+ log = [];
+ assertThrows(() => {
+ let [x, ...[[]]] = [1, 2, 3];
+ }, TypeError);
+ assertEquals(log, [[]]);
+
+ log = [];
+ assertThrows(() => {
+ const [x, ...[[]]] = [1, 2, 3];
+ }, TypeError);
+ assertEquals(log, [[]]);
+
+ log = [];
+ assertThrows(() => {
+ (([x, ...[[]]]) => {})([1, 2, 3]);
+ }, TypeError);
+ assertEquals(log, [[]]);
+
+
+ log = [];
+ assertDoesNotThrow(() => {
+ var [x, ...[...y]] = [1, 2, 3];
+ });
+ assertEquals(log, []);
+
+ log = [];
+ assertDoesNotThrow(() => {
+ let [x, ...[...y]] = [1, 2, 3];
+ });
+ assertEquals(log, []);
+
+ log = [];
+ assertDoesNotThrow(() => {
+ const [x, ...[...y]] = [1, 2, 3];
+ });
+ assertEquals(log, []);
+
+ log = [];
+ assertDoesNotThrow(() => {
+ (([x, ...[...y]]) => {})([1, 2, 3]);
+ });
+ assertEquals(log, []);
+
+
+ Array.prototype[Symbol.iterator] = backup;
+ }
+}
+
+
+// Return method throws.
+{
+ let log = [];
+ g.prototype.return = (...args) => { log.push(args); throw 23 };
+
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (var x of g()) { break; }
+ }, 23);
+ assertEquals([[]], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (let x of g()) { break; }
+ }, 23);
+ assertEquals([[]], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (const x of g()) { break; }
+ }, 23);
+ assertEquals([[]], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (x of g()) { break; }
+ }, 23);
+ assertEquals([[]], log);
+
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (var x of g()) { throw 42; }
+ }, 42);
+ assertEquals([[]], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (let x of g()) { throw 42; }
+ }, 42);
+ assertEquals([[]], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (const x of g()) { throw 42; }
+ }, 42);
+ assertEquals([[]], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (x of g()) { throw 42; }
+ }, 42);
+ assertEquals([[]], log);
+
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (var x of g()) { return 42; }
+ }, 23);
+ assertEquals([[]], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (let x of g()) { return 42; }
+ }, 23);
+ assertEquals([[]], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (const x of g()) { return 42; }
+ }, 23);
+ assertEquals([[]], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (x of g()) { return 42; }
+ }, 23);
+ assertEquals([[]], log);
+
+
+ log = [];
+ assertEquals(42, eval('for (var x of g()) { x; }'));
+ assertEquals([], log);
+
+ log = [];
+ assertEquals(42, eval('for (let x of g()) { x; }'));
+ assertEquals([], log);
+
+ log = [];
+ assertEquals(42, eval('for (const x of g()) { x; }'));
+ assertEquals([], log);
+
+ log = [];
+ assertEquals(42, eval('for (x of g()) { x; }'));
+ assertEquals([], log);
+
+
+ log = [];
+ assertThrowsEquals(() => {
+ var [x] = g(); return x;
+ }, 23);
+ assertEquals([[]], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ let [x] = g(); return x;
+ }, 23);
+ assertEquals([[]], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ const [x] = g(); return x;
+ }, 23);
+ assertEquals([[]], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ [x] = g(); return x;
+ }, 23);
+ assertEquals([[]], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ (([x]) => x)(g())
+ }, 23);
+ assertEquals([[]], log);
+}
+
+
+// Next method throws.
+{
+ g.prototype.next = () => { throw 666; };
+ g.prototype.return = () => { assertUnreachable() };
+
+
+ assertThrowsEquals(() => {
+ for (var x of g()) {}
+ }, 666);
+
+ assertThrowsEquals(() => {
+ for (let x of g()) {}
+ }, 666);
+
+ assertThrowsEquals(() => {
+ for (const x of g()) {}
+ }, 666);
+
+ assertThrowsEquals(() => {
+ for (x of g()) {}
+ }, 666);
+
+ assertThrowsEquals(() => {
+ var [x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ let [x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ const [x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ [x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ (([x]) => x)(g());
+ }, 666);
+
+ assertThrowsEquals(() => {
+ var [...x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ let [...x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ const [...x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ [...x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ (([...x]) => x)(g());
+ }, 666);
+}
+
+
+// Value throws.
+{
+ g.prototype.next = () => ({get value() {throw 666}});
+ g.prototype.return = () => { assertUnreachable() };
+
+
+ assertThrowsEquals(() => {
+ for (var x of g()) {}
+ }, 666);
+
+ assertThrowsEquals(() => {
+ for (let x of g()) {}
+ }, 666);
+
+ assertThrowsEquals(() => {
+ for (const x of g()) {}
+ }, 666);
+
+ assertThrowsEquals(() => {
+ for (x of g()) {}
+ }, 666);
+
+ assertThrowsEquals(() => {
+ var [x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ let [x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ const [x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ [x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ (([x]) => x)(g());
+ }, 666);
+
+ assertThrowsEquals(() => {
+ var [...x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ let [...x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ const [...x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ [...x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ (([...x]) => x)(g());
+ }, 666);
+}
+
+
+// Done throws.
+{
+ g.prototype.next = () => ({get done() {throw 666}});
+ g.prototype.return = () => { assertUnreachable() };
+
+
+ assertThrowsEquals(() => {
+ for (var x of g()) {}
+ }, 666);
+
+ assertThrowsEquals(() => {
+ for (let x of g()) {}
+ }, 666);
+
+ assertThrowsEquals(() => {
+ for (const x of g()) {}
+ }, 666);
+
+ assertThrowsEquals(() => {
+ for (x of g()) {}
+ }, 666);
+
+ assertThrowsEquals(() => {
+ var [x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ let [x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ const [x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ [x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ (([x]) => x)(g());
+ }, 666);
+
+ assertThrowsEquals(() => {
+ var [...x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ let [...x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ const [...x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ [...x] = g();
+ }, 666);
+
+ assertThrowsEquals(() => {
+ (([...x]) => x)(g());
+ }, 666);
+}
+
+
+// Nested loops.
+{
+ function* g1() { yield 1; yield 2; throw 3; }
+ function* g2() { yield -1; yield -2; throw -3; }
+
+ assertDoesNotThrow(() => {
+ for (let x of g1()) {
+ for (let y of g2()) {
+ if (y == -2) break;
+ }
+ if (x == 2) break;
+ }
+ }, -3);
+
+ assertThrowsEquals(() => {
+ for (let x of g1()) {
+ for (let y of g2()) {
+ }
+ }
+ }, -3);
+
+ assertThrowsEquals(() => {
+ for (let x of g1()) {
+ for (let y of g2()) {
+ if (y == -2) break;
+ }
+ }
+ }, 3);
+
+ assertDoesNotThrow(() => {
+ l: for (let x of g1()) {
+ for (let y of g2()) {
+ if (y == -2) break l;
+ }
+ }
+ });
+
+ assertThrowsEquals(() => {
+ for (let x of g1()) {
+ for (let y of g2()) {
+ throw 4;
+ }
+ }
+ }, 4);
+
+ assertThrowsEquals(() => {
+ for (let x of g1()) {
+ for (let y of g2()) {
+ if (y == -2) throw 4;
+ }
+ }
+ }, 4);
+
+ let log = [];
+ g1.prototype.return = () => { log.push(1); throw 5 };
+ g2.prototype.return = () => { log.push(2); throw -5 };
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (let x of g1()) {
+ for (let y of g2()) {
+ if (y == -2) break;
+ }
+ if (x == 2) break;
+ }
+ }, -5);
+ assertEquals([2, 1], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (let x of g1()) {
+ for (let y of g2()) {
+ }
+ }
+ }, -3);
+ assertEquals([1], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (let x of g1()) {
+ for (let y of g2()) {
+ if (y == -2) break;
+ }
+ }
+ }, -5);
+ assertEquals([2, 1], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ l: for (let x of g1()) {
+ for (let y of g2()) {
+ if (y == -2) break l;
+ }
+ }
+ }, -5);
+ assertEquals([2, 1], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (let x of g1()) {
+ for (let y of g2()) {
+ throw 4;
+ }
+ }
+ }, 4);
+ assertEquals([2, 1], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (let x of g1()) {
+ for (let y of g2()) {
+ if (y == -2) throw 4;
+ }
+ }
+ }, 4);
+ assertEquals([2, 1], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (let x of g1()) {
+ try {
+ for (let y of g2()) {
+ }
+ } catch (_) {}
+ }
+ }, 3);
+ assertEquals([], log);
+
+ log = [];
+ assertThrowsEquals(() => {
+ for (let x of g1()) {
+ try {
+ for (let y of g2()) {
+ }
+ } catch (_) {}
+ if (x == 2) break;
+ }
+ }, 5);
+ assertEquals([1], log);
+}
+
+
+// yield*, argument's return method is "undefined".
+function TestYieldStarWithoutReturn(get_iterable) {
+ assertTrue(get_iterable().return == undefined);
+
+ function* g() { yield* get_iterable() }
+
+ {
+ let gen = g();
+ assertEquals({value: 1, done: false}, gen.next());
+ assertEquals({value: undefined, done: true}, gen.return());
+ }
+
+ assertEquals(42, (() => {
+ for (let x of g()) break;
+ return 42;
+ })());
+
+ assertEquals(42, (() => {
+ for (let x of g()) return 42;
+ })());
+
+ assertThrowsEquals(() => {
+ for (let x of g()) throw 42;
+ }, 42);
+}
+{
+ let get_iterable1 = () => [1, 2];
+ let get_iterable2 = function*() { yield 1; yield 2 };
+ get_iterable2.prototype.return = null;
+ TestYieldStarWithoutReturn(get_iterable1);
+ TestYieldStarWithoutReturn(get_iterable2);
+}
+
+
+// yield*, argument's return method is defined.
+{
+ let get_iterable = function*() { yield 1; yield 2 };
+ const obj = {};
+ get_iterable.prototype.return = (...args) => obj;
+
+ function* g() { yield* get_iterable() }
+
+ {
+ let gen = g();
+ assertEquals({value: 1, done: false}, gen.next());
+ assertSame(obj, gen.return());
+ assertSame(obj, gen.return());
+ assertSame(obj, gen.return());
+ assertEquals({value: 2, done: false}, gen.next());
+ assertSame(obj, gen.return());
+ assertSame(obj, gen.return());
+ assertSame(obj, gen.return());
+ assertEquals({value: undefined, done: true}, gen.next());
+ assertEquals({value: undefined, done: true}, gen.return());
+ assertEquals({value: undefined, done: true}, gen.return());
+ }
+
+ assertEquals(42, (() => {
+ for (let x of g()) break;
+ return 42;
+ })());
+
+ assertEquals(42, (() => {
+ for (let x of g()) return 42;
+ })());
+
+ assertThrowsEquals(() => {
+ for (let x of g()) throw 42;
+ }, 42);
+}
diff --git a/test/mjsunit/es6/json.js b/test/mjsunit/es6/json.js
index 4c1ada8..c049a25 100644
--- a/test/mjsunit/es6/json.js
+++ b/test/mjsunit/es6/json.js
@@ -9,5 +9,7 @@
assertTrue(desc.configurable);
assertFalse(desc.writable);
assertEquals("JSON", desc.value);
+ delete JSON[Symbol.toStringTag];
+ assertEquals('[object Object]', "" + JSON);
}
testJSONToString();
diff --git a/test/mjsunit/es6/legacy-subclassing.js b/test/mjsunit/es6/legacy-subclassing.js
deleted file mode 100644
index dbf666d..0000000
--- a/test/mjsunit/es6/legacy-subclassing.js
+++ /dev/null
@@ -1,38 +0,0 @@
-// 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: --noharmony-species
-
-// Before Symbol.species was added, ArrayBuffer subclasses constructed
-// ArrayBuffers, and Array subclasses constructed Arrays, but TypedArray and
-// Promise subclasses constructed an instance of the subclass.
-
-'use strict';
-
-assertEquals(undefined, Symbol.species);
-
-class MyArray extends Array { }
-let myArray = new MyArray();
-assertEquals(MyArray, myArray.constructor);
-assertEquals(Array, myArray.map(x => x + 1).constructor);
-assertEquals(Array, myArray.concat().constructor);
-
-class MyUint8Array extends Uint8Array { }
-Object.defineProperty(MyUint8Array.prototype, "BYTES_PER_ELEMENT", {value: 1});
-let myTypedArray = new MyUint8Array(3);
-assertEquals(MyUint8Array, myTypedArray.constructor);
-assertEquals(MyUint8Array, myTypedArray.map(x => x + 1).constructor);
-
-class MyArrayBuffer extends ArrayBuffer { }
-let myBuffer = new MyArrayBuffer(0);
-assertEquals(MyArrayBuffer, myBuffer.constructor);
-assertEquals(ArrayBuffer, myBuffer.slice().constructor);
-
-class MyPromise extends Promise { }
-let myPromise = new MyPromise(() => {});
-assertEquals(MyPromise, myPromise.constructor);
-assertEquals(MyPromise, myPromise.then().constructor);
-
-// However, subarray instantiates members of the parent class
-assertEquals(Uint8Array, myTypedArray.subarray(1).constructor);
diff --git a/test/mjsunit/es6/math-log2-log10.js b/test/mjsunit/es6/math-log2-log10.js
index b1a7736..ea17a79 100644
--- a/test/mjsunit/es6/math-log2-log10.js
+++ b/test/mjsunit/es6/math-log2-log10.js
@@ -57,13 +57,13 @@
var n = -1074;
// This loop covers n from -1074 to -1043
for (var lowbits = 1; lowbits <= 0x80000000; lowbits *= 2) {
- var x = %_ConstructDouble(0, lowbits);
+ var x = %ConstructDouble(0, lowbits);
assertEquals(n, Math.log2(x));
n++;
}
// This loop covers n from -1042 to -1023
for (var hibits = 1; hibits <= 0x80000; hibits *= 2) {
- var x = %_ConstructDouble(hibits, 0);
+ var x = %ConstructDouble(hibits, 0);
assertEquals(n, Math.log2(x));
n++;
}
diff --git a/test/mjsunit/es6/math.js b/test/mjsunit/es6/math.js
index cb43bd5..dc761d6 100644
--- a/test/mjsunit/es6/math.js
+++ b/test/mjsunit/es6/math.js
@@ -9,5 +9,7 @@
assertTrue(desc.configurable);
assertFalse(desc.writable);
assertEquals("Math", desc.value);
+ delete Math[Symbol.toStringTag];
+ assertEquals('[object Object]', "" + Math);
}
testMathToString();
diff --git a/test/mjsunit/es6/no-unicode-regexp-flag.js b/test/mjsunit/es6/no-unicode-regexp-flag.js
deleted file mode 100644
index 82d070e..0000000
--- a/test/mjsunit/es6/no-unicode-regexp-flag.js
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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.
-
-// Before Unicode RegExps are shipped, we shouldn't have the 'unicode'
-// property on RegExp.prototype, or read it from 'flags'.
-// mjsunit/es6/regexp-flags tests that the property is there when the
-// flag is on.
-
-// Flags: --no-harmony-unicode-regexps
-
-'use strict';
-
-assertFalse(RegExp.prototype.hasOwnProperty('unicode'));
-
-// If we were going to be really strict, we could have a test like this,
-// with the assertTrue replaced by assertFalse, since flags shouldn't
-// Get the 'unicode' property. However, it is probably OK to omit this
-// detailed fix.
-var x = /a/;
-var y = false;
-Object.defineProperty(x, 'unicode', { get() { y = true; } });
-assertEquals("", x.flags);
-assertTrue(y);
diff --git a/test/mjsunit/es6/object-tostring.js b/test/mjsunit/es6/object-tostring.js
index 29d07f2..bc7d968 100644
--- a/test/mjsunit/es6/object-tostring.js
+++ b/test/mjsunit/es6/object-tostring.js
@@ -15,15 +15,16 @@
RegExp: [ RegExp ],
Error: [ Error, TypeError, RangeError, SyntaxError, ReferenceError,
EvalError, URIError ]
-}
-for (f in funs) {
- for (i in funs[f]) {
+};
+for (var f in funs) {
+ for (var i in funs[f]) {
+
assertEquals("[object " + f + "]",
- Object.prototype.toString.call(new funs[f][i]),
- funs[f][i]);
+ Object.prototype.toString.call(new funs[f][i]),
+ funs[f][i]);
assertEquals("[object Function]",
- Object.prototype.toString.call(funs[f][i]),
- funs[f][i]);
+ Object.prototype.toString.call(funs[f][i]),
+ funs[f][i]);
}
}
@@ -130,11 +131,11 @@
}
testObjectToStringPropertyDesc();
-function testObjectToStringOwnNonStringValue() {
- var obj = Object.defineProperty({}, Symbol.toStringTag, { value: 1 });
+function testObjectToStringOnNonStringValue(obj) {
+ Object.defineProperty(obj, Symbol.toStringTag, { value: 1 });
assertEquals("[object Object]", ({}).toString.call(obj));
}
-testObjectToStringOwnNonStringValue();
+testObjectToStringOnNonStringValue({});
// Proxies
@@ -149,11 +150,77 @@
assertTag("Foo", new Proxy(() => 42, {get() {return "Foo"}}));
assertTag("Function", new Proxy(() => 42, {get() {return 666}}));
-revocable = Proxy.revocable([], {});
+var revocable = Proxy.revocable([], {});
revocable.revoke();
assertThrows(() => Object.prototype.toString.call(revocable.proxy), TypeError);
-handler = {};
+var handler = {};
revocable = Proxy.revocable([], handler);
+// The first get() call, i.e., toString() revokes the proxy
handler.get = () => revocable.revoke();
+assertEquals("[object Array]", Object.prototype.toString.call(revocable.proxy));
assertThrows(() => Object.prototype.toString.call(revocable.proxy), TypeError);
+
+revocable = Proxy.revocable([], handler);
+handler.get = () => {revocable.revoke(); return "value";};
+assertEquals("[object value]", Object.prototype.toString.call(revocable.proxy));
+assertThrows(() => Object.prototype.toString.call(revocable.proxy), TypeError);
+
+
+revocable = Proxy.revocable(function() {}, handler);
+handler.get = () => revocable.revoke();
+assertEquals("[object Function]", Object.prototype.toString.call(revocable.proxy));
+assertThrows(() => Object.prototype.toString.call(revocable.proxy), TypeError);
+
+function* gen() { yield 1; }
+
+assertTag("GeneratorFunction", gen);
+Object.defineProperty(gen, Symbol.toStringTag, {writable: true});
+gen[Symbol.toStringTag] = "different string";
+assertTag("different string", gen);
+gen[Symbol.toStringTag] = 1;
+assertTag("Function", gen);
+
+function overwriteToStringTagWithNonStringValue(tag, obj) {
+ assertTag(tag, obj);
+
+ Object.defineProperty(obj, Symbol.toStringTag, {
+ configurable: true,
+ value: "different string"
+ });
+ assertTag("different string", obj);
+
+ testObjectToStringOnNonStringValue(obj);
+}
+
+overwriteToStringTagWithNonStringValue("global", global);
+overwriteToStringTagWithNonStringValue("Generator", gen());
+
+var arrayBuffer = new ArrayBuffer();
+overwriteToStringTagWithNonStringValue("ArrayBuffer", arrayBuffer);
+overwriteToStringTagWithNonStringValue("DataView", new DataView(arrayBuffer));
+
+overwriteToStringTagWithNonStringValue("Int8Array", new Int8Array());
+overwriteToStringTagWithNonStringValue("Uint8Array", new Uint8Array());
+overwriteToStringTagWithNonStringValue("Uint8ClampedArray",
+ new Uint8ClampedArray());
+overwriteToStringTagWithNonStringValue("Int16Array", new Int16Array());
+overwriteToStringTagWithNonStringValue("Uint16Array", new Uint16Array());
+overwriteToStringTagWithNonStringValue("Int32Array", new Int32Array());
+overwriteToStringTagWithNonStringValue("Uint32Array", new Uint32Array());
+overwriteToStringTagWithNonStringValue("Float32Array", new Float32Array());
+overwriteToStringTagWithNonStringValue("Float64Array", new Float64Array());
+
+var set = new Set();
+var map = new Map();
+
+overwriteToStringTagWithNonStringValue("Set", set);
+overwriteToStringTagWithNonStringValue("Map", map);
+
+overwriteToStringTagWithNonStringValue("Set Iterator", set[Symbol.iterator]());
+overwriteToStringTagWithNonStringValue("Map Iterator", map[Symbol.iterator]());
+
+overwriteToStringTagWithNonStringValue("WeakSet", new WeakSet());
+overwriteToStringTagWithNonStringValue("WeakMap", new WeakMap());
+
+overwriteToStringTagWithNonStringValue("Promise", new Promise(function() {}));
diff --git a/test/mjsunit/es6/pattern-brand-check.js b/test/mjsunit/es6/pattern-brand-check.js
index 9b0c011..2e32294 100644
--- a/test/mjsunit/es6/pattern-brand-check.js
+++ b/test/mjsunit/es6/pattern-brand-check.js
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --harmony-regexp-subclass
-
function createNonRegExp(calls) {
return {
get [Symbol.match]() {
diff --git a/test/mjsunit/es6/promise-species.js b/test/mjsunit/es6/promise-species.js
new file mode 100644
index 0000000..f6f2e7a
--- /dev/null
+++ b/test/mjsunit/es6/promise-species.js
@@ -0,0 +1,42 @@
+// 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: --allow-natives-syntax
+
+// Test that Promises use @@species appropriately
+
+// Another constructor with no species will not be instantiated
+var test = new Promise(function(){});
+var bogoCount = 0;
+function bogusConstructor() { bogoCount++; }
+test.constructor = bogusConstructor;
+assertTrue(Promise.resolve(test) instanceof Promise);
+assertFalse(Promise.resolve(test) instanceof bogusConstructor);
+// Tests that chromium:575314 is fixed thoroughly
+Promise.resolve(test).catch(e => %AbortJS("Error " + e)).then(() => {
+ if (bogoCount != 0) %AbortJS("bogoCount was " + bogoCount + " should be 0");
+});
+
+// If there is a species, it will be instantiated
+// @@species will be read exactly once, and the constructor is called with a
+// function
+var count = 0;
+var params;
+class MyPromise extends Promise {
+ constructor(...args) {
+ super(...args);
+ params = args;
+ }
+ static get [Symbol.species]() {
+ count++
+ return this;
+ }
+}
+
+var myPromise = MyPromise.resolve().then();
+assertEquals(1, count);
+assertEquals(1, params.length);
+assertEquals('function', typeof(params[0]));
+assertTrue(myPromise instanceof MyPromise);
+assertTrue(myPromise instanceof Promise);
diff --git a/test/mjsunit/es6/proxies-for.js b/test/mjsunit/es6/proxies-for.js
index a171227..2b3060b 100644
--- a/test/mjsunit/es6/proxies-for.js
+++ b/test/mjsunit/es6/proxies-for.js
@@ -151,7 +151,7 @@
object.__proto__ = proxy;
assertEquals(["0"], keys(object));
- // The Proxy doesn't set his ownKeys enumerable.
+ // The Proxy doesn't set its ownKeys enumerable.
delete object[0];
assertEquals([], keys(object));
diff --git a/test/mjsunit/es6/proxies-json.js b/test/mjsunit/es6/proxies-json.js
index d48d539..6b40e3e 100644
--- a/test/mjsunit/es6/proxies-json.js
+++ b/test/mjsunit/es6/proxies-json.js
@@ -35,7 +35,10 @@
// Test fast case that bails out to slow case.
assertEquals(expected, JSON.stringify(object));
// Test slow case.
- assertEquals(expected, JSON.stringify(object, undefined, 0));
+ assertEquals(expected, JSON.stringify(object, (key, value) => value));
+ // Test gap.
+ assertEquals(JSON.stringify(object, null, "="),
+ JSON.stringify(object, (key, value) => value, "="));
}
@@ -67,6 +70,7 @@
var parent1a = { b: proxy1 };
testStringify('{"b":{"a":"A","b":"B","c":"C"}}', parent1a);
+testStringify('{"b":{"a":"A","b":"B","c":"C"}}', parent1a);
var parent1b = { a: 123, b: proxy1, c: true };
testStringify('{"a":123,"b":{"a":"A","b":"B","c":"C"},"c":true}', parent1b);
@@ -503,3 +507,56 @@
assertEquals(["get", target, "length", proxy], log[0]);
assertEquals(["get", target, "0", proxy], log[1]);
assertEquals(["deleteProperty", target, "0"], log[2]);
+
+proxy = new Proxy([], {
+ get: function(target, property) {
+ if (property == "length") return 7;
+ return 0;
+ },
+});
+assertEquals('[[0,0,0,0,0,0,0]]', JSON.stringify([proxy]));
+
+proxy = new Proxy([], {
+ get: function(target, property) {
+ if (property == "length") return 1E40;
+ return 0;
+ },
+});
+assertThrows(() => JSON.stringify([proxy]), RangeError);
+
+log = [];
+proxy = new Proxy({}, {
+ ownKeys: function() {
+ log.push("ownKeys");
+ return ["0", "a", "b"];
+ },
+ get: function(target, property) {
+ log.push("get " + property);
+ return property.toUpperCase();
+ },
+ getOwnPropertyDescriptor: function(target, property) {
+ log.push("descriptor " + property);
+ return {enumerable: true, configurable: true};
+ },
+ isExtensible: assertUnreachable,
+ has: assertUnreachable,
+ getPrototypeOf: assertUnreachable,
+ setPrototypeOf: assertUnreachable,
+ preventExtensions: assertUnreachable,
+ setPrototypeOf: assertUnreachable,
+ defineProperty: assertUnreachable,
+ set: assertUnreachable,
+ deleteProperty: assertUnreachable,
+ apply: assertUnreachable,
+ construct: assertUnreachable,
+});
+
+assertEquals('[{"0":"0","a":"A","b":"B"}]', JSON.stringify([proxy]));
+assertEquals(['get toJSON',
+ 'ownKeys',
+ 'descriptor 0',
+ 'descriptor a',
+ 'descriptor b',
+ 'get 0',
+ 'get a',
+ 'get b'], log);
diff --git a/test/mjsunit/es6/proxies-keys.js b/test/mjsunit/es6/proxies-keys.js
index 65dea6a..2635ac3 100644
--- a/test/mjsunit/es6/proxies-keys.js
+++ b/test/mjsunit/es6/proxies-keys.js
@@ -48,3 +48,31 @@
assertEquals(["1","2"], Object.getOwnPropertyNames(p));
assertEquals([symbol], Object.getOwnPropertySymbols(p));
})();
+
+(function testNoProxyTraps() {
+ var test_sym = Symbol("sym1");
+ var test_sym2 = Symbol("sym2");
+ var target = {
+ one: 1,
+ two: 2,
+ [test_sym]: 4,
+ 0: 0,
+ };
+ Object.defineProperty(
+ target, "non-enum",
+ { enumerable: false, value: "nope", configurable: true, writable: true });
+ target.__proto__ = {
+ target_proto: 3,
+ 1: 1,
+ [test_sym2]: 5
+ };
+ Object.defineProperty(
+ target.__proto__, "non-enum2",
+ { enumerable: false, value: "nope", configurable: true, writable: true });
+ var proxy = new Proxy(target, {});
+
+ assertEquals(["0", "one", "two"], Object.keys(proxy));
+ assertEquals(["0", "one", "two", "non-enum"],
+ Object.getOwnPropertyNames(proxy));
+ assertEquals([test_sym], Object.getOwnPropertySymbols(proxy));
+})();
diff --git a/test/mjsunit/es6/reflect.js b/test/mjsunit/es6/reflect.js
index ee272b0..d597a78 100644
--- a/test/mjsunit/es6/reflect.js
+++ b/test/mjsunit/es6/reflect.js
@@ -541,6 +541,13 @@
[s2]: 0, "-1": 0, "88": 0, "aaa": 0 };
assertEquals(["0", "42", "88", "bla", "-1", "aaa", s1, s2],
Reflect.ownKeys(obj));
+ // Force dict-mode elements.
+ delete obj[0];
+ assertEquals(["42", "88", "bla", "-1", "aaa", s1, s2],
+ Reflect.ownKeys(obj));
+ // Force dict-mode properties.
+ delete obj["bla"];
+ assertEquals(["42", "88", "-1", "aaa", s1, s2], Reflect.ownKeys(obj));
})();
diff --git a/test/mjsunit/es6/regexp-constructor.js b/test/mjsunit/es6/regexp-constructor.js
index 559ac00..b685ff2 100644
--- a/test/mjsunit/es6/regexp-constructor.js
+++ b/test/mjsunit/es6/regexp-constructor.js
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --harmony-regexp-subclass
-
"use strict";
function should_not_be_called() {
diff --git a/test/mjsunit/es6/regexp-flags.js b/test/mjsunit/es6/regexp-flags.js
index 480222d..2bcccfa 100644
--- a/test/mjsunit/es6/regexp-flags.js
+++ b/test/mjsunit/es6/regexp-flags.js
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --harmony-unicode-regexps
-
var r1 = /abc/gi;
assertEquals("abc", r1.source);
assertTrue(r1.global);
diff --git a/test/mjsunit/es6/species.js b/test/mjsunit/es6/species.js
new file mode 100644
index 0000000..39156a4
--- /dev/null
+++ b/test/mjsunit/es6/species.js
@@ -0,0 +1,35 @@
+// 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.
+
+// Test the ES2015 @@species feature
+
+'use strict';
+
+let TypedArray = Uint8Array.__proto__;
+
+// The @@species property exists on the right objects and has the right values
+
+let classesWithSpecies = [RegExp, Array, TypedArray, ArrayBuffer, Map, Set, Promise];
+let classesWithoutSpecies = [Object, Function, String, Number, Symbol, WeakMap, WeakSet];
+
+for (let constructor of classesWithSpecies) {
+ assertEquals(constructor, constructor[Symbol.species]);
+ assertThrows(function() { constructor[Symbol.species] = undefined }, TypeError);
+ let descriptor = Object.getOwnPropertyDescriptor(constructor, Symbol.species);
+ assertTrue(descriptor.configurable);
+ assertFalse(descriptor.enumerable);
+ assertEquals(undefined, descriptor.writable);
+ assertEquals(undefined, descriptor.set);
+ assertEquals('function', typeof descriptor.get);
+}
+
+// @@species is defined with distinct getters
+assertEquals(classesWithSpecies.length,
+ new Set(classesWithSpecies.map(constructor =>
+ Object.getOwnPropertyDescriptor(
+ constructor, Symbol.species).get)
+ ).size);
+
+for (let constructor of classesWithoutSpecies)
+ assertEquals(undefined, constructor[Symbol.species]);
diff --git a/test/mjsunit/es6/string-match.js b/test/mjsunit/es6/string-match.js
new file mode 100644
index 0000000..2c7affe
--- /dev/null
+++ b/test/mjsunit/es6/string-match.js
@@ -0,0 +1,18 @@
+// 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.
+
+var pattern = {};
+pattern[Symbol.match] = function(string) {
+ return string.length;
+};
+// Check object coercible fails.
+assertThrows(() => String.prototype.match.call(null, pattern),
+ TypeError);
+// Override is called.
+assertEquals(5, "abcde".match(pattern));
+// Non-callable override.
+pattern[Symbol.match] = "dumdidum";
+assertThrows(() => "abcde".match(pattern), TypeError);
+
+assertEquals("[Symbol.match]", RegExp.prototype[Symbol.match].name);
diff --git a/test/mjsunit/es6/string-replace.js b/test/mjsunit/es6/string-replace.js
new file mode 100644
index 0000000..0beb57a
--- /dev/null
+++ b/test/mjsunit/es6/string-replace.js
@@ -0,0 +1,17 @@
+// 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.
+
+var pattern = {
+ [Symbol.replace]: (string, newValue) => string + newValue
+};
+// Check object coercible fails.
+assertThrows(() => String.prototype.replace.call(null, pattern, "x"),
+ TypeError);
+// Override is called.
+assertEquals("abcdex", "abcde".replace(pattern, "x"));
+// Non-callable override.
+pattern[Symbol.replace] = "dumdidum";
+assertThrows(() => "abcde".replace(pattern, "x"), TypeError);
+
+assertEquals("[Symbol.replace]", RegExp.prototype[Symbol.replace].name);
diff --git a/test/mjsunit/es6/string-search.js b/test/mjsunit/es6/string-search.js
index dc02982..cbdf33d 100644
--- a/test/mjsunit/es6/string-search.js
+++ b/test/mjsunit/es6/string-search.js
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --harmony-regexp-subclass
-
var pattern = {};
pattern[Symbol.search] = function(string) {
return string.length;
diff --git a/test/mjsunit/es6/string-split.js b/test/mjsunit/es6/string-split.js
new file mode 100644
index 0000000..8ca655c
--- /dev/null
+++ b/test/mjsunit/es6/string-split.js
@@ -0,0 +1,19 @@
+// 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.
+
+var pattern = {};
+var limit = { value: 3 };
+pattern[Symbol.split] = function(string, limit) {
+ return string.length * limit.value;
+};
+// Check object coercible fails.
+assertThrows(() => String.prototype.split.call(null, pattern, limit),
+ TypeError);
+// Override is called.
+assertEquals(15, "abcde".split(pattern, limit));
+// Non-callable override.
+pattern[Symbol.split] = "dumdidum";
+assertThrows(() => "abcde".split(pattern, limit), TypeError);
+
+assertEquals("[Symbol.split]", RegExp.prototype[Symbol.split].name);
diff --git a/test/mjsunit/es6/symbols.js b/test/mjsunit/es6/symbols.js
index 9bac41f..a21afb3 100644
--- a/test/mjsunit/es6/symbols.js
+++ b/test/mjsunit/es6/symbols.js
@@ -555,7 +555,9 @@
function TestStringify(expected, input) {
assertEquals(expected, JSON.stringify(input));
- assertEquals(expected, JSON.stringify(input, null, 0));
+ assertEquals(expected, JSON.stringify(input, (key, value) => value));
+ assertEquals(JSON.stringify(input, null, "="),
+ JSON.stringify(input, (key, value) => value, "="));
}
TestStringify(undefined, Symbol("a"));
diff --git a/test/mjsunit/es6/tail-call-megatest.js b/test/mjsunit/es6/tail-call-megatest.js
index 1de8ec6..3d2ecb8 100644
--- a/test/mjsunit/es6/tail-call-megatest.js
+++ b/test/mjsunit/es6/tail-call-megatest.js
@@ -10,6 +10,7 @@
return error.message + "\n at " + stack.join("\n at ");
}
+var verbose = typeof(arguments) !== "undefined" && arguments.indexOf("-v") >= 0;
function checkStackTrace(expected) {
var e = new Error();
@@ -340,32 +341,32 @@
return source;
}
- var f_args_variants = ["", "1", "1, 2"];
- var g_args_variants = ["", "10", "10, 20"];
+ var f_args_variants = [/*"", "1",*/ "1, 2"];
+ var g_args_variants = [/*"", "10",*/ "10, 20"];
var f_inlinable_variants = [true, false];
var g_inlinable_variants = [true, false];
// This is to avoid bailing out because of referencing new.target.
- var check_new_target_variants = [true, false];
+ var check_new_target_variants = [/*true,*/ false];
var deopt_mode_variants = ["none", "f", "g", "test"];
var f_variants = [
f_cfg_sloppy,
f_cfg_strict,
f_cfg_bound,
f_cfg_proxy,
- f_cfg_possibly_eval,
+// f_cfg_possibly_eval,
];
var g_variants = [
g_cfg_normal,
- g_cfg_reflect_apply,
+// g_cfg_reflect_apply,
g_cfg_function_apply,
- g_cfg_function_apply_arguments_object,
+// g_cfg_function_apply_arguments_object,
g_cfg_function_call,
];
var test_warmup_counts = [0, 1, 2];
var iter = 0;
var tests_executed = 0;
- if (shard !== undefined) {
+ if (verbose && shard !== undefined) {
print("Running shard #" + shard);
}
f_variants.forEach((f_cfg) => {
@@ -378,7 +379,9 @@
g_inlinable_variants.forEach((g_inlinable) => {
test_warmup_counts.forEach((test_warmup_count) => {
if (shard !== undefined && (iter++) % SHARDS_COUNT != shard) {
- print("skipping...");
+ if (verbose) {
+ print("skipping...");
+ }
return;
}
tests_executed++;
@@ -396,8 +399,10 @@
deopt_mode,
};
var source = test_template(cfg);
- print("====================");
- print(source);
+ if (verbose) {
+ // print("====================");
+ // print(source);
+ }
eval(source);
});
});
@@ -408,7 +413,9 @@
});
});
});
- print("Number of tests executed: " + tests_executed);
+ if (verbose) {
+ print("Number of tests executed: " + tests_executed);
+ }
}
// Uncomment to run all the tests at once or use shard runners.
diff --git a/test/mjsunit/es6/typedarray-set-length-internal.js b/test/mjsunit/es6/typedarray-set-length-internal.js
new file mode 100644
index 0000000..22b8f67
--- /dev/null
+++ b/test/mjsunit/es6/typedarray-set-length-internal.js
@@ -0,0 +1,35 @@
+// Copyright 2016 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.
+
+var typedArrayConstructors = [
+ Uint8Array,
+ Int8Array,
+ Uint16Array,
+ Int16Array,
+ Uint32Array,
+ Int32Array,
+ Uint8ClampedArray,
+ Float32Array,
+ Float64Array
+];
+
+var descriptor = { get: function() { throw new Error("accessed length"); } };
+
+for (var constructor of typedArrayConstructors) {
+ var differentConstructor =
+ constructor === Uint8Array ? Int8Array : Uint8Array;
+ var target = new constructor(16);
+ Object.defineProperty(target, "length", descriptor);
+
+ var sameBuffer = new differentConstructor(target.buffer, 0, 2);
+ Object.defineProperty(sameBuffer, "length", descriptor);
+ target.set(sameBuffer);
+
+ var differentBuffer = new differentConstructor(16);
+ Object.defineProperty(differentBuffer, "length", descriptor);
+ target.set(differentBuffer);
+
+ var array = [0, 1, 2];
+ target.set(array);
+}
diff --git a/test/mjsunit/es6/typedarray-species.js b/test/mjsunit/es6/typedarray-species.js
new file mode 100644
index 0000000..020d65c
--- /dev/null
+++ b/test/mjsunit/es6/typedarray-species.js
@@ -0,0 +1,84 @@
+// 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.
+
+// Subclasses of %TypedArray% construct themselves under map, etc
+
+var typedArrayConstructors = [
+ Uint8Array,
+ Int8Array,
+ Uint16Array,
+ Int16Array,
+ Uint32Array,
+ Int32Array,
+ Uint8ClampedArray,
+ Float32Array,
+ Float64Array
+];
+
+for (let constructor of typedArrayConstructors) {
+ class MyTypedArray extends constructor { }
+ assertEquals(MyTypedArray, new MyTypedArray().map(()=>0).constructor);
+ assertEquals(MyTypedArray, new MyTypedArray().filter(()=>{}).constructor);
+ assertEquals(MyTypedArray, new MyTypedArray().slice().constructor);
+}
+
+// Subclasses can override @@species to return the another class
+
+for (let constructor of typedArrayConstructors) {
+ class MyTypedArray extends constructor { }
+ class MyOtherTypedArray extends constructor {
+ static get [Symbol.species]() { return MyTypedArray; }
+ }
+ assertEquals(MyTypedArray, new MyOtherTypedArray().map(()=>0).constructor);
+ assertEquals(MyTypedArray, new MyOtherTypedArray().filter(()=>{}).constructor);
+ assertEquals(MyTypedArray, new MyOtherTypedArray().slice().constructor);
+}
+
+// TypedArray too-short and non-TypedArray error checking
+
+for (let constructor of typedArrayConstructors) {
+ class MyShortTypedArray extends constructor {
+ constructor(length) { super(length - 1); }
+ }
+ assertThrows(() => new MyShortTypedArray(5).map(()=>0), TypeError);
+ assertThrows(() => new MyShortTypedArray(5).filter(()=>true), TypeError);
+ assertThrows(() => new MyShortTypedArray(5).slice(), TypeError);
+
+ class MyNonTypedArray extends constructor {
+ static get [Symbol.species]() { return Array; }
+ }
+ assertThrows(() => new MyNonTypedArray().map(()=>0), TypeError);
+ assertThrows(() => new MyNonTypedArray().filter(()=>{}), TypeError);
+ assertThrows(() => new MyNonTypedArray().slice(), TypeError);
+}
+
+// Defaults when constructor or @@species is missing or non-constructor
+
+for (let constructor of typedArrayConstructors) {
+ class MyDefaultTypedArray extends constructor {
+ static get [Symbol.species]() { return undefined; }
+ }
+ assertEquals(constructor, new MyDefaultTypedArray().map(()=>0).constructor);
+
+ class MyOtherDefaultTypedArray extends constructor { }
+ assertEquals(MyOtherDefaultTypedArray, new MyOtherDefaultTypedArray().map(()=>0).constructor);
+ MyOtherDefaultTypedArray.prototype.constructor = undefined;
+ assertEquals(constructor, new MyOtherDefaultTypedArray().map(()=>0).constructor);
+}
+
+// Exceptions propagated when getting constructor @@species throws
+
+class SpeciesError extends Error { }
+class ConstructorError extends Error { }
+
+for (let constructor of typedArrayConstructors) {
+ class MyThrowingArray extends constructor {
+ static get [Symbol.species]() { throw new SpeciesError; }
+ }
+ assertThrows(() => new MyThrowingArray().map(()=>{}), SpeciesError);
+ Object.defineProperty(MyThrowingArray.prototype, 'constructor', {
+ get() { throw new ConstructorError; }
+ });
+ assertThrows(() => new MyThrowingArray().map(()=>{}), ConstructorError);
+}
diff --git a/test/mjsunit/es6/unicode-character-ranges.js b/test/mjsunit/es6/unicode-character-ranges.js
new file mode 100644
index 0000000..f39004f
--- /dev/null
+++ b/test/mjsunit/es6/unicode-character-ranges.js
@@ -0,0 +1,158 @@
+// Copyright 2016 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-regexp-lookbehind
+
+function execl(expectation, regexp, subject) {
+ if (regexp instanceof String) regexp = new RegExp(regexp, "u");
+ assertEquals(expectation, regexp.exec(subject));
+}
+
+function execs(expectation, regexp_source, subject) {
+ execl(expectation, new RegExp(regexp_source, "u"), subject);
+}
+
+// Character ranges.
+execl(["A"], /[A-D]/u, "A");
+execs(["A"], "[A-D]", "A");
+execl(["ABCD"], /[A-D]+/u, "ZABCDEF");
+execs(["ABCD"], "[A-D]+", "ZABCDEF");
+
+execl(["\u{12345}"], /[\u1234-\u{12345}]/u, "\u{12345}");
+execs(["\u{12345}"], "[\u1234-\u{12345}]", "\u{12345}");
+execl(null, /[^\u1234-\u{12345}]/u, "\u{12345}");
+execs(null, "[^\u1234-\u{12345}]", "\u{12345}");
+
+execl(["\u{1234}"], /[\u1234-\u{12345}]/u, "\u{1234}");
+execs(["\u{1234}"], "[\u1234-\u{12345}]", "\u{1234}");
+execl(null, /[^\u1234-\u{12345}]/u, "\u{1234}");
+execs(null, "[^\u1234-\u{12345}]", "\u{1234}");
+
+execl(null, /[\u1234-\u{12345}]/u, "\u{1233}");
+execs(null, "[\u1234-\u{12345}]", "\u{1233}");
+execl(["\u{1233}"], /[^\u1234-\u{12345}]/u, "\u{1233}");
+execs(["\u{1233}"], "[^\u1234-\u{12345}]", "\u{1233}");
+
+execl(["\u{12346}"], /[^\u1234-\u{12345}]/u, "\u{12346}");
+execs(["\u{12346}"], "[^\u1234-\u{12345}]", "\u{12346}");
+execl(null, /[\u1234-\u{12345}]/u, "\u{12346}");
+execs(null, "[\u1234-\u{12345}]", "\u{12346}");
+
+execl(["\u{12342}"], /[\u{12340}-\u{12345}]/u, "\u{12342}");
+execs(["\u{12342}"], "[\u{12340}-\u{12345}]", "\u{12342}");
+execl(["\u{12342}"], /[\ud808\udf40-\ud808\udf45]/u, "\u{12342}");
+execs(["\u{12342}"], "[\ud808\udf40-\ud808\udf45]", "\u{12342}");
+execl(null, /[^\u{12340}-\u{12345}]/u, "\u{12342}");
+execs(null, "[^\u{12340}-\u{12345}]", "\u{12342}");
+execl(null, /[^\ud808\udf40-\ud808\udf45]/u, "\u{12342}");
+execs(null, "[^\ud808\udf40-\ud808\udf45]", "\u{12342}");
+
+execl(["\u{ffff}"], /[\u{ff80}-\u{12345}]/u, "\u{ffff}");
+execs(["\u{ffff}"], "[\u{ff80}-\u{12345}]", "\u{ffff}");
+execl(["\u{ffff}"], /[\u{ff80}-\ud808\udf45]/u, "\u{ffff}");
+execs(["\u{ffff}"], "[\u{ff80}-\ud808\udf45]", "\u{ffff}");
+execl(null, /[^\u{ff80}-\u{12345}]/u, "\u{ffff}");
+execs(null, "[^\u{ff80}-\u{12345}]", "\u{ffff}");
+execl(null, /[^\u{ff80}-\ud808\udf45]/u, "\u{ffff}");
+execs(null, "[^\u{ff80}-\ud808\udf45]", "\u{ffff}");
+
+// Lone surrogate
+execl(["\ud800"], /[^\u{ff80}-\u{12345}]/u, "\uff99\u{d800}A");
+execs(["\udc00"], "[^\u{ff80}-\u{12345}]", "\uff99\u{dc00}A");
+execl(["\udc01"], /[\u0100-\u{10ffff}]/u, "A\udc01");
+execl(["\udc03"], /[\udc01-\udc03]/u, "\ud801\udc02\udc03");
+execl(["\ud801"], /[\ud801-\ud803]/u, "\ud802\udc01\ud801");
+
+// Paired sorrogate.
+execl(null, /[^\u{ff80}-\u{12345}]/u, "\u{d800}\u{dc00}");
+execs(null, "[^\u{ff80}-\u{12345}]", "\u{d800}\u{dc00}");
+execl(["\ud800\udc00"], /[\u{ff80}-\u{12345}]/u, "\u{d800}\u{dc00}");
+execs(["\ud800\udc00"], "[\u{ff80}-\u{12345}]", "\u{d800}\u{dc00}");
+execl(["foo\u{10e6d}bar"], /foo\ud803\ude6dbar/u, "foo\u{10e6d}bar");
+
+// Lone surrogates
+execl(["\ud801\ud801"], /\ud801+/u, "\ud801\udc01\ud801\ud801");
+execl(["\udc01\udc01"], /\udc01+/u, "\ud801\ud801\udc01\udc01\udc01");
+
+execl(["\udc02\udc03A"], /\W\WA/u, "\ud801\udc01A\udc02\udc03A");
+execl(["\ud801\ud802"], /\ud801./u, "\ud801\udc01\ud801\ud802");
+execl(["\udc02\udc03A"], /[\ud800-\udfff][\ud800-\udfff]A/u,
+ "\ud801\udc01A\udc02\udc03A");
+
+// Character classes
+execl(null, /\w/u, "\ud801\udc01");
+execl(["\ud801"], /[^\w]/, "\ud801\udc01");
+execl(["\ud801\udc01"], /[^\w]/u, "\ud801\udc01");
+execl(["\ud801"], /\W/, "\ud801\udc01");
+execl(["\ud801\udc01"], /\W/u, "\ud801\udc01");
+
+execl(["\ud800X"], /.X/u, "\ud800XaX");
+execl(["aX"], /.(?<!\ud800)X/u, "\ud800XaX");
+execl(["aX"], /.(?<![\ud800-\ud900])X/u, "\ud800XaX");
+
+execl(null, /[]/u, "\u1234");
+execl(["0abc"], /[^]abc/u, "0abc");
+execl(["\u1234abc"], /[^]abc/u, "\u1234abc");
+execl(["\u{12345}abc"], /[^]abc/u, "\u{12345}abc");
+
+execl(null, /[\u{0}-\u{1F444}]/u, "\ud83d\udfff");
+
+// Backward matches of lone surrogates.
+execl(["B", "\ud803A"], /(?<=([\ud800-\ud900]A))B/u,
+ "\ud801\udc00AB\udc00AB\ud802\ud803AB");
+execl(["B", "\udc00A"], /(?<=([\ud800-\u{10300}]A))B/u,
+ "\ud801\udc00AB\udc00AB\ud802\ud803AB");
+execl(["B", "\udc11A"], /(?<=([\udc00-\udd00]A))B/u,
+ "\ud801\udc00AB\udc11AB\ud802\ud803AB");
+execl(["X", "\ud800C"], /(?<=(\ud800\w))X/u,
+ "\ud800\udc00AX\udc11BX\ud800\ud800CX");
+execl(["C", "\ud800\ud800"], /(?<=(\ud800.))\w/u,
+ "\ud800\udc00AX\udc11BX\ud800\ud800CX");
+execl(["X", "\udc01C"], /(?<=(\udc01\w))X/u,
+ "\ud800\udc01AX\udc11BX\udc01\udc01CX");
+execl(["C", "\udc01\udc01"], /(?<=(\udc01.))./u,
+ "\ud800\udc01AX\udc11BX\udc01\udc01CX");
+
+var L = "\ud800";
+var T = "\udc00";
+var X = "X";
+
+// Test string contains only match.
+function testw(expect, src, subject) {
+ var re = new RegExp("^" + src + "$", "u");
+ assertEquals(expect, re.test(subject));
+}
+
+// Test string starts with match.
+function tests(expect, src, subject) {
+ var re = new RegExp("^" + src, "u");
+ assertEquals(expect, re.test(subject));
+}
+
+testw(true, X, X);
+testw(true, L, L);
+testw(true, T, T);
+testw(true, L + T, L + T);
+testw(true, T + L, T + L);
+testw(false, T, L + T);
+testw(false, L, L + T);
+testw(true, ".(?<=" + L + ")", L);
+testw(true, ".(?<=" + T + ")", T);
+testw(true, ".(?<=" + L + T + ")", L + T);
+testw(true, ".(?<=" + L + T + ")", L + T);
+tests(true, ".(?<=" + T + ")", T + L);
+tests(false, ".(?<=" + L + ")", L + T);
+tests(false, ".(?<=" + T + ")", L + T);
+tests(true, "..(?<=" + T + ")", T + T + L);
+tests(true, "..(?<=" + T + ")", X + T + L);
+tests(true, "...(?<=" + L + ")", X + T + L);
+tests(false, "...(?<=" + T + ")", X + L + T)
+tests(true, "..(?<=" + L + T + ")", X + L + T)
+tests(true, "..(?<=" + L + T + "(?<=" + L + T + "))", X + L + T);
+tests(false, "..(?<=" + L + "(" + T + "))", X + L + T);
+tests(false, ".*" + L, X + L + T);
+tests(true, ".*" + L, X + L + L + T);
+tests(false, ".*" + L, X + L + T + L + T);
+tests(false, ".*" + T, X + L + T + L + T);
+tests(true, ".*" + T, X + L + T + T + L + T);
diff --git a/test/mjsunit/es6/unicode-escapes-in-regexps.js b/test/mjsunit/es6/unicode-escapes-in-regexps.js
new file mode 100644
index 0000000..2d2d118
--- /dev/null
+++ b/test/mjsunit/es6/unicode-escapes-in-regexps.js
@@ -0,0 +1,285 @@
+// Copyright 2014 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.
+
+// ES6 extends the \uxxxx escape and also allows \u{xxxxx}.
+
+function testRegexpHelper(r) {
+ assertTrue(r.test("foo"));
+ assertTrue(r.test("boo"));
+ assertFalse(r.test("moo"));
+}
+
+
+(function TestUnicodeEscapes() {
+ testRegexpHelper(/(\u0066|\u0062)oo/);
+ testRegexpHelper(/(\u0066|\u0062)oo/u);
+ testRegexpHelper(/(\u{0066}|\u{0062})oo/u);
+ testRegexpHelper(/(\u{66}|\u{000062})oo/u);
+
+ // Note that we need \\ inside a string, otherwise it's interpreted as a
+ // unicode escape inside a string.
+ testRegexpHelper(new RegExp("(\\u0066|\\u0062)oo"));
+ testRegexpHelper(new RegExp("(\\u0066|\\u0062)oo", "u"));
+ testRegexpHelper(new RegExp("(\\u{0066}|\\u{0062})oo", "u"));
+ testRegexpHelper(new RegExp("(\\u{66}|\\u{000062})oo", "u"));
+
+ // Though, unicode escapes via strings should work too.
+ testRegexpHelper(new RegExp("(\u0066|\u0062)oo"));
+ testRegexpHelper(new RegExp("(\u0066|\u0062)oo", "u"));
+ testRegexpHelper(new RegExp("(\u{0066}|\u{0062})oo", "u"));
+ testRegexpHelper(new RegExp("(\u{66}|\u{000062})oo", "u"));
+})();
+
+
+(function TestUnicodeEscapesInCharacterClasses() {
+ testRegexpHelper(/[\u0062-\u0066]oo/);
+ testRegexpHelper(/[\u0062-\u0066]oo/u);
+ testRegexpHelper(/[\u{0062}-\u{0066}]oo/u);
+ testRegexpHelper(/[\u{62}-\u{00000066}]oo/u);
+
+ // Note that we need \\ inside a string, otherwise it's interpreted as a
+ // unicode escape inside a string.
+ testRegexpHelper(new RegExp("[\\u0062-\\u0066]oo"));
+ testRegexpHelper(new RegExp("[\\u0062-\\u0066]oo", "u"));
+ testRegexpHelper(new RegExp("[\\u{0062}-\\u{0066}]oo", "u"));
+ testRegexpHelper(new RegExp("[\\u{62}-\\u{00000066}]oo", "u"));
+
+ // Though, unicode escapes via strings should work too.
+ testRegexpHelper(new RegExp("[\u0062-\u0066]oo"));
+ testRegexpHelper(new RegExp("[\u0062-\u0066]oo", "u"));
+ testRegexpHelper(new RegExp("[\u{0062}-\u{0066}]oo", "u"));
+ testRegexpHelper(new RegExp("[\u{62}-\u{00000066}]oo", "u"));
+})();
+
+
+(function TestBraceEscapesWithoutUnicodeFlag() {
+ // \u followed by illegal escape will be parsed as u. {x} will be the
+ // character count.
+ function helper1(r) {
+ assertFalse(r.test("fbar"));
+ assertFalse(r.test("fubar"));
+ assertTrue(r.test("fuubar"));
+ assertFalse(r.test("fuuubar"));
+ }
+ helper1(/f\u{2}bar/);
+ helper1(new RegExp("f\\u{2}bar"));
+
+ function helper2(r) {
+ assertFalse(r.test("fbar"));
+ assertTrue(r.test("fubar"));
+ assertTrue(r.test("fuubar"));
+ assertFalse(r.test("fuuubar"));
+ }
+
+ helper2(/f\u{1,2}bar/);
+ helper2(new RegExp("f\\u{1,2}bar"));
+
+ function helper3(r) {
+ assertTrue(r.test("u"));
+ assertTrue(r.test("{"));
+ assertTrue(r.test("2"));
+ assertTrue(r.test("}"));
+ assertFalse(r.test("q"));
+ assertFalse(r.test("("));
+ assertFalse(r.test(")"));
+ }
+ helper3(/[\u{2}]/);
+ helper3(new RegExp("[\\u{2}]"));
+})();
+
+
+(function TestInvalidEscapes() {
+ // Without the u flag, invalid unicode escapes and other invalid escapes are
+ // treated as identity escapes.
+ function helper1(r) {
+ assertTrue(r.test("firstuxz89second"));
+ }
+ helper1(/first\u\x\z\8\9second/);
+ helper1(new RegExp("first\\u\\x\\z\\8\\9second"));
+
+ function helper2(r) {
+ assertTrue(r.test("u"));
+ assertTrue(r.test("x"));
+ assertTrue(r.test("z"));
+ assertTrue(r.test("8"));
+ assertTrue(r.test("9"));
+ assertFalse(r.test("q"));
+ assertFalse(r.test("7"));
+ }
+ helper2(/[\u\x\z\8\9]/);
+ helper2(new RegExp("[\\u\\x\\z\\8\\9]"));
+
+ // However, with the u flag, these are treated as invalid escapes.
+ assertThrows("/\\u/u", SyntaxError);
+ assertThrows("/\\u12/u", SyntaxError);
+ assertThrows("/\\ufoo/u", SyntaxError);
+ assertThrows("/\\x/u", SyntaxError);
+ assertThrows("/\\xfoo/u", SyntaxError);
+ assertThrows("/\\z/u", SyntaxError);
+ assertThrows("/\\8/u", SyntaxError);
+ assertThrows("/\\9/u", SyntaxError);
+
+ assertThrows("new RegExp('\\\\u', 'u')", SyntaxError);
+ assertThrows("new RegExp('\\\\u12', 'u')", SyntaxError);
+ assertThrows("new RegExp('\\\\ufoo', 'u')", SyntaxError);
+ assertThrows("new RegExp('\\\\x', 'u')", SyntaxError);
+ assertThrows("new RegExp('\\\\xfoo', 'u')", SyntaxError);
+ assertThrows("new RegExp('\\\\z', 'u')", SyntaxError);
+ assertThrows("new RegExp('\\\\8', 'u')", SyntaxError);
+ assertThrows("new RegExp('\\\\9', 'u')", SyntaxError);
+})();
+
+
+(function TestTooBigHexEscape() {
+ // The hex number inside \u{} has a maximum value.
+ /\u{10ffff}/u
+ new RegExp("\\u{10ffff}", "u")
+ assertThrows("/\\u{110000}/u", SyntaxError);
+ assertThrows("new RegExp('\\\\u{110000}', 'u')", SyntaxError);
+
+ // Without the u flag, they're of course fine ({x} is the count).
+ /\u{110000}/
+ new RegExp("\\u{110000}")
+})();
+
+
+(function TestSyntaxEscapes() {
+ // Syntax escapes work the same with or without the u flag.
+ function helper(r) {
+ assertTrue(r.test("foo[bar"));
+ assertFalse(r.test("foo]bar"));
+ }
+ helper(/foo\[bar/);
+ helper(new RegExp("foo\\[bar"));
+ helper(/foo\[bar/u);
+ helper(new RegExp("foo\\[bar", "u"));
+})();
+
+
+(function TestUnicodeSurrogates() {
+ // U+10E6D corresponds to the surrogate pair [U+D803, U+DE6D].
+ function helper(r) {
+ assertTrue(r.test("foo\u{10e6d}bar"));
+ }
+ helper(/foo\ud803\ude6dbar/u);
+ helper(new RegExp("foo\\ud803\\ude6dbar", "u"));
+})();
+
+
+(function AllFlags() {
+ // Test that we can pass all possible regexp flags and they work properly.
+ function helper1(r) {
+ assertTrue(r.global);
+ assertTrue(r.ignoreCase);
+ assertTrue(r.multiline);
+ assertTrue(r.sticky);
+ assertTrue(r.unicode);
+ }
+
+ helper1(/foo/gimyu);
+ helper1(new RegExp("foo", "gimyu"));
+
+ function helper2(r) {
+ assertFalse(r.global);
+ assertFalse(r.ignoreCase);
+ assertFalse(r.multiline);
+ assertFalse(r.sticky);
+ assertFalse(r.unicode);
+ }
+
+ helper2(/foo/);
+ helper2(new RegExp("foo"));
+})();
+
+
+(function DuplicatedFlags() {
+ // Test that duplicating the u flag is not allowed.
+ assertThrows("/foo/ugu");
+ assertThrows("new RegExp('foo', 'ugu')");
+})();
+
+
+(function ToString() {
+ // Test that the u flag is included in the string representation of regexps.
+ function helper(r) {
+ assertEquals(r.toString(), "/foo/u");
+ }
+ helper(/foo/u);
+ helper(new RegExp("foo", "u"));
+})();
+
+// Non-BMP patterns.
+// Single character atom.
+assertTrue(new RegExp("\u{12345}", "u").test("\u{12345}"));
+assertTrue(/\u{12345}/u.test("\u{12345}"));
+assertTrue(new RegExp("\u{12345}", "u").test("\ud808\udf45"));
+assertTrue(/\u{12345}/u.test("\ud808\udf45"));
+assertFalse(new RegExp("\u{12345}", "u").test("\udf45"));
+assertFalse(/\u{12345}/u.test("\udf45"));
+
+// Multi-character atom.
+assertTrue(new RegExp("\u{12345}\u{23456}", "u").test("a\u{12345}\u{23456}b"));
+assertTrue(/\u{12345}\u{23456}/u.test("b\u{12345}\u{23456}c"));
+assertFalse(new RegExp("\u{12345}\u{23456}", "u").test("a\udf45\u{23456}b"));
+assertFalse(/\u{12345}\u{23456}/u.test("b\udf45\u{23456}c"));
+
+// Disjunction.
+assertTrue(new RegExp("\u{12345}(?:\u{23456})", "u").test(
+ "a\u{12345}\u{23456}b"));
+assertTrue(/\u{12345}(?:\u{23456})/u.test("b\u{12345}\u{23456}c"));
+assertFalse(new RegExp("\u{12345}(?:\u{23456})", "u").test(
+ "a\udf45\u{23456}b"));
+assertFalse(/\u{12345}(?:\u{23456})/u.test("b\udf45\u{23456}c"));
+
+// Alternative.
+assertTrue(new RegExp("\u{12345}|\u{23456}", "u").test("a\u{12345}b"));
+assertTrue(/\u{12345}|\u{23456}/u.test("b\u{23456}c"));
+assertFalse(new RegExp("\u{12345}|\u{23456}", "u").test("a\udf45\ud84db"));
+assertFalse(/\u{12345}|\u{23456}/u.test("b\udf45\ud808c"));
+
+// Capture.
+assertTrue(new RegExp("(\u{12345}|\u{23456}).\\1", "u").test(
+ "\u{12345}b\u{12345}"));
+assertTrue(/(\u{12345}|\u{23456}).\1/u.test("\u{12345}b\u{12345}"));
+assertFalse(new RegExp("(\u{12345}|\u{23456}).\\1", "u").test(
+ "\u{12345}b\u{23456}"));
+assertFalse(/(\u{12345}|\u{23456}).\1/u.test("\u{12345}b\u{23456}"));
+
+// Quantifier.
+assertTrue(new RegExp("\u{12345}{3}", "u").test("\u{12345}\u{12345}\u{12345}"));
+assertTrue(/\u{12345}{3}/u.test("\u{12345}\u{12345}\u{12345}"));
+assertTrue(new RegExp("\u{12345}{3}").test("\u{12345}\udf45\udf45"));
+assertFalse(/\ud808\udf45{3}/u.test("\u{12345}\udf45\udf45"));
+assertTrue(/\ud808\udf45{3}/u.test("\u{12345}\u{12345}\u{12345}"));
+assertFalse(new RegExp("\u{12345}{3}", "u").test("\u{12345}\udf45\udf45"));
+assertFalse(/\u{12345}{3}/u.test("\u{12345}\udf45\udf45"));
+
+// Literal surrogates.
+assertEquals(["\u{10000}\u{10000}"],
+ new RegExp("\ud800\udc00+", "u").exec("\u{10000}\u{10000}"));
+assertEquals(["\u{10000}\u{10000}"],
+ new RegExp("\\ud800\\udc00+", "u").exec("\u{10000}\u{10000}"));
+
+assertEquals(["\u{10003}\u{50001}"],
+ new RegExp("[\\ud800\\udc03-\\ud900\\udc01\]+", "u").exec(
+ "\u{10003}\u{50001}"));
+assertEquals(["\u{10003}\u{50001}"],
+ new RegExp("[\ud800\udc03-\u{50001}\]+", "u").exec(
+ "\u{10003}\u{50001}"));
+
+// Unicode escape sequences to represent a non-BMP character cannot have
+// mixed notation, and must follow the rules for RegExpUnicodeEscapeSequence.
+assertThrows(() => new RegExp("[\\ud800\udc03-\ud900\\udc01\]+", "u"));
+assertThrows(() => new RegExp("[\\ud800\udc03-\ud900\\udc01\]+", "u"));
+assertNull(new RegExp("\\ud800\udc00+", "u").exec("\u{10000}\u{10000}"));
+assertNull(new RegExp("\ud800\\udc00+", "u").exec("\u{10000}\u{10000}"));
+
+assertNull(new RegExp("[\\ud800\udc00]", "u").exec("\u{10000}"));
+assertNull(new RegExp("[\\{ud800}\udc00]", "u").exec("\u{10000}"));
+assertNull(new RegExp("[\ud800\\udc00]", "u").exec("\u{10000}"));
+assertNull(new RegExp("[\ud800\\{udc00}]", "u").exec("\u{10000}"));
+
+assertNull(/\u{d800}\u{dc00}+/u.exec("\ud800\udc00\udc00"));
+assertNull(/\ud800\u{dc00}+/u.exec("\ud800\udc00\udc00"));
+assertNull(/\u{d800}\udc00+/u.exec("\ud800\udc00\udc00"));
diff --git a/test/mjsunit/es6/unicode-regexp-backrefs.js b/test/mjsunit/es6/unicode-regexp-backrefs.js
new file mode 100644
index 0000000..56b9c5e
--- /dev/null
+++ b/test/mjsunit/es6/unicode-regexp-backrefs.js
@@ -0,0 +1,53 @@
+// Copyright 2016 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-regexp-lookbehind
+
+// Back reference does not end in the middle of a surrogate pair.
+function replace(string) {
+ return string.replace(/L/g, "\ud800")
+ .replace(/l/g, "\ud801")
+ .replace(/T/g, "\udc00")
+ .replace(/\./g, "[^]");
+}
+
+function test(expectation, regexp_source, subject) {
+ if (expectation !== null) expectation = expectation.map(replace);
+ subject = replace(subject);
+ regexp_source = replace(regexp_source);
+ assertEquals(expectation, new RegExp(regexp_source, "u").exec(subject));
+}
+
+// Back reference does not end in the middle of a surrogate pair.
+test(null, "(L)\\1", "LLT");
+test(["LLTLl", "L", "l"], "(L).*\\1(.)", "LLTLl");
+test(null, "(aL).*\\1", "aLaLT");
+test(["aLaLTaLl", "aL", "l"], "(aL).*\\1(.)", "aLaLTaLl");
+
+var s = "TabcLxLTabcLxTabcLTyTabcLz";
+test([s, "TabcL", "z"], "([^x]+).*\\1(.)", s);
+
+// Back reference does not start in the middle of a surrogate pair.
+test(["TLTabTc", "T", "c"], "(T).*\\1(.)", "TLTabTc");
+
+// Lookbehinds.
+test(null, "(?<=\\1(T)x)", "LTTx");
+test(["", "b", "T"], "(?<=(.)\\2.*(T)x)", "bTaLTTx");
+test(null, "(?<=\\1.*(L)x)", "LTLx");
+test(["", "b", "L"], "(?<=(.)\\2.*(L)x)", "bLaLTLx");
+
+
+test(null, "([^x]+)x*\\1", "LxLT");
+test(null, "([^x]+)x*\\1", "TxLT");
+test(null, "([^x]+)x*\\1", "LTxL");
+test(null, "([^x]+)x*\\1", "LTxT");
+test(null, "([^x]+)x*\\1", "xLxLT");
+test(null, "([^x]+)x*\\1", "xTxLT");
+test(null, "([^x]+)x*\\1", "xLTxL");
+test(null, "([^x]+)x*\\1", "xLTxT");
+test(null, "([^x]+)x*\\1", "xxxLxxLTxx");
+test(null, "([^x]+)x*\\1", "xxxTxxLTxx");
+test(null, "([^x]+)x*\\1", "xxxLTxxLxx");
+test(null, "([^x]+)x*\\1", "xxxLTxxTxx");
+test(["LTTxxLTT", "LTT"], "([^x]+)x*\\1", "xxxLTTxxLTTxx");
diff --git a/test/mjsunit/es6/unicode-regexp-ignore-case-noi18n.js b/test/mjsunit/es6/unicode-regexp-ignore-case-noi18n.js
new file mode 100644
index 0000000..a998942
--- /dev/null
+++ b/test/mjsunit/es6/unicode-regexp-ignore-case-noi18n.js
@@ -0,0 +1,57 @@
+// Copyright 2016 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.
+
+// Non-unicode use toUpperCase mappings.
+assertFalse(/[\u00e5]/i.test("\u212b"));
+assertFalse(/[\u212b]/i.test("\u00e5\u1234"));
+assertFalse(/[\u212b]/i.test("\u00e5"));
+
+assertTrue("\u212b".toLowerCase() == "\u00e5");
+assertTrue("\u00c5".toLowerCase() == "\u00e5");
+assertTrue("\u00e5".toUpperCase() == "\u00c5");
+
+// Unicode uses case folding mappings.
+assertFalse(/\u00e5/ui.test("\u212b"));
+assertTrue(/\u00e5/ui.test("\u00c5"));
+assertTrue(/\u00e5/ui.test("\u00e5"));
+assertFalse(/\u00e5/ui.test("\u212b"));
+assertTrue(/\u00c5/ui.test("\u00e5"));
+assertFalse(/\u00c5/ui.test("\u212b"));
+assertTrue(/\u00c5/ui.test("\u00c5"));
+assertFalse(/\u212b/ui.test("\u00c5"));
+assertFalse(/\u212b/ui.test("\u00e5"));
+assertTrue(/\u212b/ui.test("\u212b"));
+
+// Non-BMP.
+assertFalse(/\u{10400}/i.test("\u{10428}"));
+assertFalse(/\u{10400}/ui.test("\u{10428}"));
+assertFalse(/\ud801\udc00/ui.test("\u{10428}"));
+assertFalse(/[\u{10428}]/ui.test("\u{10400}"));
+assertFalse(/[\ud801\udc28]/ui.test("\u{10400}"));
+assertEquals(["\uff21\u{10400}"],
+ /[\uff40-\u{10428}]+/ui.exec("\uff21\u{10400}abc"));
+assertEquals(["abc"], /[^\uff40-\u{10428}]+/ui.exec("\uff21\u{10400}abc\uff23"));
+assertEquals(["\uff53\u24bb"],
+ /[\u24d5-\uff33]+/ui.exec("\uff54\uff53\u24bb\u24ba"));
+
+// Full mappings are ignored.
+assertFalse(/\u00df/ui.test("SS"));
+assertFalse(/\u1f8d/ui.test("\u1f05\u03b9"));
+
+// Simple mappings.
+assertFalse(/\u1f8d/ui.test("\u1f85"));
+
+// Common mappings.
+assertTrue(/\u1f6b/ui.test("\u1f63"));
+
+// Back references.
+assertNull(/(.)\1\1/ui.exec("\u00e5\u212b\u00c5"));
+assertNull(/(.)\1/ui.exec("\u{118aa}\u{118ca}"));
+
+
+// Non-Latin1 maps to Latin1.
+assertNull(/^\u017F/ui.exec("s"));
+assertNull(/^\u017F/ui.exec("s\u1234"));
+assertNull(/^a[\u017F]/ui.exec("as"));
+assertNull(/^a[\u017F]/ui.exec("as\u1234"));
diff --git a/test/mjsunit/es6/unicode-regexp-ignore-case.js b/test/mjsunit/es6/unicode-regexp-ignore-case.js
new file mode 100644
index 0000000..dd02ca9
--- /dev/null
+++ b/test/mjsunit/es6/unicode-regexp-ignore-case.js
@@ -0,0 +1,62 @@
+// Copyright 2016 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.
+
+// Non-unicode use toUpperCase mappings.
+assertFalse(/[\u00e5]/i.test("\u212b"));
+assertFalse(/[\u212b]/i.test("\u00e5\u1234"));
+assertFalse(/[\u212b]/i.test("\u00e5"));
+
+assertTrue("\u212b".toLowerCase() == "\u00e5");
+assertTrue("\u00c5".toLowerCase() == "\u00e5");
+assertTrue("\u00e5".toUpperCase() == "\u00c5");
+
+// Unicode uses case folding mappings.
+assertTrue(/\u00e5/ui.test("\u212b"));
+assertTrue(/\u00e5/ui.test("\u00c5"));
+assertTrue(/\u00e5/ui.test("\u00e5"));
+assertTrue(/\u00e5/ui.test("\u212b"));
+assertTrue(/\u00c5/ui.test("\u00e5"));
+assertTrue(/\u00c5/ui.test("\u212b"));
+assertTrue(/\u00c5/ui.test("\u00c5"));
+assertTrue(/\u212b/ui.test("\u00c5"));
+assertTrue(/\u212b/ui.test("\u00e5"));
+assertTrue(/\u212b/ui.test("\u212b"));
+
+// Non-BMP.
+assertFalse(/\u{10400}/i.test("\u{10428}"));
+assertTrue(/\u{10400}/ui.test("\u{10428}"));
+assertTrue(/\ud801\udc00/ui.test("\u{10428}"));
+assertTrue(/[\u{10428}]/ui.test("\u{10400}"));
+assertTrue(/[\ud801\udc28]/ui.test("\u{10400}"));
+assertEquals(["\uff21\u{10400}"],
+ /[\uff40-\u{10428}]+/ui.exec("\uff21\u{10400}abc"));
+assertEquals(["abc"], /[^\uff40-\u{10428}]+/ui.exec("\uff21\u{10400}abc\uff23"));
+assertEquals(["\uff53\u24bb"],
+ /[\u24d5-\uff33]+/ui.exec("\uff54\uff53\u24bb\u24ba"));
+
+// Full mappings are ignored.
+assertFalse(/\u00df/ui.test("SS"));
+assertFalse(/\u1f8d/ui.test("\u1f05\u03b9"));
+
+// Simple mappings work.
+assertTrue(/\u1f8d/ui.test("\u1f85"));
+
+// Common mappings work.
+assertTrue(/\u1f6b/ui.test("\u1f63"));
+
+// Back references.
+assertEquals(["\u00e5\u212b\u00c5", "\u00e5"],
+ /(.)\1\1/ui.exec("\u00e5\u212b\u00c5"));
+assertEquals(["\u{118aa}\u{118ca}", "\u{118aa}"],
+ /(.)\1/ui.exec("\u{118aa}\u{118ca}"));
+
+// Misc.
+assertTrue(/\u00e5\u00e5\u00e5/ui.test("\u212b\u00e5\u00c5"));
+assertTrue(/AB\u{10400}/ui.test("ab\u{10428}"));
+
+// Non-Latin1 maps to Latin1.
+assertEquals(["s"], /^\u017F/ui.exec("s"));
+assertEquals(["s"], /^\u017F/ui.exec("s\u1234"));
+assertEquals(["as"], /^a[\u017F]/ui.exec("as"));
+assertEquals(["as"], /^a[\u017F]/ui.exec("as\u1234"));
diff --git a/test/mjsunit/es6/unicode-regexp-last-index.js b/test/mjsunit/es6/unicode-regexp-last-index.js
new file mode 100644
index 0000000..67fbac7
--- /dev/null
+++ b/test/mjsunit/es6/unicode-regexp-last-index.js
@@ -0,0 +1,104 @@
+// Copyright 2016 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-regexp-lookbehind
+
+var r = /./ug;
+assertEquals(["\ud800\udc00"], r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(2, r.lastIndex);
+r.lastIndex = 1;
+assertEquals(["\ud800\udc00"], r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(2, r.lastIndex);
+assertEquals(["\ud801\udc01"], r.exec("\ud800\udc00\ud801\udc01"));
+r.lastIndex = 3;
+assertEquals(["\ud801\udc01"], r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(4, r.lastIndex);
+r.lastIndex = 4;
+assertNull(r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(0, r.lastIndex);
+r.lastIndex = 5;
+assertNull(r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(0, r.lastIndex);
+
+r.lastIndex = 3;
+assertEquals(["\ud802"], r.exec("\ud800\udc00\ud801\ud802"));
+r.lastIndex = 4;
+assertNull(r.exec("\ud800\udc00\ud801\ud802"));
+
+r = /./g;
+assertEquals(["\ud800"], r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(1, r.lastIndex);
+assertEquals(["\udc00"], r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(2, r.lastIndex);
+assertEquals(["\ud801"], r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(3, r.lastIndex);
+assertEquals(["\udc01"], r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(4, r.lastIndex);
+assertNull(r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(0, r.lastIndex);
+r.lastIndex = 1;
+assertEquals(["\udc00"], r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(2, r.lastIndex);
+
+// ------------------------
+
+r = /^./ug;
+assertEquals(["\ud800\udc00"], r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(2, r.lastIndex);
+r.lastIndex = 1;
+assertEquals(["\ud800\udc00"], r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(2, r.lastIndex);
+assertNull(r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(0, r.lastIndex);
+r.lastIndex = 3;
+assertNull(r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(0, r.lastIndex);
+r.lastIndex = 4;
+assertNull(r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(0, r.lastIndex);
+r.lastIndex = 5;
+assertNull(r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(0, r.lastIndex);
+
+r = /^./g;
+assertEquals(["\ud800"], r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(1, r.lastIndex);
+assertNull(r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(0, r.lastIndex);
+r.lastIndex = 3;
+assertNull(r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(0, r.lastIndex);
+
+//------------------------
+
+r = /(?:(^.)|.)/ug;
+assertEquals(["\ud800\udc00", "\ud800\udc00"],
+ r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(2, r.lastIndex);
+r.lastIndex = 1;
+assertEquals(["\ud800\udc00", "\ud800\udc00"],
+ r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(2, r.lastIndex);
+assertEquals(["\ud801\udc01", undefined], r.exec("\ud800\udc00\ud801\udc01"));
+r.lastIndex = 3;
+assertEquals(["\ud801\udc01", undefined], r.exec("\ud800\udc00\ud801\udc01"));
+r.lastIndex = 4;
+assertNull(r.exec("\ud800\udc00\ud801\udc01"));
+r.lastIndex = 5;
+assertNull(r.exec("\ud800\udc00\ud801\udc01"));
+
+r.lastIndex = 3;
+assertEquals(["\ud802", undefined], r.exec("\ud800\udc00\ud801\ud802"));
+r.lastIndex = 4;
+assertNull(r.exec("\ud800\udc00\ud801\ud802"));
+
+r = /(?:(^.)|.)/g;
+assertEquals(["\ud800", "\ud800"],
+ r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(1, r.lastIndex);
+assertEquals(["\udc00", undefined], r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(2, r.lastIndex);
+r.lastIndex = 3;
+assertEquals(["\udc01", undefined], r.exec("\ud800\udc00\ud801\udc01"));
+assertEquals(4, r.lastIndex);
diff --git a/test/mjsunit/es6/unicode-regexp-restricted-syntax.js b/test/mjsunit/es6/unicode-regexp-restricted-syntax.js
new file mode 100644
index 0000000..dd4fa39
--- /dev/null
+++ b/test/mjsunit/es6/unicode-regexp-restricted-syntax.js
@@ -0,0 +1,42 @@
+// Copyright 2016 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.
+
+// test262/data/test/language/literals/regexp/u-dec-esc
+assertThrows("/\\1/u", SyntaxError);
+// test262/language/literals/regexp/u-invalid-char-range-a
+assertThrows("/[\\w-a]/u", SyntaxError);
+// test262/language/literals/regexp/u-invalid-char-range-b
+assertThrows("/[a-\\w]/u", SyntaxError);
+// test262/language/literals/regexp/u-invalid-char-esc
+assertThrows("/\\c/u", SyntaxError);
+assertThrows("/\\c0/u", SyntaxError);
+// test262/built-ins/RegExp/unicode_restricted_quantifiable_assertion
+assertThrows("/(?=.)*/u", SyntaxError);
+// test262/built-ins/RegExp/unicode_restricted_octal_escape
+assertThrows("/[\\1]/u", SyntaxError);
+assertThrows("/\\00/u", SyntaxError);
+assertThrows("/\\09/u", SyntaxError);
+// test262/built-ins/RegExp/unicode_restricted_identity_escape_alpha
+assertThrows("/[\\c]/u", SyntaxError);
+// test262/built-ins/RegExp/unicode_restricted_identity_escape_c
+assertThrows("/[\\c0]/u", SyntaxError);
+// test262/built-ins/RegExp/unicode_restricted_incomple_quantifier
+assertThrows("/a{/u", SyntaxError);
+assertThrows("/a{1,/u", SyntaxError);
+assertThrows("/{/u", SyntaxError);
+assertThrows("/}/u", SyntaxError);
+// test262/data/test/built-ins/RegExp/unicode_restricted_brackets
+assertThrows("/]/u", SyntaxError);
+// test262/built-ins/RegExp/unicode_identity_escape
+/\//u;
+
+// escaped \0 is allowed inside a character class.
+assertEquals(["\0"], /[\0]/u.exec("\0"));
+// unless it is followed by another digit.
+assertThrows("/[\\00]/u", SyntaxError);
+assertThrows("/[\\01]/u", SyntaxError);
+assertThrows("/[\\09]/u", SyntaxError);
+assertEquals(["\u{0}1\u{0}a\u{0}"], /[1\0a]+/u.exec("b\u{0}1\u{0}a\u{0}2"));
+// escaped \- is allowed inside a character class.
+assertEquals(["-"], /[a\-z]/u.exec("12-34"));
diff --git a/test/mjsunit/es6/unicode-regexp-unanchored-advance.js b/test/mjsunit/es6/unicode-regexp-unanchored-advance.js
new file mode 100644
index 0000000..c471122
--- /dev/null
+++ b/test/mjsunit/es6/unicode-regexp-unanchored-advance.js
@@ -0,0 +1,6 @@
+// Copyright 2013 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.
+
+var s = "a".repeat(1E7) + "\u1234";
+assertEquals(["\u1234", "\u1234"], /(\u1234)/u.exec(s));
diff --git a/test/mjsunit/es6/unicode-regexp-zero-length.js b/test/mjsunit/es6/unicode-regexp-zero-length.js
new file mode 100644
index 0000000..42bb2d7
--- /dev/null
+++ b/test/mjsunit/es6/unicode-regexp-zero-length.js
@@ -0,0 +1,56 @@
+// Copyright 2016 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.
+
+var L = "\ud800";
+var T = "\udc00";
+var x = "x";
+
+var r = /()/g; // Global, but not unicode.
+// Zero-length matches do not advance lastIndex.
+assertEquals(["", ""], r.exec(L + T + L + T));
+assertEquals(0, r.lastIndex);
+r.lastIndex = 1;
+assertEquals(["", ""], r.exec(L + T + L + T));
+assertEquals(1, r.lastIndex);
+
+var u = /()/ug; // Global and unicode.
+// Zero-length matches do not advance lastIndex.
+assertEquals(["", ""], u.exec(L + T + L + T));
+assertEquals(0, u.lastIndex);
+u.lastIndex = 1;
+assertEquals(["", ""], u.exec(L + T + L + T));
+assertEquals(0, u.lastIndex);
+
+// However, with repeating matches, lastIndex does not matter.
+// We do advance from match to match.
+r.lastIndex = 2;
+assertEquals(x + L + x + T + x + L + x + T + x,
+ (L + T + L + T).replace(r, "x"));
+
+// With unicode flag, we advance code point by code point.
+u.lastIndex = 3;
+assertEquals(x + L + T + x + L + T + x,
+ (L + T + L + T).replace(u, "x"));
+
+// Test that exhausting the global match cache is fine.
+assertEquals((x + L + T).repeat(1000) + x,
+ (L + T).repeat(1000).replace(u, "x"));
+
+// Same thing for RegExp.prototype.match.
+r.lastIndex = 1;
+assertEquals(["","","","",""], (L + T + L + T).match(r));
+r.lastIndex = 2;
+assertEquals(["","","","",""], (L + T + L + T).match(r));
+
+u.lastIndex = 1;
+assertEquals(["","",""], (L + T + L + T).match(u));
+u.lastIndex = 2;
+assertEquals(["","",""], (L + T + L + T).match(u));
+
+var expected = [];
+for (var i = 0; i <= 1000; i++) expected.push("");
+assertEquals(expected, (L + T).repeat(1000).match(u));
+
+// Also test RegExp.prototype.@@split.
+assertEquals(["\u{12345}"], "\u{12345}".split(/(?:)/u));