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));