Upgrade V8 to 5.1.281.57  DO NOT MERGE

FPIIM-449

Change-Id: Id981b686b4d587ac31697662eb98bb34be42ad90
(cherry picked from commit 3b9bc31999c9787eb726ecdbfd5796bfdec32a18)
diff --git a/test/mjsunit/es6/array-concat.js b/test/mjsunit/es6/array-concat.js
index bc9e1a0..fe320d6 100644
--- a/test/mjsunit/es6/array-concat.js
+++ b/test/mjsunit/es6/array-concat.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-proxies --harmony-reflect
-
 (function testArrayConcatArity() {
   "use strict";
   assertEquals(1, Array.prototype.concat.length);
@@ -803,9 +801,10 @@
 
   log.length = 0;
   assertEquals([obj], Array.prototype.concat.apply(obj));
-  assertEquals(1, log.length);
+  assertEquals(2, log.length);  // An extra read for the constructor
   for (var i in log) assertSame(target, log[i][1]);
-  assertEquals(["get", target, Symbol.isConcatSpreadable, obj], log[0]);
+  assertEquals(["get", target, "constructor", obj], log[0]);
+  assertEquals(["get", target, Symbol.isConcatSpreadable, obj], log[1]);
 })();
 
 
@@ -827,14 +826,15 @@
 
   log.length = 0;
   assertEquals(["a", "b"], Array.prototype.concat.apply(obj));
-  assertEquals(6, log.length);
+  assertEquals(7, log.length);
   for (var i in log) assertSame(target, log[i][1]);
-  assertEquals(["get", target, Symbol.isConcatSpreadable, obj], log[0]);
-  assertEquals(["get", target, "length", obj], log[1]);
-  assertEquals(["has", target, "0"], log[2]);
-  assertEquals(["get", target, "0", obj], log[3]);
-  assertEquals(["has", target, "1"], log[4]);
-  assertEquals(["get", target, "1", obj], log[5]);
+  assertEquals(["get", target, "constructor", obj], log[0]);
+  assertEquals(["get", target, Symbol.isConcatSpreadable, obj], log[1]);
+  assertEquals(["get", target, "length", obj], log[2]);
+  assertEquals(["has", target, "0"], log[3]);
+  assertEquals(["get", target, "0", obj], log[4]);
+  assertEquals(["has", target, "1"], log[5]);
+  assertEquals(["get", target, "1", obj], log[6]);
 })();
 
 
diff --git a/test/mjsunit/es6/array-iterator.js b/test/mjsunit/es6/array-iterator.js
index 5fab0fb..d2d19b0 100644
--- a/test/mjsunit/es6/array-iterator.js
+++ b/test/mjsunit/es6/array-iterator.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 --harmony-tostring
+// Flags: --allow-natives-syntax
 
 
 var NONE = 0;
@@ -160,7 +160,7 @@
   assertArrayEquals(['next'],
       Object.getOwnPropertyNames(ArrayIteratorPrototype));
   assertHasOwnProperty(ArrayIteratorPrototype, 'next', DONT_ENUM);
-  assertHasOwnProperty(ArrayIteratorPrototype, Symbol.iterator, DONT_ENUM);
+  assertFalse(ArrayIteratorPrototype.hasOwnProperty(Symbol.iterator));
 
   assertEquals("[object Array Iterator]",
       Object.prototype.toString.call(iterator));
diff --git a/test/mjsunit/es6/array-prototype-values.js b/test/mjsunit/es6/array-prototype-values.js
new file mode 100644
index 0000000..64162c4
--- /dev/null
+++ b/test/mjsunit/es6/array-prototype-values.js
@@ -0,0 +1,15 @@
+// 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-array-prototype-values
+
+// Functionality of the values iterator is tested elsewhere; this test
+// merely verifies that the 'values' property is set up correctly.
+var valuesDesc = Object.getOwnPropertyDescriptor(Array.prototype, 'values');
+assertEquals('object', typeof valuesDesc);
+assertSame(Array.prototype[Symbol.iterator], valuesDesc.value);
+assertTrue(valuesDesc.configurable);
+assertTrue(valuesDesc.writable);
+assertFalse(valuesDesc.enumerable);
+assertTrue(Array.prototype[Symbol.unscopables].values);
diff --git a/test/mjsunit/es6/array-tostring.js b/test/mjsunit/es6/array-tostring.js
index 397fde4..973b3c3 100644
--- a/test/mjsunit/es6/array-tostring.js
+++ b/test/mjsunit/es6/array-tostring.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-tostring
-
 var global = this;
 
 var funs = {
diff --git a/test/mjsunit/es6/block-eval-var-over-legacy-const.js b/test/mjsunit/es6/block-eval-var-over-legacy-const.js
deleted file mode 100644
index be1687b..0000000
--- a/test/mjsunit/es6/block-eval-var-over-legacy-const.js
+++ /dev/null
@@ -1,86 +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: --harmony-sloppy --harmony-sloppy-let --harmony-sloppy-function
-// Flags: --legacy-const
-
-// Legacy-const-let conflict in a function throws, even if the legacy const
-// is in an eval
-
-// Throws at the top level of a function
-assertThrows(function() {
-  let x = 1;
-  eval('const x = 2');
-}, TypeError);
-
-// If the eval is in its own block scope, throws
-assertThrows(function() {
-  let y = 1;
-  { eval('const y = 2'); }
-}, TypeError);
-
-// If the let is in its own block scope, with the eval, throws
-assertThrows(function() {
-  {
-    let x = 1;
-    eval('const x = 2');
-  }
-}, TypeError);
-
-// Legal if the let is no longer visible
-assertDoesNotThrow(function() {
-  {
-    let x = 1;
-  }
-  eval('const x = 2');
-});
-
-// In global scope
-let caught = false;
-try {
-  let z = 1;
-  eval('const z = 2');
-} catch (e) {
-  caught = true;
-}
-assertTrue(caught);
-
-// Let declarations beyond a function boundary don't conflict
-caught = false;
-try {
-  let a = 1;
-  (function() {
-    eval('const a');
-  })();
-} catch (e) {
-  caught = true;
-}
-assertFalse(caught);
-
-// legacy const across with doesn't conflict
-caught = false;
-try {
-  (function() {
-    with ({x: 1}) {
-      eval("const x = 2;");
-    }
-  })();
-} catch (e) {
-  caught = true;
-}
-assertFalse(caught);
-
-// legacy const can still conflict with let across a with
-caught = false;
-try {
-  (function() {
-    let x;
-    with ({x: 1}) {
-      eval("const x = 2;");
-    }
-  })();
-} catch (e) {
-  caught = true;
-}
-assertTrue(caught);
diff --git a/test/mjsunit/es6/block-let-contextual-sloppy.js b/test/mjsunit/es6/block-let-contextual-sloppy.js
index 20ca107..ac7bca1 100644
--- a/test/mjsunit/es6/block-let-contextual-sloppy.js
+++ b/test/mjsunit/es6/block-let-contextual-sloppy.js
@@ -2,10 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Flags: --harmony-sloppy --harmony-sloppy-let --harmony-destructuring-bind
-// Flags: --legacy-const
+// Flags: --harmony-sloppy --harmony-sloppy-let
 
-// let is usable as a variable with var or legacy const, not let or ES6 const
+// let is usable as a variable with var, but not let or ES6 const
 
 (function (){
   assertEquals(undefined, let);
@@ -50,13 +49,6 @@
   assertEquals(1, obj.x);
 })();
 
-(function () {
-  let obj = {};
-  const [let] = [function() { return obj; }];
-  let().x = 1;
-  assertEquals(1, obj.x);
-})();
-
 (function() {
   function let() {
     return 1;
diff --git a/test/mjsunit/es6/built-in-accessor-names.js b/test/mjsunit/es6/built-in-accessor-names.js
index c5f8cec..8c29d36 100644
--- a/test/mjsunit/es6/built-in-accessor-names.js
+++ b/test/mjsunit/es6/built-in-accessor-names.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-tostring
-
 'use strict';
 
 function assertGetterName(expected, object, name) {
diff --git a/test/mjsunit/es6/classes-proxy.js b/test/mjsunit/es6/classes-proxy.js
index 09d12c2..4642df8 100644
--- a/test/mjsunit/es6/classes-proxy.js
+++ b/test/mjsunit/es6/classes-proxy.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: --allow-natives-syntax --harmony-proxies --harmony-reflect
+// Flags: --allow-natives-syntax
 
 function CreateConstructableProxy(handler) {
   return new Proxy(function(){}, handler);
diff --git a/test/mjsunit/es6/classes-subclass-builtins.js b/test/mjsunit/es6/classes-subclass-builtins.js
index 313aad1..7669ef3 100644
--- a/test/mjsunit/es6/classes-subclass-builtins.js
+++ b/test/mjsunit/es6/classes-subclass-builtins.js
@@ -2,8 +2,8 @@
 // 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-reflect --harmony-regexp-subclass
-// Flags: --expose-gc --strong-mode
+// Flags: --allow-natives-syntax --harmony-regexp-subclass
+// Flags: --expose-gc
 
 "use strict";
 
@@ -78,11 +78,6 @@
     constructor(...args) {
       assertFalse(new.target === undefined);
       super(...args);
-      // Strong functions are not extensible, so don't add fields.
-      if (args[args.length - 1].indexOf("use strong") >= 0) {
-        assertThrows(()=>{ this.a = 10; }, TypeError);
-        return;
-      }
       this.a = 42;
       this.d = 4.2;
       this.o = {foo:153};
@@ -95,26 +90,24 @@
   assertNull(Object.getOwnPropertyDescriptor(sloppy_func, "caller").value);
   assertEquals(undefined, Object.getOwnPropertyDescriptor(strict_func, "caller"));
 
-  function CheckFunction(func, is_strong) {
+  function CheckFunction(func) {
     assertEquals("function", typeof func);
     assertTrue(func instanceof Object);
     assertTrue(func instanceof Function);
     assertTrue(func instanceof A);
     checkPrototypeChain(func, [A, Function, Object]);
-    if (!is_strong) {
-      assertEquals(42, func.a);
-      assertEquals(4.2, func.d);
-      assertEquals(153, func.o.foo);
-      assertTrue(undefined !== func.prototype);
-      func.prototype.bar = "func.bar";
-      var obj = new func();
-      assertTrue(obj instanceof Object);
-      assertTrue(obj instanceof func);
-      assertEquals("object", typeof obj);
-      assertEquals(113, obj.foo);
-      assertEquals("func.bar", obj.bar);
-      delete func.prototype.bar;
-    }
+    assertEquals(42, func.a);
+    assertEquals(4.2, func.d);
+    assertEquals(153, func.o.foo);
+    assertTrue(undefined !== func.prototype);
+    func.prototype.bar = "func.bar";
+    var obj = new func();
+    assertTrue(obj instanceof Object);
+    assertTrue(obj instanceof func);
+    assertEquals("object", typeof obj);
+    assertEquals(113, obj.foo);
+    assertEquals("func.bar", obj.bar);
+    delete func.prototype.bar;
   }
 
   var source = "this.foo = 113;";
@@ -135,15 +128,6 @@
   var strict_func1 = new A("'use strict'; return 312;");
   assertTrue(%HaveSameMap(strict_func, strict_func1));
 
-  // Strong function
-  var strong_func = new A("'use strong'; " + source);
-  assertFalse(%HaveSameMap(strong_func, sloppy_func));
-  assertFalse(%HaveSameMap(strong_func, strict_func));
-  CheckFunction(strong_func, true);
-
-  var strong_func1 = new A("'use strong'; return 312;");
-  assertTrue(%HaveSameMap(strong_func, strong_func1));
-
   gc();
 })();
 
@@ -592,11 +576,6 @@
     constructor(...args) {
       assertFalse(new.target === undefined);
       super(...args);
-      // Strong functions are not extensible, so don't add fields.
-      if (args[args.length - 1].indexOf("use strong") >= 0) {
-        assertThrows(()=>{ this.a = 10; }, TypeError);
-        return;
-      }
       this.a = 42;
       this.d = 4.2;
       this.o = {foo:153};
@@ -610,35 +589,34 @@
   assertEquals(undefined, Object.getOwnPropertyDescriptor(sloppy_func, "caller"));
   assertEquals(undefined, Object.getOwnPropertyDescriptor(strict_func, "caller"));
 
-  function CheckFunction(func, is_strong) {
+  function CheckFunction(func) {
     assertEquals("function", typeof func);
     assertTrue(func instanceof Object);
     assertTrue(func instanceof Function);
     assertTrue(func instanceof GeneratorFunction);
     assertTrue(func instanceof A);
     checkPrototypeChain(func, [A, GeneratorFunction, Function, Object]);
-    if (!is_strong) {
-      assertEquals(42, func.a);
-      assertEquals(4.2, func.d);
-      assertEquals(153, func.o.foo);
 
-      assertTrue(undefined !== func.prototype);
-      func.prototype.bar = "func.bar";
-      var obj = func();  // Generator object.
-      assertTrue(obj instanceof Object);
-      assertTrue(obj instanceof func);
-      assertEquals("object", typeof obj);
-      assertEquals("func.bar", obj.bar);
-      delete func.prototype.bar;
+    assertEquals(42, func.a);
+    assertEquals(4.2, func.d);
+    assertEquals(153, func.o.foo);
 
-      assertPropertiesEqual({done: false, value: 1}, obj.next());
-      assertPropertiesEqual({done: false, value: 1}, obj.next());
-      assertPropertiesEqual({done: false, value: 2}, obj.next());
-      assertPropertiesEqual({done: false, value: 3}, obj.next());
-      assertPropertiesEqual({done: false, value: 5}, obj.next());
-      assertPropertiesEqual({done: false, value: 8}, obj.next());
-      assertPropertiesEqual({done: true, value: undefined}, obj.next());
-    }
+    assertTrue(undefined !== func.prototype);
+    func.prototype.bar = "func.bar";
+    var obj = func();  // Generator object.
+    assertTrue(obj instanceof Object);
+    assertTrue(obj instanceof func);
+    assertEquals("object", typeof obj);
+    assertEquals("func.bar", obj.bar);
+    delete func.prototype.bar;
+
+    assertPropertiesEqual({done: false, value: 1}, obj.next());
+    assertPropertiesEqual({done: false, value: 1}, obj.next());
+    assertPropertiesEqual({done: false, value: 2}, obj.next());
+    assertPropertiesEqual({done: false, value: 3}, obj.next());
+    assertPropertiesEqual({done: false, value: 5}, obj.next());
+    assertPropertiesEqual({done: false, value: 8}, obj.next());
+    assertPropertiesEqual({done: true, value: undefined}, obj.next());
   }
 
   var source = "yield 1; yield 1; yield 2; yield 3; yield 5; yield 8;";
@@ -659,15 +637,6 @@
   var strict_func1 = new A("'use strict'; yield 312;");
   assertTrue(%HaveSameMap(strict_func, strict_func1));
 
-  // Strong generator function
-  var strong_func = new A("'use strong'; " + source);
-  assertFalse(%HaveSameMap(strong_func, sloppy_func));
-  assertFalse(%HaveSameMap(strong_func, strict_func));
-  CheckFunction(strong_func, true);
-
-  var strong_func1 = new A("'use strong'; yield 312;");
-  assertTrue(%HaveSameMap(strong_func, strong_func1));
-
   gc();
 })();
 
@@ -950,7 +919,13 @@
 
   var o = Reflect.construct(RegExp, [pattern], f);
   assertEquals(["match", "tostring"], log);
-  assertEquals(/biep/, o);
+  // TODO(littledan): Is the RegExp constructor correct to create
+  // the internal slots and do these type checks this way?
+  assertEquals("biep", %_RegExpSource(o));
+  assertThrows(() => Object.getOwnPropertyDescriptor(RegExp.prototype,
+                                                     'source').get(o),
+               TypeError);
+  assertEquals("/undefined/undefined", RegExp.prototype.toString.call(o));
   assertTrue(o.__proto__ === p2);
   assertTrue(f.prototype === p3);
 })();
diff --git a/test/mjsunit/es6/classes.js b/test/mjsunit/es6/classes.js
index ac10f0e..4dabda8 100644
--- a/test/mjsunit/es6/classes.js
+++ b/test/mjsunit/es6/classes.js
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Flags: --harmony-sloppy --allow-natives-syntax
+// Flags: --harmony-sloppy --harmony-function-name --allow-natives-syntax
+// Flags: --harmony-do-expressions
 
 (function TestBasics() {
   var C = class C {}
@@ -22,13 +23,11 @@
   class D2 { constructor() {} }
   assertEquals('D2', D2.name);
 
-  // TODO(arv): The logic for the name of anonymous functions in ES6 requires
-  // the below to be 'E';
   var E = class {}
-  assertEquals('', E.name);  // Should be 'E'.
+  assertEquals('E', E.name);  // Should be 'E'.
 
   var F = class { constructor() {} };
-  assertEquals('', F.name);  // Should be 'F'.
+  assertEquals('F', F.name);  // Should be 'F'.
 })();
 
 
@@ -996,3 +995,55 @@
   testClassRestrictedProperties(
       class extends Class { constructor() { super(); } });
 })();
+
+
+(function testReturnFromClassLiteral() {
+
+  function usingDoExpressionInBody() {
+    let x = 42;
+    let dummy = function() {x};
+    try {
+      class C {
+        dummy() {C}
+        [do {return}]() {}
+      };
+    } finally {
+      return x;
+    }
+  }
+  assertEquals(42, usingDoExpressionInBody());
+
+  function usingDoExpressionInExtends() {
+    let x = 42;
+    let dummy = function() {x};
+    try {
+      class C extends (do {return}) { dummy() {C} };
+    } finally {
+      return x;
+    }
+  }
+  assertEquals(42, usingDoExpressionInExtends());
+
+  function usingYieldInBody() {
+    function* foo() {
+      class C {
+        [yield]() {}
+      }
+    }
+    var g = foo();
+    g.next();
+    return g.return(42).value;
+  }
+  assertEquals(42, usingYieldInBody());
+
+  function usingYieldInExtends() {
+    function* foo() {
+      class C extends (yield) {};
+    }
+    var g = foo();
+    g.next();
+    return g.return(42).value;
+  }
+  assertEquals(42, usingYieldInExtends());
+
+})();
diff --git a/test/mjsunit/es6/classof-proxy.js b/test/mjsunit/es6/classof-proxy.js
index c3bc985..0204361 100644
--- a/test/mjsunit/es6/classof-proxy.js
+++ b/test/mjsunit/es6/classof-proxy.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: --allow-natives-syntax --harmony-proxies
+// Flags: --allow-natives-syntax
 
 function test_function(o) {
   if (%_ClassOf(o) === "Function") {
diff --git a/test/mjsunit/es6/collection-iterator.js b/test/mjsunit/es6/collection-iterator.js
index 18b3f1a..a92c9ae 100644
--- a/test/mjsunit/es6/collection-iterator.js
+++ b/test/mjsunit/es6/collection-iterator.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: --allow-natives-syntax --harmony-tostring
+// Flags: --allow-natives-syntax
 
 
 (function TestSetIterator() {
diff --git a/test/mjsunit/es6/collections.js b/test/mjsunit/es6/collections.js
index e410e22..1664a93 100644
--- a/test/mjsunit/es6/collections.js
+++ b/test/mjsunit/es6/collections.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 --allow-natives-syntax --harmony-tostring
+// Flags: --expose-gc --allow-natives-syntax
 
 
 function assertSize(expected, collection) {
diff --git a/test/mjsunit/es6/completion.js b/test/mjsunit/es6/completion.js
index 05565bf..7559514 100644
--- a/test/mjsunit/es6/completion.js
+++ b/test/mjsunit/es6/completion.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: --harmony-sloppy-let --no-legacy-const
+// Flags: --harmony-sloppy-let
 
 
 function assertUndef(x) {
diff --git a/test/mjsunit/es6/debug-blockscopes.js b/test/mjsunit/es6/debug-blockscopes.js
index d3c3620..193ad70 100644
--- a/test/mjsunit/es6/debug-blockscopes.js
+++ b/test/mjsunit/es6/debug-blockscopes.js
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // Flags: --expose-debug-as debug --allow-natives-syntax
-// Flags: --debug-eval-readonly-locals
 // The functions used for testing backtraces. They are at the top to make the
 // testing of source line/column easier.
 
diff --git a/test/mjsunit/es6/debug-liveedit-new-target-1.js b/test/mjsunit/es6/debug-liveedit-new-target-1.js
index 043c5f1..8855742 100644
--- a/test/mjsunit/es6/debug-liveedit-new-target-1.js
+++ b/test/mjsunit/es6/debug-liveedit-new-target-1.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: --harmony-reflect --expose-debug-as debug --allow-natives-syntax
+// Flags: --expose-debug-as debug --allow-natives-syntax
 
 // Test that live-editing a frame that uses new.target fails.
 
diff --git a/test/mjsunit/es6/debug-promises/events.js b/test/mjsunit/es6/debug-promises/events.js
deleted file mode 100644
index 3fcb22f..0000000
--- a/test/mjsunit/es6/debug-promises/events.js
+++ /dev/null
@@ -1,122 +0,0 @@
-// 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: --allow-natives-syntax --expose-debug-as debug
-
-Debug = debug.Debug;
-
-var eventsExpected = 16;
-var exception = null;
-var result = [];
-
-function updatePromise(promise, parentPromise, status, value) {
-  var i;
-  for (i = 0; i < result.length; ++i) {
-    if (result[i].promise === promise) {
-      result[i].parentPromise = parentPromise || result[i].parentPromise;
-      result[i].status = status || result[i].status;
-      result[i].value = value || result[i].value;
-      break;
-    }
-  }
-  assertTrue(i < result.length);
-}
-
-function listener(event, exec_state, event_data, data) {
-  if (event != Debug.DebugEvent.PromiseEvent) return;
-  try {
-    eventsExpected--;
-    assertTrue(event_data.promise().isPromise());
-    if (event_data.status() === 0) {
-      // New promise.
-      assertEquals("pending", event_data.promise().status());
-      result.push({ promise: event_data.promise().value(), status: 0 });
-      assertTrue(exec_state.frame(0).sourceLineText().indexOf("// event") > 0);
-    } else if (event_data.status() !== undefined) {
-      // Resolve/reject promise.
-      updatePromise(event_data.promise().value(),
-                    undefined,
-                    event_data.status(),
-                    event_data.value().value());
-    } else {
-      // Chain promises.
-      assertTrue(event_data.parentPromise().isPromise());
-      updatePromise(event_data.promise().value(),
-                    event_data.parentPromise().value());
-      assertTrue(exec_state.frame(0).sourceLineText().indexOf("// event") > 0);
-    }
-  } catch (e) {
-    print(e + e.stack)
-    exception = e;
-  }
-}
-
-Debug.setListener(listener);
-
-function resolver(resolve, reject) { resolve(); }
-
-var p1 = new Promise(resolver);  // event
-var p2 = p1.then().then();  // event
-var p3 = new Promise(function(resolve, reject) {  // event
-  reject("rejected");
-});
-var p4 = p3.then();  // event
-var p5 = p1.then();  // event
-
-function assertAsync(b, s) {
-  if (b) {
-    print(s, "succeeded");
-  } else {
-    %AbortJS(s + " FAILED!");
-  }
-}
-
-function testDone(iteration) {
-  function checkResult() {
-    if (eventsExpected === 0) {
-      assertAsync(result.length === 6, "result.length");
-
-      assertAsync(result[0].promise === p1, "result[0].promise");
-      assertAsync(result[0].parentPromise === undefined,
-                  "result[0].parentPromise");
-      assertAsync(result[0].status === 1, "result[0].status");
-      assertAsync(result[0].value === undefined, "result[0].value");
-
-      assertAsync(result[1].parentPromise === p1,
-                  "result[1].parentPromise");
-      assertAsync(result[1].status === 1, "result[1].status");
-
-      assertAsync(result[2].promise === p2, "result[2].promise");
-
-      assertAsync(result[3].promise === p3, "result[3].promise");
-      assertAsync(result[3].parentPromise === undefined,
-                  "result[3].parentPromise");
-      assertAsync(result[3].status === -1, "result[3].status");
-      assertAsync(result[3].value === "rejected", "result[3].value");
-
-      assertAsync(result[4].promise === p4, "result[4].promise");
-      assertAsync(result[4].parentPromise === p3,
-                  "result[4].parentPromise");
-      assertAsync(result[4].status === -1, "result[4].status");
-      assertAsync(result[4].value === "rejected", "result[4].value");
-
-      assertAsync(result[5].promise === p5, "result[5].promise");
-      assertAsync(result[5].parentPromise === p1,
-                  "result[5].parentPromise");
-      assertAsync(result[5].status === 1, "result[5].status");
-
-      assertAsync(exception === null, "exception === null");
-      Debug.setListener(null);
-    } else if (iteration > 10) {
-      %AbortJS("Not all events were received!");
-    } else {
-      testDone(iteration + 1);
-    }
-  }
-
-  var iteration = iteration || 0;
-  %EnqueueMicrotask(checkResult);
-}
-
-testDone();
diff --git a/test/mjsunit/es6/debug-promises/resolve-after-aborted-try-finally.js b/test/mjsunit/es6/debug-promises/resolve-after-aborted-try-finally.js
deleted file mode 100644
index 918ae2a..0000000
--- a/test/mjsunit/es6/debug-promises/resolve-after-aborted-try-finally.js
+++ /dev/null
@@ -1,32 +0,0 @@
-// 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
-
-// Test debug events when we listen to all exceptions and
-// there is a catch handler for the exception thrown in a Promise.
-// We expect a normal Exception debug event to be triggered.
-
-Debug = debug.Debug;
-
-var events = [];
-
-function listener(event, exec_state, event_data, data) {
-  if (event == Debug.DebugEvent.PromiseEvent) events.push(event_data.status());
-}
-
-Debug.setListener(listener);
-
-var p = new Promise(function(resolve, reject) {
-  do {
-    try {
-      throw new Error("reject");
-    } finally {
-      break;  // No rethrow.
-    }
-  } while (false);
-  resolve();
-});
-
-assertEquals([0 /* create */, 1 /* resolve */], events);
diff --git a/test/mjsunit/es6/debug-promises/resolve-after-try-catch.js b/test/mjsunit/es6/debug-promises/resolve-after-try-catch.js
deleted file mode 100644
index 298201f..0000000
--- a/test/mjsunit/es6/debug-promises/resolve-after-try-catch.js
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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
-
-// Test debug events when we listen to all exceptions and
-// there is a catch handler for the exception thrown in a Promise.
-// We expect a normal Exception debug event to be triggered.
-
-Debug = debug.Debug;
-
-var events = [];
-
-function listener(event, exec_state, event_data, data) {
-  if (event == Debug.DebugEvent.PromiseEvent) events.push(event_data.status());
-}
-
-Debug.setListener(listener);
-
-var p = new Promise(function (resolve, reject) {
-  try {
-    throw new Error("reject");
-  } catch (e) {
-  }
-  resolve();
-});
-
-assertEquals([0 /* create */, 1 /* resolve */], events);
diff --git a/test/mjsunit/es6/debug-promises/rethrow-in-try-finally.js b/test/mjsunit/es6/debug-promises/rethrow-in-try-finally.js
deleted file mode 100644
index b1e2ff9..0000000
--- a/test/mjsunit/es6/debug-promises/rethrow-in-try-finally.js
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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
-
-// Test debug events when we listen to all exceptions and
-// there is a catch handler for the exception thrown in a Promise.
-// We expect a normal Exception debug event to be triggered.
-
-Debug = debug.Debug;
-
-var events = [];
-
-function listener(event, exec_state, event_data, data) {
-  if (event == Debug.DebugEvent.PromiseEvent) events.push(event_data.status());
-}
-
-Debug.setListener(listener);
-
-var p = new Promise(function(resolve, reject) {
-  try {
-    throw new Error("reject");
-  } finally {
-    // Implicit rethrow.
-  }
-  resolve();
-});
-
-assertEquals([0 /* create */, -1 /* rethrown */], events);
diff --git a/test/mjsunit/es6/debug-promises/throw-with-throw-in-reject.js b/test/mjsunit/es6/debug-promises/throw-with-throw-in-reject.js
index 349d014..5cf49f2 100644
--- a/test/mjsunit/es6/debug-promises/throw-with-throw-in-reject.js
+++ b/test/mjsunit/es6/debug-promises/throw-with-throw-in-reject.js
@@ -31,6 +31,7 @@
 };
 
 MyPromise.prototype = new Promise(function() {});
+MyPromise.__proto__ = Promise;
 p.constructor = MyPromise;
 
 var q = p.chain(
diff --git a/test/mjsunit/es6/debug-promises/throw-with-undefined-reject.js b/test/mjsunit/es6/debug-promises/throw-with-undefined-reject.js
index 69ee01e..6fe3b17 100644
--- a/test/mjsunit/es6/debug-promises/throw-with-undefined-reject.js
+++ b/test/mjsunit/es6/debug-promises/throw-with-undefined-reject.js
@@ -2,18 +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 --promise-extra
-
-// Test debug events when an exception is thrown inside a Promise, which is
-// caught by a custom promise, which has no reject handler.
-// We expect two Exception debug events:
-//  1) when the exception is thrown in the promise q.
-//  2) when calling the undefined custom reject closure in MyPromise throws.
-
-Debug = debug.Debug;
-
-var expected_events = 2;
-var log = [];
+// A non-callable reject function throws eagerly
 
 var p = new Promise(function(resolve, reject) {
   log.push("resolve");
@@ -23,63 +12,11 @@
 function MyPromise(resolver) {
   var reject = undefined;
   var resolve = function() { };
-  log.push("construct");
   resolver(resolve, reject);
 };
 
 MyPromise.prototype = new Promise(function() {});
+MyPromise.__proto__ = Promise;
 p.constructor = MyPromise;
 
-var q = p.chain(
-  function() {
-    log.push("throw caught");
-    throw new Error("caught");  // event
-  });
-
-function listener(event, exec_state, event_data, data) {
-  try {
-    if (event == Debug.DebugEvent.Exception) {
-      expected_events--;
-      assertTrue(expected_events >= 0);
-      if (expected_events == 1) {
-        assertTrue(
-            exec_state.frame(0).sourceLineText().indexOf('// event') > 0);
-        assertEquals("caught", event_data.exception().message);
-      } else if (expected_events == 0) {
-        // All of the frames on the stack are from native Javascript.
-        assertEquals(0, exec_state.frameCount());
-        assertEquals("(var).reject is not a function",
-                     event_data.exception().message);
-      } else {
-        assertUnreachable();
-      }
-      assertSame(q, event_data.promise());
-    }
-  } catch (e) {
-    %AbortJS(e + "\n" + e.stack);
-  }
-}
-
-Debug.setBreakOnUncaughtException();
-Debug.setListener(listener);
-
-log.push("end main");
-
-function testDone(iteration) {
-  function checkResult() {
-    try {
-      assertTrue(iteration < 10);
-      if (expected_events === 0) {
-        assertEquals(["resolve", "construct", "end main", "throw caught"], log);
-      } else {
-        testDone(iteration + 1);
-      }
-    } catch (e) {
-      %AbortJS(e + "\n" + e.stack);
-    }
-  }
-
-  %EnqueueMicrotask(checkResult);
-}
-
-testDone(0);
+assertThrows(()=> p.then(function() { }), TypeError);
diff --git a/test/mjsunit/es6/debug-step-destructuring-assignment.js b/test/mjsunit/es6/debug-step-destructuring-assignment.js
new file mode 100644
index 0000000..4fde928
--- /dev/null
+++ b/test/mjsunit/es6/debug-step-destructuring-assignment.js
@@ -0,0 +1,85 @@
+// 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: --expose-debug-as debug
+
+var exception = null;
+var Debug = debug.Debug;
+var break_count = 0;
+
+function listener(event, exec_state, event_data, data) {
+  if (event != Debug.DebugEvent.Break) return;
+  try {
+    var source = exec_state.frame(0).sourceLineText();
+    print(source);
+    assertTrue(source.indexOf(`// B${break_count++}`) > 0);
+    if (source.indexOf("assertEquals") > 0) {
+      exec_state.prepareStep(Debug.StepAction.StepNext);
+    } else {
+      exec_state.prepareStep(Debug.StepAction.StepIn);
+    }
+  } catch (e) {
+    exception = e;
+    print(e);
+  }
+};
+
+Debug.setListener(listener);
+
+function f() {
+  var a, b, c, d;
+  debugger;                                       // B0
+  [                                               // B1
+    a,                                            // B2
+    b,                                            // B3
+    c = 3                                         // B4
+  ] = [1, 2];
+  assertEquals({a:1,b:2,c:3}, {a, b, c});         // B5
+
+  [                                               // B6
+    a,                                            // B7
+    [
+      b,                                          // B8
+      c                                           // B9
+    ],
+    d                                             // B10
+  ] = [5, [6, 7], 8];
+  assertEquals({a:5,b:6,c:7,d:8}, {a, b, c, d});  // B11
+
+  [                                               // B12
+    a,                                            // B13
+    b,                                            // B14
+    ...c                                          // B15
+  ] = [1, 2, 3, 4];
+  assertEquals({a:1,b:2,c:[3,4]}, {a, b, c});     // B16
+
+  ({                                              // B17
+    a,                                            // B18
+    b,                                            // B19
+    c = 7                                         // B20
+  } = {a: 5, b: 6});
+  assertEquals({a:5,b:6,c:7}, {a, b, c});         // B21
+
+  ({                                              // B22
+    a,                                            // B23
+    b = return1(),                                // B24
+    c = return1()                                 // B25
+  } = {a: 5, b: 6});
+  assertEquals({a:5,b:6,c:1}, {a, b, c});         // B28
+
+  ({                                              // B29
+    x : a,                                        // B30
+    y : b,                                        // B31
+    z : c = 3                                     // B32
+  } = {x: 1, y: 2});
+  assertEquals({a:1,b:2,c:3}, {a, b, c});         // B33
+}                                                 // B34
+
+function return1() {
+  return 1;                                       // B26
+}                                                 // B27
+
+f();
+Debug.setListener(null);                          // B35
+assertNull(exception);
diff --git a/test/mjsunit/es6/debug-step-destructuring-bind.js b/test/mjsunit/es6/debug-step-destructuring-bind.js
new file mode 100644
index 0000000..f670f52
--- /dev/null
+++ b/test/mjsunit/es6/debug-step-destructuring-bind.js
@@ -0,0 +1,110 @@
+// 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: --expose-debug-as debug
+
+var exception = null;
+var Debug = debug.Debug;
+var break_count = 0;
+
+function listener(event, exec_state, event_data, data) {
+  if (event != Debug.DebugEvent.Break) return;
+  try {
+    var source = exec_state.frame(0).sourceLineText();
+    print(source, break_count);
+    assertTrue(source.indexOf(`B${break_count++}`) > 0);
+    if (source.indexOf("assertEquals") > 0) {
+      exec_state.prepareStep(Debug.StepAction.StepNext);
+    } else {
+      exec_state.prepareStep(Debug.StepAction.StepIn);
+    }
+  } catch (e) {
+    exception = e;
+    print(e);
+  }
+};
+
+Debug.setListener(listener);
+
+var id = x => x;                                  // B9 B10 B36 B37
+
+function test() {
+  debugger;                                       // B0
+  function fx1([
+                a,                                // B2
+                b                                 // B3
+              ]) {
+    assertEquals([1, 2], [a, b]);                 // B4
+  }                                               // B5
+  fx1([1, 2, 3]);                                 // B1
+
+  function f2([
+                a,                                // B7
+                b = id(3)                         // B8
+              ]) {
+    assertEquals([4, 3], [a, b]);                 // B11
+  }                                               // B12
+  f2([4]);                                        // B6
+
+  function f3({
+                x: a,                             // B14
+                y: b                              // B15
+              }) {
+    assertEquals([5, 6], [a, b]);                 // B16
+  }                                               // B17
+  f3({y: 6, x: 5});                               // B13
+
+  function f4([
+                a,                                // B19
+                {
+                  b,                              // B20
+                  c,                              // B21
+                }
+              ]) {
+    assertEquals([2, 4, 6], [a, b, c]);           // B22
+  }                                               // B23
+  f4([2, {c: 6, b: 4}]);                          // B18
+
+  function f5([
+                {
+                  a,                              // B25
+                  b = 7                           // B26
+                },
+                c = 3                             // B27
+              ] = [{a:1}]) {
+    assertEquals([1, 7, 3], [a, b, c]);           // B28
+  }                                               // B29
+  f5();                                           // B24
+
+  var name = "x";                                 // B30
+  function f6({
+                [id(name)]: a,                    // B34 B35
+                b = a                             // B38
+              }) {
+    assertEquals([9, 9], [a, b]);                 // B39
+  }                                               // B40
+  var o6 = {};                                    // B31
+  o6[name] = 9;                                   // B32
+  f6(o6);                                         // B33
+
+  try {
+    throw [3, 4];                                 // B41
+  } catch ([
+             a,                                   // B42
+             b,                                   // B43
+             c = 6                                // B44
+           ]) {
+    assertEquals([3, 4, 6], [a, b, c]);           // B45
+  }
+
+  var {
+    x: a,                                         // B46
+    y: b = 9                                      // B47
+  } = { x: 4 };
+  assertEquals([4, 9], [a, b]);                   // B48
+}                                                 // B49
+
+test();
+Debug.setListener(null);                          // B50
+assertNull(exception);
diff --git a/test/mjsunit/es6/debug-stepin-default-parameters.js b/test/mjsunit/es6/debug-stepin-default-parameters.js
new file mode 100644
index 0000000..aaac9f0
--- /dev/null
+++ b/test/mjsunit/es6/debug-stepin-default-parameters.js
@@ -0,0 +1,46 @@
+// 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: --expose-debug-as debug
+
+Debug = debug.Debug
+
+var exception = null;
+var log = [];
+
+function listener(event, exec_state, event_data, data) {
+  if (event != Debug.DebugEvent.Break) return;
+  try {
+    print(event_data.sourceLineText());
+    var entry = "";
+    for (var i = 0; i < exec_state.frameCount(); i++) {
+      entry += exec_state.frame(i).sourceLineText().substr(-1);
+      entry += exec_state.frame(i).sourceColumn();
+    }
+    log.push(entry);
+    exec_state.prepareStep(Debug.StepAction.StepIn);
+  } catch (e) {
+    exception = e;
+  }
+};
+
+function default_arg(x) {
+  return "default";                 // d
+}                                   // e
+
+function f(arg0 = default_arg()) {  // f
+  return arg0;                      // g
+}                                   // h
+
+
+Debug.setListener(listener);
+debugger;                           // a
+var result = f();                   // b
+Debug.setListener(null);            // c
+
+assertNull(exception);
+assertEquals("default", result);
+
+assertEquals(["a0","b13","f18b13","d2f18b13","e0f18b13","g2b13","h0b13","c0"],
+             log);
diff --git a/test/mjsunit/es6/debug-stepin-proxies.js b/test/mjsunit/es6/debug-stepin-proxies.js
new file mode 100644
index 0000000..4e71c79
--- /dev/null
+++ b/test/mjsunit/es6/debug-stepin-proxies.js
@@ -0,0 +1,61 @@
+// 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: --expose-debug-as debug
+
+Debug = debug.Debug
+
+var exception = null;
+var log = [];
+
+function listener(event, exec_state, event_data, data) {
+  if (event != Debug.DebugEvent.Break) return;
+  try {
+    print(event_data.sourceLineText());
+    var entry = "";
+    for (var i = 0; i < exec_state.frameCount(); i++) {
+      entry += exec_state.frame(i).sourceLineText().substr(-1);
+      entry += exec_state.frame(i).sourceColumn();
+    }
+    log.push(entry);
+    exec_state.prepareStep(Debug.StepAction.StepIn);
+  } catch (e) {
+    exception = e;
+  }
+};
+
+var target = {};
+var handler = {
+  has: function(target, name) {
+    return true;                     // h
+  },                                 // i
+  get: function(target, name) {
+    return 42;                       // j
+  },                                 // k
+  set: function(target, name, value) {
+    return false;                    // l
+  },                                 // m
+}
+
+var proxy = new Proxy(target, handler);
+
+Debug.setListener(listener);
+debugger;                            // a
+var has = "step" in proxy;           // b
+var get = proxy.step;                // c
+proxy.step = 43;                     // d
+
+Debug.setListener(null);             // g
+
+assertNull(exception);
+assertTrue(has);
+assertEquals(42, get);
+
+assertEquals([
+  "a0",
+  "b17", "h4b20", "i2b20",  // [[Has]]
+  "c15", "j4c15", "k2c15",  // [[Get]]
+  "d0", "l4d11", "m2d11",   // [[Set]]
+  "g0"
+], log);
diff --git a/test/mjsunit/es6/debug-stepin-string-template.js b/test/mjsunit/es6/debug-stepin-string-template.js
index f500fae..2d8c394 100644
--- a/test/mjsunit/es6/debug-stepin-string-template.js
+++ b/test/mjsunit/es6/debug-stepin-string-template.js
@@ -48,7 +48,8 @@
 
 assertEquals([
   "a0",
-  "b0",
+  "b44",
+  "b13",
   "d2b13",
   "e0b13",
   "b25",
diff --git a/test/mjsunit/es6/debug-stepin-tailcalls.js b/test/mjsunit/es6/debug-stepin-tailcalls.js
new file mode 100644
index 0000000..6020ba9
--- /dev/null
+++ b/test/mjsunit/es6/debug-stepin-tailcalls.js
@@ -0,0 +1,46 @@
+// 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: --expose-debug-as debug --harmony-tailcalls
+
+"use strict";
+
+var Debug = debug.Debug
+var exception = null;
+var breaks = 0;
+
+function f(x) {
+  if (x > 0) {            // B3 B5 B7 B9
+    return f(x - 1);      // B4 B6 B8
+  }
+}                         // B10
+
+function g(x) {
+  return f(x);            // B2
+}
+
+function h(x) {
+  debugger;               // B0
+  g(x);                   // B1
+}                         // B11
+
+
+function listener(event, exec_state, event_data, data) {
+  if (event != Debug.DebugEvent.Break) return;
+  try {
+    print(event_data.sourceLineText());
+    assertTrue(event_data.sourceLineText().indexOf(`B${breaks++}`) > 0);
+    exec_state.prepareStep(Debug.StepAction.StepIn);
+  } catch (e) {
+    exception = e;
+  };
+};
+
+Debug.setListener(listener);
+
+h(3);
+
+Debug.setListener(null);  // B12
+assertNull(exception);
+assertEquals(13, breaks);
diff --git a/test/mjsunit/es6/debug-stepnext-for.js b/test/mjsunit/es6/debug-stepnext-for.js
index 932840a..9d5641a 100644
--- a/test/mjsunit/es6/debug-stepnext-for.js
+++ b/test/mjsunit/es6/debug-stepnext-for.js
@@ -91,7 +91,7 @@
 // based on other values.
 var expected = [
   // Entry
-  "a2","b2",
+  "a2",
   // Empty for-in-var: get enumerable
   "c16",
   // Empty for-in: get enumerable
@@ -108,12 +108,12 @@
   "i12","i10","i11","I4","i11","I4","i11","I4","i11",
   // For-of-let: [Symbol.iterator](), next(), body, next(), ...
   "j16","j14","j15","J4","j15","J4","j15","J4","j15",
-  // For-var: var decl, condition, body, next, condition, body, ...
-  "k7","k20","K4","k26","k20","K4","k26","k20","K4","k26","k20",
+  // For-var: init, condition, body, next, condition, body, ...
+  "k15","k20","K4","k26","k20","K4","k26","k20","K4","k26","k20",
   // For: init, condition, body, next, condition, body, ...
   "l7","l16","L4","l22","l16","L4","l22","l16","L4","l22","l16",
   // For-let: init, condition, body, next, condition, body, ...
-  "m7","m20","M4","m26","m20","M4","m26","m20","M4","m26","m20",
+  "m15","m20","M4","m26","m20","M4","m26","m20","M4","m26","m20",
   // Exit.
   "y0","z0",
 ]
diff --git a/test/mjsunit/es6/debug-stepout-tailcalls.js b/test/mjsunit/es6/debug-stepout-tailcalls.js
new file mode 100644
index 0000000..db0878d
--- /dev/null
+++ b/test/mjsunit/es6/debug-stepout-tailcalls.js
@@ -0,0 +1,45 @@
+// 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: --expose-debug-as debug --harmony-tailcalls
+
+"use strict";
+
+var Debug = debug.Debug
+var exception = null;
+var breaks = 0;
+
+function f(x) {
+  if (x > 0) {
+    return f(x - 1);      // Tail call
+  }
+  debugger;               // Break 0
+}
+
+function g(x) {
+  return f(x);            // Tail call
+}
+
+function h(x) {
+  g(x);                   // Not tail call
+}                         // Break 1
+
+
+function listener(event, exec_state, event_data, data) {
+  if (event != Debug.DebugEvent.Break) return;
+  try {
+    assertTrue(event_data.sourceLineText().indexOf(`Break ${breaks++}`) > 0);
+    exec_state.prepareStep(Debug.StepAction.StepOut);
+  } catch (e) {
+    exception = e;
+  };
+};
+
+Debug.setListener(listener);
+
+h(3);
+
+Debug.setListener(null);  // Break 2
+assertNull(exception);
+assertEquals(3, breaks);
diff --git a/test/mjsunit/es6/default-parameters-debug.js b/test/mjsunit/es6/default-parameters-debug.js
new file mode 100644
index 0000000..30e19c4
--- /dev/null
+++ b/test/mjsunit/es6/default-parameters-debug.js
@@ -0,0 +1,58 @@
+// 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: --expose-debug-as debug
+
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+listenerComplete = false;
+breakPointCount = 0;
+
+function listener(event, exec_state, event_data, data) {
+  if (event == Debug.DebugEvent.Break) {
+    breakPointCount++;
+    if (breakPointCount == 1) {
+      // Break point in initializer for parameter `a`, invoked by
+      // initializer for parameter `b`
+      assertEquals('default', exec_state.frame(1).evaluate('mode').value());
+
+      // initializer for `b` can't refer to `b`
+      assertThrows(function() {
+        exec_state.frame(1).evaluate('b').value();
+      }, ReferenceError);
+
+      assertThrows(function() {
+        exec_state.frame(1).evaluate('c');
+      }, ReferenceError);
+    } else if (breakPointCount == 2) {
+      // Break point in IIFE initializer for parameter `c`
+      assertEquals('modeFn', exec_state.frame(1).evaluate('a.name').value());
+      assertEquals('default', exec_state.frame(1).evaluate('b').value());
+      assertThrows(function() {
+        exec_state.frame(1).evaluate('c');
+      }, ReferenceError);
+    } else if (breakPointCount == 3) {
+      // Break point in function body --- `c` parameter is shadowed
+      assertEquals('modeFn', exec_state.frame(0).evaluate('a.name').value());
+      assertEquals('default', exec_state.frame(0).evaluate('b').value());
+      assertEquals('local', exec_state.frame(0).evaluate('d').value());
+    }
+  }
+};
+
+// Add the debug event listener.
+Debug.setListener(listener);
+
+function f(a = function modeFn(mode) { debugger; return mode; },
+           b = a("default"),
+           c = (function() { debugger; })()) {
+  var d = 'local';
+  debugger;
+};
+
+f();
+
+// Make sure that the debug event listener vas invoked.
+assertEquals(3, breakPointCount);
diff --git a/test/mjsunit/es6/default-parameters-destructuring.js b/test/mjsunit/es6/default-parameters-destructuring.js
new file mode 100644
index 0000000..50071f0
--- /dev/null
+++ b/test/mjsunit/es6/default-parameters-destructuring.js
@@ -0,0 +1,110 @@
+// 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 TestSloppyEvalScoping() {
+  var x = 1;
+
+  function f41({[eval("var x = 2; 'a'")]: w}, z = x) { return z; }
+  assertEquals(1, f41({}));
+  assertEquals(1, f41({a: 0}));
+  function f42({[eval("var x = 2; 'a'")]: w}, z = eval("x")) { return z; }
+  assertEquals(1, f42({}));
+  assertEquals(1, f42({a: 0}));
+  function f43({a: w = eval("var x = 2")}, z = x) { return z; }
+  assertEquals(1, f43({}));
+  assertEquals(1, f43({a: 0}));
+  function f44({a: w = eval("var x = 2")}, z = eval("x")) { return z; }
+  assertEquals(1, f44({}));
+  assertEquals(1, f44({a: 0}));
+
+  function f5({a = eval("var x = 2"), b = x}) { return b; }
+  assertEquals(2, f5({}));
+  assertEquals(1, f5({a: 0}));
+  function f6({a = eval("var x = 2"), b = eval("x")}) { return b; }
+  assertEquals(2, f6({}));
+  assertEquals(1, f6({a: 0}));
+  function f71({[eval("var x = 2; 'a'")]: w, b = x}) { return b; }
+  assertEquals(2, f71({}));
+  assertEquals(2, f71({a: 0}));
+  function f72({[eval("var x = 2; 'a'")]: w, b = eval("x")}) { return b; }
+  assertEquals(2, f72({}));
+  assertEquals(2, f72({a: 0}));
+  function f73({a: w = eval("var x = 2"), b = x}) { return b; }
+  assertEquals(2, f73({}));
+  assertEquals(1, f73({a: 0}));
+  function f74({a: w = eval("var x = 2"), b = eval("x")}) { return b; }
+  assertEquals(2, f74({}));
+  assertEquals(1, f74({a: 0}));
+
+  var g41 = ({[eval("var x = 2; 'a'")]: w}, z = x) => { return z; };
+  assertEquals(1, g41({}));
+  assertEquals(1, g41({a: 0}));
+  var g42 = ({[eval("var x = 2; 'a'")]: w}, z = eval("x")) => { return z; };
+  assertEquals(1, g42({}));
+  assertEquals(1, g42({a: 0}));
+  var g43 = ({a: w = eval("var x = 2")}, z = x) => { return z; };
+  assertEquals(1, g43({}));
+  assertEquals(1, g43({a: 0}));
+  var g44 = ({a: w = eval("var x = 2")}, z = eval("x")) => { return z; };
+  assertEquals(1, g44({}));
+  assertEquals(1, g44({a: 0}));
+
+  var g5 = ({a = eval("var x = 2"), b = x}) => { return b; };
+  assertEquals(2, g5({}));
+  assertEquals(1, g5({a: 0}));
+  var g6 = ({a = eval("var x = 2"), b = eval("x")}) => { return b; };
+  assertEquals(2, g6({}));
+  assertEquals(1, g6({a: 0}));
+  var g71 = ({[eval("var x = 2; 'a'")]: w, b = x}) => { return b; };
+  assertEquals(2, g71({}));
+  assertEquals(2, g71({a: 0}));
+  var g72 = ({[eval("var x = 2; 'a'")]: w, b = eval("x")}) => { return b; };
+  assertEquals(2, g72({}));
+  assertEquals(2, g72({a: 0}));
+  var g73 = ({a: w = eval("var x = 2"), b = x}) => { return b; };
+  assertEquals(2, g73({}));
+  assertEquals(1, g73({a: 0}));
+  var g74 = ({a: w = eval("var x = 2"), b = eval("x")}) => { return b; };
+  assertEquals(2, g74({}));
+  assertEquals(1, g74({a: 0}));
+})();
+
+
+(function TestStrictEvalScoping() {
+  'use strict';
+  var x = 1;
+
+  function f41({[eval("var x = 2; 'a'")]: w}, z = x) { return z; }
+  assertEquals(1, f41({}));
+  assertEquals(1, f41({a: 0}));
+  function f42({[eval("var x = 2; 'a'")]: w}, z = eval("x")) { return z; }
+  assertEquals(1, f42({}));
+  assertEquals(1, f42({a: 0}));
+  function f43({a: w = eval("var x = 2")}, z = x) { return z; }
+  assertEquals(1, f43({}));
+  assertEquals(1, f43({a: 0}));
+  function f44({a: w = eval("var x = 2")}, z = eval("x")) { return z; }
+  assertEquals(1, f44({}));
+  assertEquals(1, f44({a: 0}));
+
+  function f5({a = eval("var x = 2"), b = x}) { return b; }
+  assertEquals(1, f5({}));
+  assertEquals(1, f5({a: 0}));
+  function f6({a = eval("var x = 2"), b = eval("x")}) { return b; }
+  assertEquals(1, f6({}));
+  assertEquals(1, f6({a: 0}));
+  function f71({[eval("var x = 2; 'a'")]: w, b = x}) { return b; }
+  assertEquals(1, f71({}));
+  assertEquals(1, f71({a: 0}));
+  function f72({[eval("var x = 2; 'a'")]: w, b = eval("x")}) { return b; }
+  assertEquals(1, f72({}));
+  assertEquals(1, f72({a: 0}));
+  function f73({a: w = eval("var x = 2"), b = x}) { return b; }
+  assertEquals(1, f73({}));
+  assertEquals(1, f73({a: 0}));
+  function f74({a: w = eval("var x = 2"), b = eval("x")}) { return b; }
+  assertEquals(1, f74({}));
+  assertEquals(1, f74({a: 0}));
+})();
diff --git a/test/mjsunit/es6/default-parameters.js b/test/mjsunit/es6/default-parameters.js
new file mode 100644
index 0000000..4e0bf54
--- /dev/null
+++ b/test/mjsunit/es6/default-parameters.js
@@ -0,0 +1,363 @@
+// 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 TestDefaults() {
+  function f1(x = 1) { return x }
+  assertEquals(1, f1());
+  assertEquals(1, f1(undefined));
+  assertEquals(2, f1(2));
+  assertEquals(null, f1(null));
+
+  function f2(x, y = x) { return x + y; }
+  assertEquals(8, f2(4));
+  assertEquals(8, f2(4, undefined));
+  assertEquals(6, f2(4, 2));
+
+  function f3(x = 1, y) { return x + y; }
+  assertEquals(8, f3(5, 3));
+  assertEquals(3, f3(undefined, 2));
+  assertEquals(6, f3(4, 2));
+
+  function f4(x = () => 1) { return x() }
+  assertEquals(1, f4());
+  assertEquals(1, f4(undefined));
+  assertEquals(2, f4(() => 2));
+  assertThrows(() => f4(null), TypeError);
+
+  function f5(x, y = () => x) { return x + y(); }
+  assertEquals(8, f5(4));
+  assertEquals(8, f5(4, undefined));
+  assertEquals(6, f5(4, () => 2));
+
+  function f6(x = {a: 1, m() { return 2 }}) { return x.a + x.m(); }
+  assertEquals(3, f6());
+  assertEquals(3, f6(undefined));
+  assertEquals(5, f6({a: 2, m() { return 3 }}));
+
+  var g1 = (x = 1) => { return x };
+  assertEquals(1, g1());
+  assertEquals(1, g1(undefined));
+  assertEquals(2, g1(2));
+  assertEquals(null, g1(null));
+
+  var g2 = (x, y = x) => { return x + y; };
+  assertEquals(8, g2(4));
+  assertEquals(8, g2(4, undefined));
+  assertEquals(6, g2(4, 2));
+
+  var g3 = (x = 1, y) => { return x + y; };
+  assertEquals(8, g3(5, 3));
+  assertEquals(3, g3(undefined, 2));
+  assertEquals(6, g3(4, 2));
+
+  var g4 = (x = () => 1) => { return x() };
+  assertEquals(1, g4());
+  assertEquals(1, g4(undefined));
+  assertEquals(2, g4(() => 2));
+  assertThrows(() => g4(null), TypeError);
+
+  var g5 = (x, y = () => x) => { return x + y(); };
+  assertEquals(8, g5(4));
+  assertEquals(8, g5(4, undefined));
+  assertEquals(6, g5(4, () => 2));
+
+  var g6 = (x = {a: 1, m() { return 2 }}) => { return x.a + x.m(); };
+  assertEquals(3, g6());
+  assertEquals(3, g6(undefined));
+  assertEquals(5, g6({a: 2, m() { return 3 }}));
+}());
+
+
+(function TestEvalInParameters() {
+  function f1(x = eval(0)) { return x }
+  assertEquals(0, f1());
+  function f2(x = () => eval(1)) { return x() }
+  assertEquals(1, f2());
+})();
+
+
+(function TestParameterScopingSloppy() {
+  var x = 1;
+
+  function f1(a = x) { var x = 2; return a; }
+  assertEquals(1, f1());
+  function f2(a = x) { function x() {}; return a; }
+  assertEquals(1, f2());
+  function f3(a = eval("x")) { var x; return a; }
+  assertEquals(1, f3());
+  function f31(a = eval("'use strict'; x")) { var x; return a; }
+  assertEquals(1, f31());
+  function f4(a = function() { return x }) { var x; return a(); }
+  assertEquals(1, f4());
+  function f5(a = () => x) { var x; return a(); }
+  assertEquals(1, f5());
+  function f6(a = () => eval("x")) { var x; return a(); }
+  assertEquals(1, f6());
+  function f61(a = () => { 'use strict'; return eval("x") }) { var x; return a(); }
+  assertEquals(1, f61());
+  function f62(a = () => eval("'use strict'; x")) { var x; return a(); }
+  assertEquals(1, f62());
+
+  var g1 = (a = x) => { var x = 2; return a; };
+  assertEquals(1, g1());
+  var g2 = (a = x) => { function x() {}; return a; };
+  assertEquals(1, g2());
+  var g3 = (a = eval("x")) => { var x; return a; };
+  assertEquals(1, g3());
+  var g31 = (a = eval("'use strict'; x")) => { var x; return a; };
+  assertEquals(1, g31());
+  var g4 = (a = function() { return x }) => { var x; return a(); };
+  assertEquals(1, g4());
+  var g5 = (a = () => x) => { var x; return a(); };
+  assertEquals(1, g5());
+  var g6 = (a = () => eval("x")) => { var x; return a(); };
+  assertEquals(1, g6());
+  var g61 = (a = () => { 'use strict'; return eval("x") }) => { var x; return a(); };
+  assertEquals(1, g61());
+  var g62 = (a = () => eval("'use strict'; x")) => { var x; return a(); };
+  assertEquals(1, g62());
+
+  var f11 = function f(x = f) { var f; return x; }
+  assertSame(f11, f11());
+  var f12 = function f(x = f) { function f() {}; return x; }
+  assertSame(f12, f12());
+  var f13 = function f(f = 7, x = f) { return x; }
+  assertSame(7, f13());
+
+  var o1 = {f: function(x = this) { return x; }};
+  assertSame(o1, o1.f());
+  assertSame(1, o1.f(1));
+})();
+
+(function TestParameterScopingStrict() {
+  "use strict";
+  var x = 1;
+
+  function f1(a = x) { let x = 2; return a; }
+  assertEquals(1, f1());
+  function f2(a = x) { const x = 2; return a; }
+  assertEquals(1, f2());
+  function f3(a = x) { function x() {}; return a; }
+  assertEquals(1, f3());
+  function f4(a = eval("x")) { var x; return a; }
+  assertEquals(1, f4());
+  function f5(a = () => eval("x")) { var x; return a(); }
+  assertEquals(1, f5());
+
+  var g1 = (a = x) => { let x = 2; return a; };
+  assertEquals(1, g1());
+  var g2 = (a = x) => { const x = 2; return a; };
+  assertEquals(1, g2());
+  var g3 = (a = x) => { function x() {}; return a; };
+  assertEquals(1, g3());
+  var g4 = (a = eval("x")) => { var x; return a; };
+  assertEquals(1, g4());
+  var g5 = (a = () => eval("x")) => { var x; return a(); };
+  assertEquals(1, g5());
+
+  var f11 = function f(x = f) { let f; return x; }
+  assertSame(f11, f11());
+  var f12 = function f(x = f) { const f = 0; return x; }
+  assertSame(f12, f12());
+  var f13 = function f(x = f) { function f() {}; return x; }
+  assertSame(f13, f13());
+})();
+
+(function TestSloppyEvalScoping() {
+  var x = 1;
+
+  function f1(y = eval("var x = 2")) { with ({}) { return x; } }
+  assertEquals(1, f1());
+  function f2(y = eval("var x = 2"), z = x) { return z; }
+  assertEquals(1, f2());
+  assertEquals(1, f2(0));
+  function f3(y = eval("var x = 2"), z = eval("x")) { return z; }
+  assertEquals(1, f3());
+  assertEquals(1, f3(0));
+  function f8(y = (eval("var x = 2"), x)) { return y; }
+  assertEquals(2, f8());
+  assertEquals(0, f8(0));
+
+  function f11(z = eval("var y = 2")) { return y; }
+  assertThrows(f11, ReferenceError);
+  function f12(z = eval("var y = 2"), b = y) {}
+  assertThrows(f12, ReferenceError);
+  function f13(z = eval("var y = 2"), b = eval("y")) {}
+  assertThrows(f13, ReferenceError);
+
+  function f21(f = () => x) { eval("var x = 2"); return f() }
+  assertEquals(1, f21());
+  assertEquals(3, f21(() => 3));
+  function f22(f = () => eval("x")) { eval("var x = 2"); return f() }
+  assertEquals(1, f22());
+  assertEquals(3, f22(() => 3));
+
+  var g1 = (y = eval("var x = 2")) => { with ({}) { return x; } };
+  assertEquals(1, g1());
+  var g2 = (y = eval("var x = 2"), z = x) => { return z; };
+  assertEquals(1, g2());
+  assertEquals(1, g2(0));
+  var g3 = (y = eval("var x = 2"), z = eval("x")) => { return z; };
+  assertEquals(1, g3());
+  assertEquals(1, g3(0));
+  var g8 = (y = (eval("var x = 2"), x)) => { return y; };
+  assertEquals(2, g8());
+  assertEquals(0, g8(0));
+
+  var g11 = (z = eval("var y = 2")) => { return y; };
+  assertThrows(g11, ReferenceError);
+  var g12 = (z = eval("var y = 2"), b = y) => {};
+  assertThrows(g12, ReferenceError);
+  var g13 = (z = eval("var y = 2"), b = eval("y")) => {};
+  assertThrows(g13, ReferenceError);
+
+  var g21 = (f = () => x) => { eval("var x = 2"); return f() };
+  assertEquals(1, g21());
+  assertEquals(3, g21(() => 3));
+  var g22 = (f = () => eval("x")) => { eval("var x = 2"); return f() };
+  assertEquals(1, g22());
+  assertEquals(3, g22(() => 3));
+})();
+
+
+(function TestStrictEvalScoping() {
+  'use strict';
+  var x = 1;
+
+  function f1(y = eval("var x = 2")) { return x; }
+  assertEquals(1, f1());
+  function f2(y = eval("var x = 2"), z = x) { return z; }
+  assertEquals(1, f2());
+  assertEquals(1, f2(0));
+  function f3(y = eval("var x = 2"), z = eval("x")) { return z; }
+  assertEquals(1, f3());
+  assertEquals(1, f3(0));
+  function f8(y = (eval("var x = 2"), x)) { return y; }
+  assertEquals(1, f8());
+  assertEquals(0, f8(0));
+
+  function f11(z = eval("var y = 2")) { return y; }
+  assertThrows(f11, ReferenceError);
+  function f12(z = eval("var y = 2"), b = y) {}
+  assertThrows(f12, ReferenceError);
+  function f13(z = eval("var y = 2"), b = eval("y")) {}
+  assertThrows(f13, ReferenceError);
+
+  function f21(f = () => x) { eval("var x = 2"); return f() }
+  assertEquals(1, f21());
+  assertEquals(3, f21(() => 3));
+  function f22(f = () => eval("x")) { eval("var x = 2"); return f() }
+  assertEquals(1, f22());
+  assertEquals(3, f22(() => 3));
+})();
+
+(function TestParameterTDZSloppy() {
+  function f1(a = x, x) { return a }
+  assertThrows(() => f1(undefined, 4), ReferenceError);
+  assertEquals(4, f1(4, 5));
+  function f2(a = eval("x"), x) { return a }
+  assertThrows(() => f2(undefined, 4), ReferenceError);
+  assertEquals(4, f2(4, 5));
+  function f3(a = eval("'use strict'; x"), x) { return a }
+  assertThrows(() => f3(undefined, 4), ReferenceError);
+  assertEquals(4, f3(4, 5));
+  function f4(a = () => x, x) { return a() }
+  assertEquals(4, f4(() => 4, 5));
+  function f5(a = () => eval("x"), x) { return a() }
+  assertEquals(4, f5(() => 4, 5));
+  function f6(a = () => eval("'use strict'; x"), x) { return a() }
+  assertEquals(4, f6(() => 4, 5));
+
+  function f11(a = x, x = 2) { return a }
+  assertThrows(() => f11(), ReferenceError);
+  assertThrows(() => f11(undefined), ReferenceError);
+  assertThrows(() => f11(undefined, 4), ReferenceError);
+  assertEquals(4, f1(4, 5));
+  function f12(a = eval("x"), x = 2) { return a }
+  assertThrows(() => f12(), ReferenceError);
+  assertThrows(() => f12(undefined), ReferenceError);
+  assertThrows(() => f12(undefined, 4), ReferenceError);
+  assertEquals(4, f12(4, 5));
+  function f13(a = eval("'use strict'; x"), x = 2) { return a }
+  assertThrows(() => f13(), ReferenceError);
+  assertThrows(() => f13(undefined), ReferenceError);
+  assertThrows(() => f13(undefined, 4), ReferenceError);
+  assertEquals(4, f13(4, 5));
+
+  function f21(x = function() { return a }, ...a) { return x()[0] }
+  assertEquals(4, f21(undefined, 4));
+  function f22(x = () => a, ...a) { return x()[0] }
+  assertEquals(4, f22(undefined, 4));
+  function f23(x = () => eval("a"), ...a) { return x()[0] }
+  assertEquals(4, f23(undefined, 4));
+  function f24(x = () => {'use strict'; return eval("a") }, ...a) {
+    return x()[0]
+  }
+  assertEquals(4, f24(undefined, 4));
+  function f25(x = () => eval("'use strict'; a"), ...a) { return x()[0] }
+  assertEquals(4, f25(undefined, 4));
+
+  var g1 = (x = function() { return a }, ...a) => { return x()[0] };
+  assertEquals(4, g1(undefined, 4));
+  var g2 = (x = () => a, ...a) => { return x()[0] };
+  assertEquals(4, g2(undefined, 4));
+})();
+
+(function TestParameterTDZStrict() {
+  "use strict";
+
+  function f1(a = eval("x"), x) { return a }
+  assertThrows(() => f1(undefined, 4), ReferenceError);
+  assertEquals(4, f1(4, 5));
+  function f2(a = () => eval("x"), x) { return a() }
+  assertEquals(4, f2(() => 4, 5));
+
+  function f11(a = eval("x"), x = 2) { return a }
+  assertThrows(() => f11(), ReferenceError);
+  assertThrows(() => f11(undefined), ReferenceError);
+  assertThrows(() => f11(undefined, 4), ReferenceError);
+  assertEquals(4, f11(4, 5));
+
+  function f21(x = () => eval("a"), ...a) { return x()[0] }
+  assertEquals(4, f21(undefined, 4));
+})();
+
+(function TestArgumentsForNonSimpleParameters() {
+  function f1(x = 900) { arguments[0] = 1; return x }
+  assertEquals(9, f1(9));
+  assertEquals(900, f1());
+  function f2(x = 1001) { x = 2; return arguments[0] }
+  assertEquals(10, f2(10));
+  assertEquals(undefined, f2());
+}());
+
+
+(function TestFunctionLength() {
+   assertEquals(0, (function(x = 1) {}).length);
+   assertEquals(0, (function(x = 1, ...a) {}).length);
+   assertEquals(1, (function(x, y = 1) {}).length);
+   assertEquals(1, (function(x, y = 1, ...a) {}).length);
+   assertEquals(2, (function(x, y, z = 1) {}).length);
+   assertEquals(2, (function(x, y, z = 1, ...a) {}).length);
+   assertEquals(1, (function(x, y = 1, z) {}).length);
+   assertEquals(1, (function(x, y = 1, z, ...a) {}).length);
+   assertEquals(1, (function(x, y = 1, z, v = 2) {}).length);
+   assertEquals(1, (function(x, y = 1, z, v = 2, ...a) {}).length);
+})();
+
+(function TestDirectiveThrows() {
+  "use strict";
+
+  assertThrows(function(){ eval("function(x=1){'use strict';}") }, SyntaxError);
+  assertThrows(function(){ eval("(x=1) => {'use strict';}") }, SyntaxError);
+  assertThrows(
+    function(){ eval("(class{foo(x=1) {'use strict';}});") }, SyntaxError);
+
+  assertThrows(
+    function(){ eval("function(a, x=1){'use strict';}") }, SyntaxError);
+  assertThrows(function(){ eval("(a, x=1) => {'use strict';}") }, SyntaxError);
+  assertThrows(
+    function(){ eval("(class{foo(a, x=1) {'use strict';}});") }, SyntaxError);
+})();
diff --git a/test/mjsunit/es6/destructuring-assignment-lazy.js b/test/mjsunit/es6/destructuring-assignment-lazy.js
new file mode 100644
index 0000000..fdae30e
--- /dev/null
+++ b/test/mjsunit/es6/destructuring-assignment-lazy.js
@@ -0,0 +1,14 @@
+// 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: --min-preparse-length=0
+
+function f() {
+  var a, b;
+  [ a, b ] = [1, 2];
+  assertEquals(1, a);
+  assertEquals(2, b);
+}
+
+f();
diff --git a/test/mjsunit/es6/destructuring-assignment.js b/test/mjsunit/es6/destructuring-assignment.js
new file mode 100644
index 0000000..df9bb0e
--- /dev/null
+++ b/test/mjsunit/es6/destructuring-assignment.js
@@ -0,0 +1,480 @@
+// 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.
+
+// script-level tests
+var ox, oy = {}, oz;
+({
+  x: ox,
+  y: oy.value,
+  y2: oy["value2"],
+  z: ({ set v(val) { oz = val; } }).v
+} = {
+  x: "value of x",
+  y: "value of y1",
+  y2: "value of y2",
+  z: "value of z"
+});
+assertEquals("value of x", ox);
+assertEquals("value of y1", oy.value);
+assertEquals("value of y2", oy.value2);
+assertEquals("value of z", oz);
+
+[ox, oy.value, oy["value2"], ...{ set v(val) { oz = val; } }.v] = [
+  1007,
+  798432,
+  555,
+  1, 2, 3, 4, 5
+];
+assertEquals(ox, 1007);
+assertEquals(oy.value, 798432);
+assertEquals(oy.value2, 555);
+assertEquals(oz, [1, 2, 3, 4, 5]);
+
+
+(function testInFunction() {
+  var x, y = {}, z;
+  ({
+    x: x,
+    y: y.value,
+    y2: y["value2"],
+    z: ({ set v(val) { z = val; } }).v
+  } = {
+    x: "value of x",
+    y: "value of y1",
+    y2: "value of y2",
+    z: "value of z"
+  });
+  assertEquals("value of x", x);
+  assertEquals("value of y1", y.value);
+  assertEquals("value of y2", y.value2);
+  assertEquals("value of z", z);
+
+  [x, y.value, y["value2"], ...{ set v(val) { z = val; } }.v] = [
+    1007,
+    798432,
+    555,
+    1, 2, 3, 4, 5
+  ];
+  assertEquals(x, 1007);
+  assertEquals(y.value, 798432);
+  assertEquals(y.value2, 555);
+  assertEquals(z, [1, 2, 3, 4, 5]);
+})();
+
+
+(function testArrowFunctionInitializers() {
+  var fn = (config = {
+    value: defaults.value,
+    nada: { nada: defaults.nada } = { nada: "nothing" }
+  } = { value: "BLAH" }) => config;
+  var defaults = {};
+  assertEquals({ value: "BLAH" }, fn());
+  assertEquals("BLAH", defaults.value);
+  assertEquals("nothing", defaults.nada);
+})();
+
+
+(function testArrowFunctionInitializers2() {
+  var fn = (config = [
+    defaults.value,
+    { nada: defaults.nada } = { nada: "nothing" }
+  ] = ["BLAH"]) => config;
+  var defaults = {};
+  assertEquals(["BLAH"], fn());
+  assertEquals("BLAH", defaults.value);
+  assertEquals("nothing", defaults.nada);
+})();
+
+
+(function testFunctionInitializers() {
+  function fn(config = {
+    value: defaults.value,
+    nada: { nada: defaults.nada } = { nada: "nothing" }
+  } = { value: "BLAH" }) {
+    return config;
+  }
+  var defaults = {};
+  assertEquals({ value: "BLAH" }, fn());
+  assertEquals("BLAH", defaults.value);
+  assertEquals("nothing", defaults.nada);
+})();
+
+
+(function testFunctionInitializers2() {
+  function fn(config = [
+    defaults.value,
+    { nada: defaults.nada } = { nada: "nothing" }
+  ] = ["BLAH"]) { return config; }
+  var defaults = {};
+  assertEquals(["BLAH"], fn());
+  assertEquals("BLAH", defaults.value);
+  assertEquals("nothing", defaults.nada);
+})();
+
+
+(function testDeclarationInitializers() {
+  var defaults = {};
+  var { value } = { value: defaults.value } = { value: "BLAH" };
+  assertEquals("BLAH", value);
+  assertEquals("BLAH", defaults.value);
+})();
+
+
+(function testDeclarationInitializers2() {
+  var defaults = {};
+  var [value] = [defaults.value] = ["BLAH"];
+  assertEquals("BLAH", value);
+  assertEquals("BLAH", defaults.value);
+})();
+
+
+(function testObjectLiteralProperty() {
+  var ext = {};
+  var obj = {
+    a: { b: ext.b, c: ext["c"], d: { set v(val) { ext.d = val; } }.v } = {
+      b: "b", c: "c", d: "d" }
+  };
+  assertEquals({ b: "b", c: "c", d: "d" }, ext);
+  assertEquals({ a: { b: "b", c: "c", d: "d" } }, obj);
+})();
+
+
+(function testArrayLiteralProperty() {
+  var ext = {};
+  var obj = [
+    ...[ ext.b, ext["c"], { set v(val) { ext.d = val; } }.v ] = [
+      "b", "c", "d" ]
+  ];
+  assertEquals({ b: "b", c: "c", d: "d" }, ext);
+  assertEquals([ "b", "c", "d" ], obj);
+})();
+
+
+// TODO(caitp): add similar test for ArrayPatterns, once Proxies support
+// delegating symbol-keyed get/set.
+(function testObjectPatternOperationOrder() {
+  var steps = [];
+  var store = {};
+  function computePropertyName(name) {
+    steps.push("compute name: " + name);
+    return name;
+  }
+  function loadValue(descr, value) {
+    steps.push("load: " + descr + " > " + value);
+    return value;
+  }
+  function storeValue(descr, name, value) {
+    steps.push("store: " + descr + " = " + value);
+    store[name] = value;
+  }
+  var result = {
+    get a() { assertUnreachable(); },
+    set a(value) { storeValue("result.a", "a", value); },
+    get b() { assertUnreachable(); },
+    set b(value) { storeValue("result.b", "b", value); }
+  };
+
+  ({
+    obj: {
+      x: result.a = 10,
+      [computePropertyName("y")]: result.b = false,
+    } = {}
+  } = { obj: {
+    get x() { return loadValue(".temp.obj.x", undefined); },
+    set x(value) { assertUnreachable(); },
+    get y() { return loadValue(".temp.obj.y", undefined); },
+    set y(value) { assertUnreachable(); }
+  }});
+
+  assertPropertiesEqual({
+    a: 10,
+    b: false
+  }, store);
+
+  assertArrayEquals([
+    "load: .temp.obj.x > undefined",
+    "store: result.a = 10",
+
+    "compute name: y",
+    "load: .temp.obj.y > undefined",
+    "store: result.b = false"
+  ], steps);
+
+  steps = [];
+
+  ({
+    obj: {
+      x: result.a = 50,
+      [computePropertyName("y")]: result.b = "hello",
+    } = {}
+  } = { obj: {
+    get x() { return loadValue(".temp.obj.x", 20); },
+    set x(value) { assertUnreachable(); },
+    get y() { return loadValue(".temp.obj.y", true); },
+    set y(value) { assertUnreachable(); }
+  }});
+
+  assertPropertiesEqual({
+    a: 20,
+    b: true
+  }, store);
+
+  assertArrayEquals([
+    "load: .temp.obj.x > 20",
+    "store: result.a = 20",
+    "compute name: y",
+    "load: .temp.obj.y > true",
+    "store: result.b = true",
+  ], steps);
+})();
+
+// Credit to Mike Pennisi and other Test262 contributors for originally writing
+// the testse the following are based on.
+(function testArrayElision() {
+  var value = [1, 2, 3, 4, 5, 6, 7, 8, 9];
+  var a, obj = {};
+  var result = [, a, , obj.b, , ...obj["rest"]] = value;
+
+  assertEquals(result, value);
+  assertEquals(2, a);
+  assertEquals(4, obj.b);
+  assertArrayEquals([6, 7, 8, 9], obj.rest);
+})();
+
+(function testArrayElementInitializer() {
+  function test(value, initializer, expected) {
+    var a, obj = {};
+    var initialized = false;
+    var shouldBeInitialized = value[0] === undefined;
+    assertEquals(value, [ a = (initialized = true, initializer) ] = value);
+    assertEquals(expected, a);
+    assertEquals(shouldBeInitialized, initialized);
+
+    var initialized2 = false;
+    assertEquals(value, [ obj.a = (initialized2 = true, initializer) ] = value);
+    assertEquals(expected, obj.a);
+    assertEquals(shouldBeInitialized, initialized2);
+  }
+
+  test([], "BAM!", "BAM!");
+  test([], "BOOP!", "BOOP!");
+  test([null], 123, null);
+  test([undefined], 456, 456);
+  test([,], "PUPPIES", "PUPPIES");
+
+  (function accept_IN() {
+    var value = [], x;
+    assertEquals(value, [ x = 'x' in {} ] = value);
+    assertEquals(false, x);
+  })();
+
+  (function ordering() {
+    var x = 0, a, b, value = [];
+    assertEquals(value, [ a = x += 1, b = x *= 2 ] = value);
+    assertEquals(1, a);
+    assertEquals(2, b);
+    assertEquals(2, x);
+  })();
+
+  (function yieldExpression() {
+    var value = [], it, result, x;
+    it = (function*() {
+      result = [ x = yield ] = value;
+    })();
+    var next = it.next();
+
+    assertEquals(undefined, result);
+    assertEquals(undefined, next.value);
+    assertEquals(false, next.done);
+    assertEquals(undefined, x);
+
+    next = it.next(86);
+
+    assertEquals(value, result);
+    assertEquals(undefined, next.value);
+    assertEquals(true, next.done);
+    assertEquals(86, x);
+  })();
+
+  (function yieldIdentifier() {
+    var value = [], yield = "BOOP!", x;
+    assertEquals(value, [ x = yield ] = value);
+    assertEquals("BOOP!", x);
+  })();
+
+  assertThrows(function let_TDZ() {
+    "use strict";
+    var x;
+    [ x = y ] = [];
+    let y;
+  }, ReferenceError);
+})();
+
+
+(function testArrayElementNestedPattern() {
+  assertThrows(function nestedArrayRequireObjectCoercibleNull() {
+    var x; [ [ x ] ] = [ null ];
+  }, TypeError);
+
+  assertThrows(function nestedArrayRequireObjectCoercibleUndefined() {
+    var x; [ [ x ] ] = [ undefined ];
+  }, TypeError);
+
+  assertThrows(function nestedArrayRequireObjectCoercibleUndefined2() {
+    var x; [ [ x ] ] = [ ];
+  }, TypeError);
+
+  assertThrows(function nestedArrayRequireObjectCoercibleUndefined3() {
+    var x; [ [ x ] ] = [ , ];
+  }, TypeError);
+
+  assertThrows(function nestedObjectRequireObjectCoercibleNull() {
+    var x; [ { x } ] = [ null ];
+  }, TypeError);
+
+  assertThrows(function nestedObjectRequireObjectCoercibleUndefined() {
+    var x; [ { x } ] = [ undefined ];
+  }, TypeError);
+
+  assertThrows(function nestedObjectRequireObjectCoercibleUndefined2() {
+    var x; [ { x } ] = [ ];
+  }, TypeError);
+
+  assertThrows(function nestedObjectRequireObjectCoercibleUndefined3() {
+    var x; [ { x } ] = [ , ];
+  }, TypeError);
+
+  (function nestedArray() {
+    var x, value = [ [ "zap", "blonk" ] ];
+    assertEquals(value, [ [ , x ] ] = value);
+    assertEquals("blonk", x);
+  })();
+
+  (function nestedObject() {
+    var x, value = [ { a: "zap", b: "blonk" } ];
+    assertEquals(value, [ { b: x } ] = value);
+    assertEquals("blonk", x);
+  })();
+})();
+
+(function testArrayRestElement() {
+  (function testBasic() {
+    var x, rest, array = [1, 2, 3];
+    assertEquals(array, [x, ...rest] = array);
+    assertEquals(1, x);
+    assertEquals([2, 3], rest);
+
+    array = [4, 5, 6];
+    assertEquals(array, [, ...rest] = array);
+    assertEquals([5, 6], rest);
+
+  })();
+
+  (function testNestedRestObject() {
+    var value = [1, 2, 3], x;
+    assertEquals(value, [...{ 1: x }] = value);
+    assertEquals(2, x);
+  })();
+
+  (function iterable() {
+    var count = 0;
+    var x, y, z;
+    function* g() {
+      count++;
+      yield;
+      count++;
+      yield;
+      count++;
+      yield;
+    }
+    var it = g();
+    assertEquals(it, [...x] = it);
+    assertEquals([undefined, undefined, undefined], x);
+    assertEquals(3, count);
+
+    it = [g()];
+    assertEquals(it, [ [...y] ] = it);
+    assertEquals([undefined, undefined, undefined], y);
+    assertEquals(6, count);
+
+    it = { a: g() };
+    assertEquals(it, { a: [...z] } = it);
+    assertEquals([undefined, undefined, undefined], z);
+    assertEquals(9, count);
+  })();
+})();
+
+(function testRequireObjectCoercible() {
+  assertThrows(() => ({} = undefined), TypeError);
+  assertThrows(() => ({} = null), TypeError);
+  assertThrows(() => [] = undefined, TypeError);
+  assertThrows(() => [] = null, TypeError);
+  assertEquals("test", ({} = "test"));
+  assertEquals("test", [] = "test");
+  assertEquals(123, ({} = 123));
+})();
+
+(function testConstReassignment() {
+  "use strict";
+  const c = "untouchable";
+  assertThrows(() => { [ c ] = [ "nope!" ]; }, TypeError);
+  assertThrows(() => { [ [ c ] ]  = [ [ "nope!" ] ]; }, TypeError);
+  assertThrows(() => { [ { c } ]  = [ { c: "nope!" } ]; }, TypeError);
+  assertThrows(() => { ({ c } = { c: "nope!" }); }, TypeError);
+  assertThrows(() => { ({ a: { c } } = { a: { c: "nope!" } }); }, TypeError);
+  assertThrows(() => { ({ a: [ c ] } = { a: [ "nope!" ] }); }, TypeError);
+  assertEquals("untouchable", c);
+})();
+
+(function testForIn() {
+  var log = [];
+  var x = {};
+  var object = {
+    "Apenguin": 1,
+    "\u{1F382}cake": 2,
+    "Bpuppy": 3,
+    "Cspork": 4
+  };
+  for ([x.firstLetter, ...x.rest] in object) {
+    if (x.firstLetter === "A") {
+      assertEquals(["p", "e", "n", "g", "u", "i", "n"], x.rest);
+      continue;
+    }
+    if (x.firstLetter === "C") {
+      assertEquals(["s", "p", "o", "r", "k"], x.rest);
+      break;
+    }
+    log.push({ firstLetter: x.firstLetter, rest: x.rest });
+  }
+  assertEquals([
+    { firstLetter: "\u{1F382}", rest: ["c", "a", "k", "e"] },
+    { firstLetter: "B", rest: ["p", "u", "p", "p", "y"] },
+  ], log);
+})();
+
+(function testForOf() {
+  var log = [];
+  var x = {};
+  var names = [
+    "Apenguin",
+    "\u{1F382}cake",
+    "Bpuppy",
+    "Cspork"
+  ];
+  for ([x.firstLetter, ...x.rest] of names) {
+    if (x.firstLetter === "A") {
+      assertEquals(["p", "e", "n", "g", "u", "i", "n"], x.rest);
+      continue;
+    }
+    if (x.firstLetter === "C") {
+      assertEquals(["s", "p", "o", "r", "k"], x.rest);
+      break;
+    }
+    log.push({ firstLetter: x.firstLetter, rest: x.rest });
+  }
+  assertEquals([
+    { firstLetter: "\u{1F382}", rest: ["c", "a", "k", "e"] },
+    { firstLetter: "B", rest: ["p", "u", "p", "p", "y"] },
+  ], log);
+})();
diff --git a/test/mjsunit/es6/destructuring-parameters-literalcount-nolazy.js b/test/mjsunit/es6/destructuring-parameters-literalcount-nolazy.js
new file mode 100644
index 0000000..0317509
--- /dev/null
+++ b/test/mjsunit/es6/destructuring-parameters-literalcount-nolazy.js
@@ -0,0 +1,40 @@
+// 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: --no-lazy --allow-natives-syntax
+
+
+var t1 = [1];
+var t2 = [2];
+var t3 = [3];
+var t4 = [4];
+var t5 = [5];
+function g({x = {a:10,b:20}},
+           {y = [1,2,3],
+            n = [],
+            p = /abc/}) {
+  assertSame(10, x.a);
+  assertSame(20, x.b);
+  assertSame(2, y[1]);
+  assertSame(0, n.length);
+  assertTrue(p.test("abc"));
+}
+g({},{});
+%OptimizeFunctionOnNextCall(g);
+g({},{});
+
+
+var h = ({x = {a:10,b:20}},
+         {y = [1,2,3],
+          n = [],
+          p = /abc/ }) => {
+    assertSame(10, x.a);
+    assertSame(20, x.b);
+    assertSame(2, y[1]);
+    assertSame(0, n.length);
+    assertTrue(p.test("abc"));
+  };
+h({},{});
+%OptimizeFunctionOnNextCall(h);
+h({},{});
diff --git a/test/mjsunit/es6/destructuring-parameters-literalcount.js b/test/mjsunit/es6/destructuring-parameters-literalcount.js
new file mode 100644
index 0000000..77a3226
--- /dev/null
+++ b/test/mjsunit/es6/destructuring-parameters-literalcount.js
@@ -0,0 +1,40 @@
+// 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
+
+
+var t1 = [1];
+var t2 = [2];
+var t3 = [3];
+var t4 = [4];
+var t5 = [5];
+function g({x = {a:10,b:20}},
+           {y = [1,2,3],
+            n = [],
+            p = /abc/}) {
+  assertSame(10, x.a);
+  assertSame(20, x.b);
+  assertSame(2, y[1]);
+  assertSame(0, n.length);
+  assertTrue(p.test("abc"));
+}
+g({},{});
+%OptimizeFunctionOnNextCall(g);
+g({},{});
+
+
+var h = ({x = {a:10,b:20}},
+         {y = [1,2,3],
+          n = [],
+          p = /abc/ }) => {
+    assertSame(10, x.a);
+    assertSame(20, x.b);
+    assertSame(2, y[1]);
+    assertSame(0, n.length);
+    assertTrue(p.test("abc"));
+  };
+h({},{});
+%OptimizeFunctionOnNextCall(h);
+h({},{});
diff --git a/test/mjsunit/es6/destructuring.js b/test/mjsunit/es6/destructuring.js
new file mode 100644
index 0000000..1f16c45
--- /dev/null
+++ b/test/mjsunit/es6/destructuring.js
@@ -0,0 +1,1191 @@
+// 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 TestObjectLiteralPattern() {
+  var { x : x, y : y, get, set } = { x : 1, y : 2, get: 3, set: 4 };
+  assertEquals(1, x);
+  assertEquals(2, y);
+  assertEquals(3, get);
+  assertEquals(4, set);
+
+  var {z} = { z : 3 };
+  assertEquals(3, z);
+
+
+  var sum = 0;
+  for (var {z} = { z : 3 }; z != 0; z--) {
+    sum += z;
+  }
+  assertEquals(6, sum);
+
+
+  var log = [];
+  var o = {
+    get x() {
+      log.push("x");
+      return 0;
+    },
+    get y() {
+      log.push("y");
+      return {
+        get z() { log.push("z"); return 1; }
+      }
+    }
+  };
+  var { x : x0, y : { z : z1 }, x : x1 } = o;
+  assertSame(0, x0);
+  assertSame(1, z1);
+  assertSame(0, x1);
+  assertArrayEquals(["x", "y", "z", "x"], log);
+}());
+
+
+(function TestObjectLiteralPatternInitializers() {
+  var { x : x, y : y = 2 } = { x : 1 };
+  assertEquals(1, x);
+  assertEquals(2, y);
+
+  var {z = 3} = {};
+  assertEquals(3, z);
+
+  var sum = 0;
+  for (var {z = 3} = {}; z != 0; z--) {
+    sum += z;
+  }
+  assertEquals(6, sum);
+
+  var log = [];
+  var o = {
+    get x() {
+      log.push("x");
+      return undefined;
+    },
+    get y() {
+      log.push("y");
+      return {
+        get z() { log.push("z"); return undefined; }
+      }
+    }
+  };
+  var { x : x0 = 0, y : { z : z1 = 1}, x : x1 = 0} = o;
+  assertSame(0, x0);
+  assertSame(1, z1);
+  assertSame(0, x1);
+  assertArrayEquals(["x", "y", "z", "x"], log);
+}());
+
+
+(function TestObjectLiteralPatternLexicalInitializers() {
+  'use strict';
+  let { x : x, y : y = 2 } = { x : 1 };
+  assertEquals(1, x);
+  assertEquals(2, y);
+
+  let {z = 3} = {};
+  assertEquals(3, z);
+
+  let log = [];
+  let o = {
+    get x() {
+      log.push("x");
+      return undefined;
+    },
+    get y() {
+      log.push("y");
+      return {
+        get z() { log.push("z"); return undefined; }
+      }
+    }
+  };
+
+  let { x : x0 = 0, y : { z : z1 = 1 }, x : x1 = 5} = o;
+  assertSame(0, x0);
+  assertSame(1, z1);
+  assertSame(5, x1);
+  assertArrayEquals(["x", "y", "z", "x"], log);
+
+  let sum = 0;
+  for (let {x = 0, z = 3} = {}; z != 0; z--) {
+    assertEquals(0, x);
+    sum += z;
+  }
+  assertEquals(6, sum);
+}());
+
+
+(function TestObjectLiteralPatternLexical() {
+  'use strict';
+  let { x : x, y : y } = { x : 1, y : 2 };
+  assertEquals(1, x);
+  assertEquals(2, y);
+
+  let {z} = { z : 3 };
+  assertEquals(3, z);
+
+  let log = [];
+  let o = {
+    get x() {
+      log.push("x");
+      return 0;
+    },
+    get y() {
+      log.push("y");
+      return {
+        get z() { log.push("z"); return 1; }
+      }
+    }
+  };
+  let { x : x0, y : { z : z1 }, x : x1 } = o;
+  assertSame(0, x0);
+  assertSame(1, z1);
+  assertSame(0, x1);
+  assertArrayEquals(["x", "y", "z", "x"], log);
+
+  let sum = 0;
+  for (let {x, z} = { x : 0, z : 3 }; z != 0; z--) {
+    assertEquals(0, x);
+    sum += z;
+  }
+  assertEquals(6, sum);
+}());
+
+
+(function TestObjectLiteralPatternLexicalConst() {
+  'use strict';
+  const { x : x, y : y } = { x : 1, y : 2 };
+  assertEquals(1, x);
+  assertEquals(2, y);
+
+  assertThrows(function() { x++; }, TypeError);
+  assertThrows(function() { y++; }, TypeError);
+
+  const {z} = { z : 3 };
+  assertEquals(3, z);
+
+  for (const {x, z} = { x : 0, z : 3 }; z != 3 || x != 0;) {
+    assertTrue(false);
+  }
+}());
+
+
+(function TestFailingMatchesSloppy() {
+  var {x, y} = {};
+  assertSame(undefined, x);
+  assertSame(undefined, y);
+
+  var { x : { z1 }, y2} = { x : {}, y2 : 42 }
+  assertSame(undefined, z1);
+  assertSame(42, y2);
+}());
+
+
+(function TestFailingMatchesStrict() {
+  'use strict';
+  var {x, y} = {};
+  assertSame(undefined, x);
+  assertSame(undefined, y);
+
+  var { x : { z1 }, y2} = { x : {}, y2 : 42 }
+  assertSame(undefined, z1);
+  assertSame(42, y2);
+
+  {
+    let {x1,y1} = {};
+    assertSame(undefined, x1);
+    assertSame(undefined, y1);
+
+    let { x : { z1 }, y2} = { x : {}, y2 : 42 }
+    assertSame(undefined, z1);
+    assertSame(42, y2);
+  }
+}());
+
+
+(function TestTDZInIntializers() {
+  'use strict';
+  {
+    let {x, y = x} = {x : 42, y : 27};
+    assertSame(42, x);
+    assertSame(27, y);
+  }
+
+  {
+    let {x, y = x + 1} = { x : 42 };
+    assertSame(42, x);
+    assertSame(43, y);
+  }
+  assertThrows(function() {
+    let {x = y, y} = { y : 42 };
+  }, ReferenceError);
+
+  {
+    let {x, y = eval("x+1")} = {x:42};
+    assertEquals(42, x);
+    assertEquals(43, y);
+  }
+
+  {
+    let {x, y = () => eval("x+1")} = {x:42};
+    assertEquals(42, x);
+    assertEquals(43, y());
+  }
+
+  {
+    let {x = function() {return y+1;}, y} = {y:42};
+    assertEquals(43, x());
+    assertEquals(42, y);
+  }
+  {
+    let {x = function() {return eval("y+1");}, y} = {y:42};
+    assertEquals(43, x());
+    assertEquals(42, y);
+  }
+}());
+
+
+(function TestSideEffectsInInitializers() {
+  var callCount = 0;
+  function f(v) { callCount++; return v; }
+
+  callCount = 0;
+  var { x = f(42) } = { x : 27 };
+  assertSame(27, x);
+  assertEquals(0, callCount);
+
+  callCount = 0;
+  var { x = f(42) } = {};
+  assertSame(42, x);
+  assertEquals(1, callCount);
+}());
+
+
+(function TestAssignmentExprInInitializers() {
+  {
+    let x, y;
+    {
+      let { x = y = 1 } = {};
+      assertSame(x, 1);
+      assertSame(y, 1);
+    }
+    assertSame(undefined, x);
+    assertSame(1, y);
+  }
+
+  {
+    let x, y;
+    {
+      let { x: x = y = 1 } = {};
+      assertSame(1, x);
+      assertSame(1, y);
+    }
+    assertSame(undefined, x);
+    assertSame(1, y);
+  }
+
+  {
+    let x, y;
+    {
+      let [ x = y = 1 ] = [];
+      assertSame(1, x);
+      assertSame(1, y);
+    }
+    assertSame(undefined, x);
+    assertSame(1, y);
+  }
+
+  {
+    let x, y;
+    (function({ x = y = 1 }) {}({}));
+    assertSame(undefined, x);
+    assertSame(1, y);
+  }
+
+  {
+    let x, y;
+    (function({ x: x = y = 1 }) {}({}));
+    assertSame(undefined, x);
+    assertSame(1, y);
+  }
+
+  {
+    let x, y;
+    (function([ x = y = 1 ]) {}([]));
+    assertSame(undefined, x);
+    assertSame(1, y);
+  }
+}());
+
+
+(function TestMultipleAccesses() {
+  assertThrows(
+    "'use strict';"+
+    "const {x,x} = {x:1};",
+    SyntaxError);
+
+  assertThrows(
+    "'use strict';"+
+    "let {x,x} = {x:1};",
+     SyntaxError);
+
+  (function() {
+    var {x,x = 2} = {x : 1};
+    assertSame(1, x);
+  }());
+
+  assertThrows(function () {
+    'use strict';
+    let {x = (function() { x = 2; }())} = {};
+  }, ReferenceError);
+
+  (function() {
+    'use strict';
+    let {x = (function() { x = 2; }())} = {x:1};
+    assertSame(1, x);
+  }());
+}());
+
+
+(function TestComputedNames() {
+  var x = 1;
+  var {[x]:y} = {1:2};
+  assertSame(2, y);
+
+  (function(){
+    'use strict';
+    let {[x]:y} = {1:2};
+    assertSame(2, y);
+  }());
+
+  var callCount = 0;
+  function foo(v) { callCount++; return v; }
+
+  (function() {
+    callCount = 0;
+    var {[foo("abc")]:x} = {abc:42};
+    assertSame(42, x);
+    assertEquals(1, callCount);
+  }());
+
+  (function() {
+    'use strict';
+    callCount = 0;
+    let {[foo("abc")]:x} = {abc:42};
+    assertSame(42, x);
+    assertEquals(1, callCount);
+  }());
+
+  (function() {
+    callCount = 0;
+    var {[foo("abc")]:x} = {};
+    assertSame(undefined, x);
+    assertEquals(1, callCount);
+  }());
+
+  (function() {
+    'use strict';
+    callCount = 0;
+    let {[foo("abc")]:x} = {};
+    assertSame(undefined, x);
+    assertEquals(1, callCount);
+  }());
+
+  for (val of [null, undefined]) {
+    callCount = 0;
+    assertThrows(function() {
+      var {[foo()]:x} = val;
+    }, TypeError);
+    assertEquals(0, callCount);
+
+    callCount = 0;
+    assertThrows(function() {
+      'use strict';
+      let {[foo()]:x} = val;
+    }, TypeError);
+    assertEquals(0, callCount);
+  }
+
+  var log = [];
+  var o = {
+    get x() { log.push("get x"); return 1; },
+    get y() { log.push("get y"); return 2; }
+  }
+  function f(v) { log.push("f " + v); return v; }
+
+  (function() {
+    log = [];
+    var { [f('x')]:x, [f('y')]:y } = o;
+    assertSame(1, x);
+    assertSame(2, y);
+    assertArrayEquals(["f x", "get x", "f y", "get y"], log);
+  }());
+
+  (function() {
+    'use strict';
+    log = [];
+    let { [f('x')]:x, [f('y')]:y } = o;
+    assertSame(1, x);
+    assertSame(2, y);
+    assertArrayEquals(["f x", "get x", "f y", "get y"], log);
+  }());
+
+  (function() {
+    'use strict';
+    log = [];
+    const { [f('x')]:x, [f('y')]:y } = o;
+    assertSame(1, x);
+    assertSame(2, y);
+    assertArrayEquals(["f x", "get x", "f y", "get y"], log);
+  }());
+}());
+
+
+(function TestExceptions() {
+  for (var val of [null, undefined]) {
+    assertThrows(function() { var {} = val; }, TypeError);
+    assertThrows(function() { var {x} = val; }, TypeError);
+    assertThrows(function() { var { x : {} } = { x : val }; }, TypeError);
+    assertThrows(function() { 'use strict'; let {} = val; }, TypeError);
+    assertThrows(function() { 'use strict'; let {x} = val; }, TypeError);
+    assertThrows(function() { 'use strict'; let { x : {} } = { x : val }; },
+                 TypeError);
+  }
+}());
+
+
+(function TestArrayLiteral() {
+  var [a, b, c] = [1, 2, 3];
+  assertSame(1, a);
+  assertSame(2, b);
+  assertSame(3, c);
+}());
+
+(function TestIterators() {
+  var log = [];
+  function* f() {
+    log.push("1");
+    yield 1;
+    log.push("2");
+    yield 2;
+    log.push("3");
+    yield 3;
+    log.push("done");
+  };
+
+  (function() {
+    log = [];
+    var [a, b, c] = f();
+    assertSame(1, a);
+    assertSame(2, b);
+    assertSame(3, c);
+    assertArrayEquals(["1", "2", "3"], log);
+  }());
+
+  (function() {
+    log = [];
+    var [a, b, c, d] = f();
+    assertSame(1, a);
+    assertSame(2, b);
+    assertSame(3, c);
+    assertSame(undefined, d);
+    assertArrayEquals(["1", "2", "3", "done"], log);
+  }());
+
+  (function() {
+    log = [];
+    var [a, , c] = f();
+    assertSame(1, a);
+    assertSame(3, c);
+    assertArrayEquals(["1", "2", "3"], log);
+  }());
+
+  (function() {
+    log = [];
+    var [a, , c, d] = f();
+    assertSame(1, a);
+    assertSame(3, c);
+    assertSame(undefined, d);
+    assertArrayEquals(["1", "2", "3", "done"], log);
+  }());
+
+  (function() {
+    log = [];
+    // last comma is not an elision.
+    var [a, b,] = f();
+    assertSame(1, a);
+    assertSame(2, b);
+    assertArrayEquals(["1", "2"], log);
+  }());
+
+  (function() {
+    log = [];
+    // last comma is not an elision, but the comma before the last is.
+    var [a, b, ,] = f();
+    assertSame(1, a);
+    assertSame(2, b);
+    assertArrayEquals(["1", "2", "3"], log);
+  }());
+
+  (function() {
+    log = [];
+    var [a, ...rest] = f();
+    assertSame(1, a);
+    assertArrayEquals([2,3], rest);
+    assertArrayEquals(["1", "2", "3", "done"], log);
+  }());
+
+  (function() {
+    log = [];
+    var [a, b, c, ...rest] = f();
+    assertSame(1, a);
+    assertSame(2, b);
+    assertSame(3, c);
+    assertArrayEquals([], rest);
+    assertArrayEquals(["1", "2", "3", "done"], log);
+  }());
+
+  (function() {
+    log = [];
+    var [a, b, c, d, ...rest] = f();
+    assertSame(1, a);
+    assertSame(2, b);
+    assertSame(3, c);
+    assertSame(undefined, d);
+    assertArrayEquals([], rest);
+    assertArrayEquals(["1", "2", "3", "done"], log);
+  }());
+}());
+
+
+(function TestIteratorsLexical() {
+  'use strict';
+  var log = [];
+  function* f() {
+    log.push("1");
+    yield 1;
+    log.push("2");
+    yield 2;
+    log.push("3");
+    yield 3;
+    log.push("done");
+  };
+
+  (function() {
+    log = [];
+    let [a, b, c] = f();
+    assertSame(1, a);
+    assertSame(2, b);
+    assertSame(3, c);
+    assertArrayEquals(["1", "2", "3"], log);
+  }());
+
+  (function() {
+    log = [];
+    let [a, b, c, d] = f();
+    assertSame(1, a);
+    assertSame(2, b);
+    assertSame(3, c);
+    assertSame(undefined, d);
+    assertArrayEquals(["1", "2", "3", "done"], log);
+  }());
+
+  (function() {
+    log = [];
+    let [a, , c] = f();
+    assertSame(1, a);
+    assertSame(3, c);
+    assertArrayEquals(["1", "2", "3"], log);
+  }());
+
+  (function() {
+    log = [];
+    let [a, , c, d] = f();
+    assertSame(1, a);
+    assertSame(3, c);
+    assertSame(undefined, d);
+    assertArrayEquals(["1", "2", "3", "done"], log);
+  }());
+
+  (function() {
+    log = [];
+    // last comma is not an elision.
+    let [a, b,] = f();
+    assertSame(1, a);
+    assertSame(2, b);
+    assertArrayEquals(["1", "2"], log);
+  }());
+
+  (function() {
+    log = [];
+    // last comma is not an elision, but the comma before the last is.
+    let [a, b, ,] = f();
+    assertSame(1, a);
+    assertSame(2, b);
+    assertArrayEquals(["1", "2", "3"], log);
+  }());
+
+  (function() {
+    log = [];
+    let [a, ...rest] = f();
+    assertSame(1, a);
+    assertArrayEquals([2,3], rest);
+    assertArrayEquals(["1", "2", "3", "done"], log);
+  }());
+
+  (function() {
+    log = [];
+    let [a, b, c, ...rest] = f();
+    assertSame(1, a);
+    assertSame(2, b);
+    assertSame(3, c);
+    assertArrayEquals([], rest);
+    assertArrayEquals(["1", "2", "3", "done"], log);
+  }());
+
+  (function() {
+    log = [];
+    let [a, b, c, d, ...rest] = f();
+    assertSame(1, a);
+    assertSame(2, b);
+    assertSame(3, c);
+    assertSame(undefined, d);
+    assertArrayEquals([], rest);
+    assertArrayEquals(["1", "2", "3", "done"], log);
+  }());
+}());
+
+(function TestIteratorsRecursive() {
+  var log = [];
+  function* f() {
+    log.push("1");
+    yield {x : 1, y : 2};
+    log.push("2");
+    yield [42, 27, 30];
+    log.push("3");
+    yield "abc";
+    log.push("done");
+  };
+
+  (function() {
+    var [{x, y}, [a, b]] = f();
+    assertSame(1, x);
+    assertSame(2, y);
+    assertSame(42, a);
+    assertSame(27, b);
+    assertArrayEquals(["1", "2"], log);
+  }());
+
+  (function() {
+    'use strict';
+    log = [];
+    let [{x, y}, [a, b]] = f();
+    assertSame(1, x);
+    assertSame(2, y);
+    assertSame(42, a);
+    assertSame(27, b);
+    assertArrayEquals(["1", "2"], log);
+  }());
+}());
+
+
+(function TestForEachLexical() {
+  'use strict';
+  let a = [{x:1, y:-1}, {x:2,y:-2}, {x:3,y:-3}];
+  let sumX = 0;
+  let sumY = 0;
+  let fs = [];
+  for (let {x,y} of a) {
+    sumX += x;
+    sumY += y;
+    fs.push({fx : function() { return x; }, fy : function() { return y }});
+  }
+  assertSame(6, sumX);
+  assertSame(-6, sumY);
+  assertSame(3, fs.length);
+  for (let i = 0; i < fs.length; i++) {
+    let {fx,fy} = fs[i];
+    assertSame(i+1, fx());
+    assertSame(-(i+1), fy());
+  }
+
+  var o = { __proto__:null, 'a1':1, 'b2':2 };
+  let sx = '';
+  let sy = '';
+  for (let [x,y] in o) {
+    sx += x;
+    sy += y;
+  }
+  assertEquals('ab', sx);
+  assertEquals('12', sy);
+}());
+
+
+(function TestForEachVars() {
+  var a = [{x:1, y:-1}, {x:2,y:-2}, {x:3,y:-3}];
+  var sumX = 0;
+  var sumY = 0;
+  var fs = [];
+  for (var {x,y} of a) {
+    sumX += x;
+    sumY += y;
+    fs.push({fx : function() { return x; }, fy : function() { return y }});
+  }
+  assertSame(6, sumX);
+  assertSame(-6, sumY);
+  assertSame(3, fs.length);
+  for (var i = 0; i < fs.length; i++) {
+    var {fx,fy} = fs[i];
+    assertSame(3, fx());
+    assertSame(-3, fy());
+  }
+
+  var o = { __proto__:null, 'a1':1, 'b2':2 };
+  var sx = '';
+  var sy = '';
+  for (var [x,y] in o) {
+    sx += x;
+    sy += y;
+  }
+  assertEquals('ab', sx);
+  assertEquals('12', sy);
+}());
+
+
+(function TestParameters() {
+  function f({a, b}) { return a - b; }
+  assertEquals(1, f({a : 6, b : 5}));
+
+  function f1(c, {a, b}) { return c + a - b; }
+  assertEquals(8, f1(7, {a : 6, b : 5}));
+
+  function f2({c, d}, {a, b}) { return c - d + a - b; }
+  assertEquals(7, f2({c : 7, d : 1}, {a : 6, b : 5}));
+
+  function f3([{a, b}]) { return a - b; }
+  assertEquals(1, f3([{a : 6, b : 5}]));
+
+  var g = ({a, b}) => { return a - b; };
+  assertEquals(1, g({a : 6, b : 5}));
+
+  var g1 = (c, {a, b}) => { return c + a - b; };
+  assertEquals(8, g1(7, {a : 6, b : 5}));
+
+  var g2 = ({c, d}, {a, b}) => { return c - d + a - b; };
+  assertEquals(7, g2({c : 7, d : 1}, {a : 6, b : 5}));
+
+  var g3 = ([{a, b}]) => { return a - b; };
+  assertEquals(1, g3([{a : 6, b : 5}]));
+}());
+
+
+(function TestExpressionsInParameters() {
+  function f0(x = eval(0)) { return x }
+  assertEquals(0, f0());
+  function f1({a = eval(1)}) { return a }
+  assertEquals(1, f1({}));
+  function f2([x = eval(2)]) { return x }
+  assertEquals(2, f2([]));
+  function f3({[eval(7)]: x}) { return x }
+  assertEquals(3, f3({7: 3}));
+})();
+
+
+(function TestParameterScoping() {
+  var x = 1;
+
+  function f1({a = x}) { var x = 2; return a; }
+  assertEquals(1, f1({}));
+  function f2({a = x}) { function x() {}; return a; }
+  assertEquals(1, f2({}));
+  (function() {
+    'use strict';
+    function f3({a = x}) { let x = 2; return a; }
+    assertEquals(1, f3({}));
+    function f4({a = x}) { const x = 2; return a; }
+    assertEquals(1, f4({}));
+    function f5({a = x}) { function x() {}; return a; }
+    assertEquals(1, f5({}));
+  })();
+  function f6({a = eval("x")}) { var x; return a; }
+  assertEquals(1, f6({}));
+  (function() {
+    'use strict';
+    function f61({a = eval("x")}) { var x; return a; }
+    assertEquals(1, f61({}));
+  })();
+  function f62({a = eval("'use strict'; x")}) { var x; return a; }
+  assertEquals(1, f62({}));
+  function f7({a = function() { return x }}) { var x; return a(); }
+  assertEquals(1, f7({}));
+  function f8({a = () => x}) { var x; return a(); }
+  assertEquals(1, f8({}));
+  function f9({a = () => eval("x")}) { var x; return a(); }
+  assertEquals(1, f9({}));
+  (function TestInitializedWithEvalArrowStrict() {
+    'use strict';
+    function f91({a = () => eval("x")}) { var x; return a(); }
+    assertEquals(1, f91({}));
+  })();
+  function f92({a = () => { 'use strict'; return eval("x") }}) { var x; return a(); }
+  assertEquals(1, f92({}));
+  function f93({a = () => eval("'use strict'; x")}) { var x; return a(); }
+  assertEquals(1, f93({}));
+
+  var g1 = ({a = x}) => { var x = 2; return a; };
+  assertEquals(1, g1({}));
+  var g2 = ({a = x}) => { function x() {}; return a; };
+  assertEquals(1, g2({}));
+  (function() {
+    'use strict';
+    var g3 = ({a = x}) => { let x = 2; return a; };
+    assertEquals(1, g3({}));
+    var g4 = ({a = x}) => { const x = 2; return a; };
+    assertEquals(1, g4({}));
+    var g5 = ({a = x}) => { function x() {}; return a; };
+    assertEquals(1, g5({}));
+  })();
+  var g6 = ({a = eval("x")}) => { var x; return a; };
+  assertEquals(1, g6({}));
+  (function() {
+    'use strict';
+    var g61 = ({a = eval("x")}) => { var x; return a; };
+    assertEquals(1, g61({}));
+  })();
+  var g62 = ({a = eval("'use strict'; x")}) => { var x; return a; };
+  assertEquals(1, g62({}));
+  var g7 = ({a = function() { return x }}) => { var x; return a(); };
+  assertEquals(1, g7({}));
+  var g8 = ({a = () => x}) => { var x; return a(); };
+  assertEquals(1, g8({}));
+  var g9 = ({a = () => eval("x")}) => { var x; return a(); };
+  assertEquals(1, g9({}));
+  (function() {
+    'use strict';
+    var g91 = ({a = () => eval("x")}) => { var x; return a(); };
+    assertEquals(1, g91({}));
+    var g92 = ({a = () => { return eval("x") }}) => { var x; return a(); };
+    assertEquals(1, g92({}));
+  })();
+  var g93 = ({a = () => eval("'use strict'; x")}) => { var x; return a(); };
+  assertEquals(1, g93({}));
+
+  var f11 = function f({x = f}) { var f; return x; }
+  assertSame(f11, f11({}));
+  var f12 = function f({x = f}) { function f() {}; return x; }
+  assertSame(f12, f12({}));
+  (function() {
+    'use strict';
+    var f13 = function f({x = f}) { let f; return x; }
+    assertSame(f13, f13({}));
+    var f14 = function f({x = f}) { const f = 0; return x; }
+    assertSame(f14, f14({}));
+    var f15 = function f({x = f}) { function f() {}; return x; }
+    assertSame(f15, f15({}));
+  })();
+  var f16 = function f({f = 7, x = f}) { return x; }
+  assertSame(7, f16({}));
+
+  var y = 'a';
+  function f20({[y]: x}) { var y = 'b'; return x; }
+  assertEquals(1, f20({a: 1, b: 2}));
+  function f21({[eval('y')]: x}) { var y = 'b'; return x; }
+  assertEquals(1, f21({a: 1, b: 2}));
+  var g20 = ({[y]: x}) => { var y = 'b'; return x; };
+  assertEquals(1, g20({a: 1, b: 2}));
+  var g21 = ({[eval('y')]: x}) => { var y = 'b'; return x; };
+  assertEquals(1, g21({a: 1, b: 2}));
+})();
+
+
+(function TestParameterDestructuringTDZ() {
+  function f1({a = x}, x) { return a }
+  assertThrows(() => f1({}, 4), ReferenceError);
+  assertEquals(4, f1({a: 4}, 5));
+  function f2({a = eval("x")}, x) { return a }
+  assertThrows(() => f2({}, 4), ReferenceError);
+  assertEquals(4, f2({a: 4}, 5));
+  (function() {
+    'use strict';
+    function f3({a = eval("x")}, x) { return a }
+    assertThrows(() => f3({}, 4), ReferenceError);
+    assertEquals(4, f3({a: 4}, 5));
+  })();
+  function f4({a = eval("'use strict'; x")}, x) { return a }
+  assertThrows(() => f4({}, 4), ReferenceError);
+  assertEquals(4, f4({a: 4}, 5));
+
+  function f5({a = () => x}, x) { return a() }
+  assertEquals(4, f5({a: () => 4}, 5));
+  function f6({a = () => eval("x")}, x) { return a() }
+  assertEquals(4, f6({a: () => 4}, 5));
+  (function() {
+    'use strict';
+    function f7({a = () => eval("x")}, x) { return a() }
+    assertEquals(4, f7({a: () => 4}, 5));
+  })();
+  function f8({a = () => eval("'use strict'; x")}, x) { return a() }
+  assertEquals(4, f8({a: () => 4}, 5));
+
+  function f11({a = b}, {b}) { return a }
+  assertThrows(() => f11({}, {b: 4}), ReferenceError);
+  assertEquals(4, f11({a: 4}, {b: 5}));
+  function f12({a = eval("b")}, {b}) { return a }
+  assertThrows(() => f12({}, {b: 4}), ReferenceError);
+  assertEquals(4, f12({a: 4}, {b: 5}));
+  (function() {
+    'use strict';
+    function f13({a = eval("b")}, {b}) { return a }
+    assertThrows(() => f13({}, {b: 4}), ReferenceError);
+    assertEquals(4, f13({a: 4}, {b: 5}));
+  })();
+  function f14({a = eval("'use strict'; b")}, {b}) { return a }
+  assertThrows(() => f14({}, {b: 4}), ReferenceError);
+  assertEquals(4, f14({a: 4}, {b: 5}));
+
+  function f15({a = () => b}, {b}) { return a() }
+  assertEquals(4, f15({a: () => 4}, {b: 5}));
+  function f16({a = () => eval("b")}, {b}) { return a() }
+  assertEquals(4, f16({a: () => 4}, {b: 5}));
+  (function() {
+    'use strict';
+    function f17({a = () => eval("b")}, {b}) { return a() }
+    assertEquals(4, f17({a: () => 4}, {b: 5}));
+  })();
+  function f18({a = () => eval("'use strict'; b")}, {b}) { return a() }
+  assertEquals(4, f18({a: () => 4}, {b: 5}));
+
+  // TODO(caitp): TDZ for rest parameters is not working yet.
+  // function f30({x = a}, ...a) { return x[0] }
+  // assertThrows(() => f30({}), ReferenceError);
+  // assertEquals(4, f30({a: [4]}, 5));
+  // function f31({x = eval("a")}, ...a) { return x[0] }
+  // assertThrows(() => f31({}), ReferenceError);
+  // assertEquals(4, f31({a: [4]}, 5));
+  // function f32({x = eval("a")}, ...a) { 'use strict'; return x[0] }
+  // assertThrows(() => f32({}), ReferenceError);
+  // assertEquals(4, f32({a: [4]}, 5));
+  // function f33({x = eval("'use strict'; a")}, ...a) { return x[0] }
+  // assertThrows(() => f33({}), ReferenceError);
+  // assertEquals(4, f33({a: [4]}, 5));
+
+  function f34({x = function() { return a }}, ...a) { return x()[0] }
+  assertEquals(4, f34({}, 4));
+  function f35({x = () => a}, ...a) { return x()[0] }
+  assertEquals(4, f35({}, 4));
+  function f36({x = () => eval("a")}, ...a) { return x()[0] }
+  assertEquals(4, f36({}, 4));
+  (function() {
+    'use strict';
+    function f37({x = () => eval("a")}, ...a) { return x()[0] }
+    assertEquals(4, f37({}, 4));
+  })();
+  function f38({x = () => { 'use strict'; return eval("a") }}, ...a) { return x()[0] }
+  assertEquals(4, f38({}, 4));
+  function f39({x = () => eval("'use strict'; a")}, ...a) { return x()[0] }
+  assertEquals(4, f39({}, 4));
+
+  // var g30 = ({x = a}, ...a) => {};
+  // assertThrows(() => g30({}), ReferenceError);
+  // var g31 = ({x = eval("a")}, ...a) => {};
+  // assertThrows(() => g31({}), ReferenceError);
+  // var g32 = ({x = eval("a")}, ...a) => { 'use strict'; };
+  // assertThrows(() => g32({}), ReferenceError);
+  // var g33 = ({x = eval("'use strict'; a")}, ...a) => {};
+  // assertThrows(() => g33({}), ReferenceError);
+  var g34 = ({x = function() { return a }}, ...a) => { return x()[0] };
+  assertEquals(4, g34({}, 4));
+  var g35 = ({x = () => a}, ...a) => { return x()[0] };
+  assertEquals(4, g35({}, 4));
+})();
+
+
+(function TestDuplicatesInParameters() {
+  assertThrows("'use strict';function f(x,x){}", SyntaxError);
+  assertThrows("'use strict';function f({x,x}){}", SyntaxError);
+  assertThrows("'use strict';function f(x, {x}){}", SyntaxError);
+  assertThrows("'use strict';var f = (x,x) => {};", SyntaxError);
+  assertThrows("'use strict';var f = ({x,x}) => {};", SyntaxError);
+  assertThrows("'use strict';var f = (x, {x}) => {};", SyntaxError);
+
+  function ok1(x) { var x; return x; };
+  assertEquals(1, ok1(1));
+  function ok2(x) { 'use strict'; { let x = 2; return x; } };
+  assertEquals(2, ok2(1));
+}());
+
+
+(function TestShadowingOfParameters() {
+  function f1({x}) { var x = 2; return x }
+  assertEquals(2, f1({x: 1}));
+  function f2({x}) { { var x = 2; } return x; }
+  assertEquals(2, f2({x: 1}));
+  function f3({x}) { var y = x; var x = 2; return y; }
+  assertEquals(1, f3({x: 1}));
+  function f4({x}) { { var y = x; var x = 2; } return y; }
+  assertEquals(1, f4({x: 1}));
+  function f5({x}, g = () => x) { var x = 2; return g(); }
+  assertEquals(1, f5({x: 1}));
+  function f6({x}, g = () => x) { { var x = 2; } return g(); }
+  assertEquals(1, f6({x: 1}));
+  function f7({x}) { var g = () => x; var x = 2; return g(); }
+  assertEquals(2, f7({x: 1}));
+  function f8({x}) { { var g = () => x; var x = 2; } return g(); }
+  assertEquals(2, f8({x: 1}));
+  function f9({x}, g = () => eval("x")) { var x = 2; return g(); }
+  assertEquals(1, f9({x: 1}));
+
+  function f10({x}, y) { var y; return y }
+  assertEquals(2, f10({x: 6}, 2));
+  function f11({x}, y) { var z = y; var y = 2; return z; }
+  assertEquals(1, f11({x: 6}, 1));
+  function f12(y, g = () => y) { var y = 2; return g(); }
+  assertEquals(1, f12(1));
+  function f13({x}, y, [z], v) { var x, y, z; return x*y*z*v }
+  assertEquals(210, f13({x: 2}, 3, [5], 7));
+
+  function f20({x}) { function x() { return 2 }; return x(); }
+  assertEquals(2, f20({x: 1}));
+  // Function hoisting is blocked by the conflicting x declaration
+  function f21({x}) { { function x() { return 2 } } return x(); }
+  assertThrows(() => f21({x: 1}), TypeError);
+
+  var g1 = ({x}) => { var x = 2; return x };
+  assertEquals(2, g1({x: 1}));
+  var g2 = ({x}) => { { var x = 2; } return x; };
+  assertEquals(2, g2({x: 1}));
+  var g3 = ({x}) => { var y = x; var x = 2; return y; };
+  assertEquals(1, g3({x: 1}));
+  var g4 = ({x}) => { { var y = x; var x = 2; } return y; };
+  assertEquals(1, g4({x: 1}));
+  var g5 = ({x}, g = () => x) => { var x = 2; return g(); };
+  assertEquals(1, g5({x: 1}));
+  var g6 = ({x}, g = () => x) => { { var x = 2; } return g(); };
+  assertEquals(1, g6({x: 1}));
+  var g7 = ({x}) => { var g = () => x; var x = 2; return g(); };
+  assertEquals(2, g7({x: 1}));
+  var g8 = ({x}) => { { var g = () => x; var x = 2; } return g(); };
+  assertEquals(2, g8({x: 1}));
+  var g9 = ({x}, g = () => eval("x")) => { var x = 2; return g(); };
+  assertEquals(1, g9({x: 1}));
+
+  var g10 = ({x}, y) => { var y; return y };
+  assertEquals(2, g10({x: 6}, 2));
+  var g11 = ({x}, y) => { var z = y; var y = 2; return z; };
+  assertEquals(1, g11({x: 6}, 1));
+  var g12 = (y, g = () => y) => { var y = 2; return g(); };
+  assertEquals(1, g12(1));
+  var g13 = ({x}, y, [z], v) => { var x, y, z; return x*y*z*v };
+  assertEquals(210, g13({x: 2}, 3, [5], 7));
+
+  var g20 = ({x}) => { function x() { return 2 }; return x(); }
+  assertEquals(2, g20({x: 1}));
+  var g21 = ({x}) => { { function x() { return 2 } } return x(); }
+  assertThrows(() => g21({x: 1}), TypeError);
+
+  assertThrows("'use strict'; function f(x) { let x = 0; }; f({});", SyntaxError);
+  assertThrows("'use strict'; function f({x}) { let x = 0; }; f({});", SyntaxError);
+  assertThrows("'use strict'; function f(x) { const x = 0; }; f({});", SyntaxError);
+  assertThrows("'use strict'; function f({x}) { const x = 0; }; f({});", SyntaxError);
+
+  assertThrows("'use strict'; let g = (x) => { let x = 0; }; f({});", SyntaxError);
+  assertThrows("'use strict'; let g = ({x}) => { let x = 0; }; f({});", SyntaxError);
+  assertThrows("'use strict'; let g = (x) => { const x = 0; }; f({});", SyntaxError);
+  assertThrows("'use strict'; let g = ({x}) => { const x = 0; }; f({});", SyntaxError);
+}());
+
+
+(function TestArgumentsForNonSimpleParameters() {
+  function f1({}, x) { arguments[1] = 0; return x }
+  assertEquals(6, f1({}, 6));
+  function f2({}, x) { x = 2; return arguments[1] }
+  assertEquals(7, f2({}, 7));
+  function f3(x, {}) { arguments[0] = 0; return x }
+  assertEquals(6, f3(6, {}));
+  function f4(x, {}) { x = 2; return arguments[0] }
+  assertEquals(7, f4(7, {}));
+  function f5(x, ...a) { arguments[0] = 0; return x }
+  assertEquals(6, f5(6, {}));
+  function f6(x, ...a) { x = 2; return arguments[0] }
+  assertEquals(6, f6(6, {}));
+  function f7({a: x}) { x = 2; return arguments[0].a }
+  assertEquals(5, f7({a: 5}));
+  function f8(x, ...a) { a = []; return arguments[1] }
+  assertEquals(6, f8(5, 6));
+}());
+
+
+(function TestForInOfTDZ() {
+  assertThrows("'use strict'; let x = {}; for (let [x, y] of [x]);", ReferenceError);
+  assertThrows("'use strict'; let x = {}; for (let [y, x] of [x]);", ReferenceError);
+  assertThrows("'use strict'; let x = {}; for (let [x, y] in {x});", ReferenceError);
+  assertThrows("'use strict'; let x = {}; for (let [y, x] in {x});", ReferenceError);
+}());
+
+
+(function TestFunctionLength() {
+   assertEquals(1, (function({}) {}).length);
+   assertEquals(1, (function([]) {}).length);
+   assertEquals(1, (function({x}) {}).length);
+   assertEquals(1, (function({}, ...a) {}).length);
+   assertEquals(1, (function({x}, {y} = {}) {}).length);
+   assertEquals(1, (function({x}, {y} = {}, ...a) {}).length);
+   assertEquals(2, (function(x, {y}, {z} = {}) {}).length);
+   assertEquals(2, (function({x}, {}, {z} = {}, ...a) {}).length);
+   assertEquals(1, (function(x, {y} = {}, {z}) {}).length);
+   assertEquals(1, (function({x}, {y} = {}, {z}, ...a) {}).length);
+   assertEquals(1, (function(x, {y} = {}, {z}, {v} = {}) {}).length);
+   assertEquals(1, (function({x}, {y} = {}, {z}, {v} = {}, ...a) {}).length);
+})();
+
+
+(function TestDirectiveThrows() {
+  "use strict";
+
+  assertThrows(function(){ eval("function({}){'use strict';}") }, SyntaxError);
+  assertThrows(function(){ eval("({}) => {'use strict';}") }, SyntaxError);
+  assertThrows(
+    function(){ eval("(class{foo({}) {'use strict';}});") }, SyntaxError);
+
+  assertThrows(
+    function(){ eval("function(a, {}){'use strict';}") }, SyntaxError);
+  assertThrows(function(){ eval("(a, {}) => {'use strict';}") }, SyntaxError);
+  assertThrows(
+    function(){ eval("(class{foo(a, {}) {'use strict';}});") }, SyntaxError);
+})();
+
+
+(function TestLegacyConstDestructuringInForLoop() {
+  var result;
+  for (const {foo} of [{foo: 1}]) { result = foo; }
+  assertEquals(1, result);
+})();
+
+
+(function TestCatch() {
+  "use strict";
+
+  // For testing proper scoping.
+  var foo = "hello", bar = "world", baz = 42;
+
+  try {
+    throw {foo: 1, bar: 2};
+  } catch ({foo, bar, baz = 3}) {
+    assertEquals(1, foo);
+    assertEquals(2, bar);
+    assertEquals(3, baz);
+  }
+
+  try {
+    throw [1, 2, 3];
+  } catch ([foo, ...bar]) {
+    assertEquals(1, foo);
+    assertEquals([2, 3], bar);
+  }
+
+  assertEquals("hello", foo);
+  assertEquals("world", bar);
+  assertEquals(42, baz);
+
+  assertEquals(undefined, eval('try {throw {foo: 1, bar: 2}} catch({foo}) {}'));
+  assertEquals(undefined, eval('try {throw [1, 2, 3]} catch([x]) {}'));
+})();
diff --git a/test/mjsunit/es6/generators-objects.js b/test/mjsunit/es6/generators-objects.js
index f304738..a0c3b80 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 --harmony-tostring
+// Flags: --allow-natives-syntax
 
 // Test instantations of generators.
 
diff --git a/test/mjsunit/es6/instanceof-proxies.js b/test/mjsunit/es6/instanceof-proxies.js
index cc720ad..86b104c 100644
--- a/test/mjsunit/es6/instanceof-proxies.js
+++ b/test/mjsunit/es6/instanceof-proxies.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 
-// Flags: --harmony-proxies --allow-natives-syntax
+// Flags: --allow-natives-syntax
 
 // Test instanceof with proxies.
 
diff --git a/test/mjsunit/es6/iteration-semantics.js b/test/mjsunit/es6/iteration-semantics.js
index 6466ac5..558fb83 100644
--- a/test/mjsunit/es6/iteration-semantics.js
+++ b/test/mjsunit/es6/iteration-semantics.js
@@ -25,8 +25,6 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Flags: --harmony-proxies
-
 // Test for-of semantics.
 
 "use strict";
diff --git a/test/mjsunit/es6/json.js b/test/mjsunit/es6/json.js
index 3fad083..4c1ada8 100644
--- a/test/mjsunit/es6/json.js
+++ b/test/mjsunit/es6/json.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-tostring
-
 function testJSONToString() {
   assertEquals('[object JSON]', "" + JSON);
   assertEquals("JSON", JSON[Symbol.toStringTag]);
diff --git a/test/mjsunit/es6/math-trunc.js b/test/mjsunit/es6/math-trunc.js
index 9231576..c925b5b 100644
--- a/test/mjsunit/es6/math-trunc.js
+++ b/test/mjsunit/es6/math-trunc.js
@@ -25,25 +25,78 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-assertEquals("Infinity", String(1/Math.trunc(0)));
-assertEquals("-Infinity", String(1/Math.trunc(-0)));
-assertEquals("Infinity", String(1/Math.trunc(Math.PI/4)));
-assertEquals("-Infinity", String(1/Math.trunc(-Math.sqrt(2)/2)));
-assertEquals(100, Math.trunc(100));
-assertEquals(-199, Math.trunc(-199));
-assertEquals(100, Math.trunc(100.1));
-assertTrue(isNaN(Math.trunc("abc")));
-assertTrue(isNaN(Math.trunc({})));
-assertEquals(0, Math.trunc([]));
-assertEquals(1, Math.trunc([1]));
-assertEquals(-100, Math.trunc([-100.1]));
-assertTrue(isNaN(Math.trunc([1, 1])));
-assertEquals(-100, Math.trunc({ toString: function() { return "-100.3"; } }));
-assertEquals(10, Math.trunc({ toString: function() { return 10.1; } }));
-assertEquals(-1, Math.trunc({ valueOf: function() { return -1.1; } }));
-assertEquals("-Infinity",
-             String(1/Math.trunc({ valueOf: function() { return "-0.1"; } })));
-assertEquals("-Infinity", String(Math.trunc(-Infinity)));
-assertEquals("Infinity", String(Math.trunc(Infinity)));
-assertEquals("-Infinity", String(Math.trunc("-Infinity")));
-assertEquals("Infinity", String(Math.trunc("Infinity")));
+// Flags: --allow-natives-syntax
+
+var test_id = 0;
+
+function testTrunc(expected, input) {
+  var test = new Function('n',
+                          '"' + (test_id++) + '";return Math.trunc(n)');
+  assertEquals(expected, test(input));
+  assertEquals(expected, test(input));
+  assertEquals(expected, test(input));
+  %OptimizeFunctionOnNextCall(test);
+  assertEquals(expected, test(input));
+
+  var test_double_input = new Function(
+      'n',
+      '"' + (test_id++) + '";return Math.trunc(+n)');
+  assertEquals(expected, test_double_input(input));
+  assertEquals(expected, test_double_input(input));
+  assertEquals(expected, test_double_input(input));
+  %OptimizeFunctionOnNextCall(test_double_input);
+  assertEquals(expected, test_double_input(input));
+
+  var test_double_output = new Function(
+      'n',
+      '"' + (test_id++) + '";return Math.trunc(n) + -0.0');
+  assertEquals(expected, test_double_output(input));
+  assertEquals(expected, test_double_output(input));
+  assertEquals(expected, test_double_output(input));
+  %OptimizeFunctionOnNextCall(test_double_output);
+  assertEquals(expected, test_double_output(input));
+}
+
+function test() {
+  // Ensure that a negative zero coming from Math.trunc is properly handled
+  // by other operations.
+  function itrunc(x) {
+    return 1 / Math.trunc(x);
+  }
+  assertEquals(Infinity, itrunc(0));
+  assertEquals(-Infinity, itrunc(-0));
+  assertEquals(Infinity, itrunc(Math.PI / 4));
+  assertEquals(-Infinity, itrunc(-Math.sqrt(2) / 2));
+  assertEquals(-Infinity, itrunc({valueOf: function() { return "-0.1"; }}));
+  %OptimizeFunctionOnNextCall(itrunc);
+
+  testTrunc(100, 100);
+  testTrunc(-199, -199);
+  testTrunc(100, 100.1);
+  testTrunc(4503599627370495.0, 4503599627370495.0);
+  testTrunc(4503599627370496.0, 4503599627370496.0);
+  testTrunc(-4503599627370495.0, -4503599627370495.0);
+  testTrunc(-4503599627370496.0, -4503599627370496.0);
+  testTrunc(9007199254740991.0, 9007199254740991.0);
+  testTrunc(-9007199254740991.0, -9007199254740991.0);
+  testTrunc(0, []);
+  testTrunc(1, [1]);
+  testTrunc(-100, [-100.1]);
+  testTrunc(-100, {toString: function() { return "-100.3"; }});
+  testTrunc(10, {toString: function() { return 10.1; }});
+  testTrunc(-1, {valueOf: function() { return -1.1; }});
+  testTrunc(-Infinity, -Infinity);
+  testTrunc(Infinity, Infinity);
+  testTrunc(-Infinity, "-Infinity");
+  testTrunc(Infinity, "Infinity");
+
+  assertTrue(isNaN(Math.trunc("abc")));
+  assertTrue(isNaN(Math.trunc({})));
+  assertTrue(isNaN(Math.trunc([1, 1])));
+}
+
+// Test in a loop to cover the custom IC and GC-related issues.
+for (var i = 0; i < 10; i++) {
+  test();
+  new Array(i * 10000);
+}
diff --git a/test/mjsunit/es6/math.js b/test/mjsunit/es6/math.js
index 3f76f11..cb43bd5 100644
--- a/test/mjsunit/es6/math.js
+++ b/test/mjsunit/es6/math.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-tostring
-
 function testMathToString() {
   assertEquals('[object Math]', "" + Math);
   assertEquals("Math", Math[Symbol.toStringTag]);
diff --git a/test/mjsunit/es6/new-target.js b/test/mjsunit/es6/new-target.js
index 8a06ff6..4be1254 100644
--- a/test/mjsunit/es6/new-target.js
+++ b/test/mjsunit/es6/new-target.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-reflect --harmony-destructuring-bind
-
 
 (function TestClass() {
   'use strict';
diff --git a/test/mjsunit/es6/no-unicode-regexp-flag.js b/test/mjsunit/es6/no-unicode-regexp-flag.js
index 035627c..82d070e 100644
--- a/test/mjsunit/es6/no-unicode-regexp-flag.js
+++ b/test/mjsunit/es6/no-unicode-regexp-flag.js
@@ -7,7 +7,7 @@
 // mjsunit/es6/regexp-flags tests that the property is there when the
 // flag is on.
 
-// Flags: --harmony-regexps --no-harmony-unicode-regexps
+// Flags: --no-harmony-unicode-regexps
 
 'use strict';
 
diff --git a/test/mjsunit/es6/object-tostring.js b/test/mjsunit/es6/object-tostring.js
index 4d6090f..29d07f2 100644
--- a/test/mjsunit/es6/object-tostring.js
+++ b/test/mjsunit/es6/object-tostring.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-tostring --harmony-proxies
-
 var global = this;
 
 var funs = {
diff --git a/test/mjsunit/es6/pattern-brand-check.js b/test/mjsunit/es6/pattern-brand-check.js
new file mode 100644
index 0000000..9b0c011
--- /dev/null
+++ b/test/mjsunit/es6/pattern-brand-check.js
@@ -0,0 +1,54 @@
+// 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-subclass
+
+function createNonRegExp(calls) {
+  return {
+    get [Symbol.match]() {
+      calls.push("@@match");
+      return undefined;
+    },
+    get [Symbol.replace]() {
+      calls.push("@@replace");
+      return undefined;
+    },
+    get [Symbol.search]() {
+      calls.push("@@search");
+      return undefined;
+    },
+    get [Symbol.split]() {
+      calls.push("@@split");
+      return undefined;
+    },
+    [Symbol.toPrimitive]() {
+      calls.push("@@toPrimitive");
+      return "";
+    }
+  };
+}
+
+(function testStringMatchBrandCheck() {
+  var calls = [];
+  "".match(createNonRegExp(calls));
+  assertEquals(["@@match", "@@toPrimitive"], calls);
+})();
+
+(function testStringSearchBrandCheck() {
+  var calls = [];
+  "".search(createNonRegExp(calls));
+  assertEquals(["@@search", "@@toPrimitive"], calls);
+})();
+
+(function testStringSplitBrandCheck() {
+  var calls = [];
+  "".split(createNonRegExp(calls));
+  assertEquals(["@@split", "@@toPrimitive"], calls);
+})();
+
+(function testStringReplaceBrandCheck() {
+  var calls = [];
+  "".replace(createNonRegExp(calls), "");
+  assertEquals(["@@replace", "@@toPrimitive"], calls);
+})();
diff --git a/test/mjsunit/es6/promises.js b/test/mjsunit/es6/promises.js
index e4c8b38..4eb539c 100644
--- a/test/mjsunit/es6/promises.js
+++ b/test/mjsunit/es6/promises.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 --harmony-tostring --promise-extra
+// Flags: --allow-natives-syntax --promise-extra
 
 // Make sure we don't rely on functions patchable by monkeys.
 var call = Function.prototype.call.call.bind(Function.prototype.call)
diff --git a/test/mjsunit/es6/proxies-accesschecks.js b/test/mjsunit/es6/proxies-accesschecks.js
new file mode 100644
index 0000000..f5b90dc
--- /dev/null
+++ b/test/mjsunit/es6/proxies-accesschecks.js
@@ -0,0 +1,13 @@
+// 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 realm = Realm.create();
+
+this.__proto__ = new Proxy({}, {
+  getPrototypeOf() { assertUnreachable() },
+  get() { assertUnreachable() }
+});
+
+var other_type_error = Realm.eval(realm, "TypeError");
+assertThrows(() => Realm.eval(realm, "Realm.global(0).foo"), other_type_error);
diff --git a/test/mjsunit/es6/proxies-apply.js b/test/mjsunit/es6/proxies-apply.js
new file mode 100644
index 0000000..a94541c
--- /dev/null
+++ b/test/mjsunit/es6/proxies-apply.js
@@ -0,0 +1,120 @@
+// 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 testNonCallable() {
+  var proxy = new Proxy({},{});
+  assertThrows(function(){ proxy() }, TypeError);
+
+  var proxy2 = new Proxy(proxy, {});
+  assertThrows(function(){ proxy2() }, TypeError);
+})();
+
+(function testCallProxyFallbackNoArguments() {
+  var called = false;
+  var target = function() {
+    called = true;
+  }
+  var proxy = new Proxy(target, {});
+  assertFalse(called);
+  proxy();
+  assertTrue(called);
+
+  called = false;
+  var proxy2 = new Proxy(proxy, {});
+  assertFalse(called);
+  proxy2();
+  assertTrue(called);
+})();
+
+(function testCallProxyFallback1Argument() {
+  var called = false;
+  var target = function(a) {
+    called = true;
+    assertEquals('1', a);
+  }
+  var proxy = new Proxy(target, {});
+  assertFalse(called);
+  proxy('1');
+  assertTrue(called);
+})();
+
+(function testCallProxyFallback2Arguments() {
+  var called = false;
+  var target = function(a, b) {
+    called = true;
+    assertEquals('1', a);
+    assertEquals('2', b);
+  }
+  var proxy = new Proxy(target, {});
+  assertFalse(called);
+  proxy('1', '2');
+  assertTrue(called);
+})();
+
+(function testCallProxyFallbackChangedReceiver() {
+  var apply_receiver = {receiver:true};
+  var seen_receiver = undefined;
+  var target = function() {
+    seen_receiver = this;
+  }
+  var proxy = new Proxy(target, {});
+  assertEquals(undefined, seen_receiver);
+  Reflect.apply(proxy, apply_receiver, [1,2,3,4]);
+  assertSame(apply_receiver, seen_receiver);
+})();
+
+(function testCallProxyTrap() {
+  var called_target = false;
+  var called_handler = false;
+  var target = function(a, b) {
+    called_target = true;
+    assertEquals(1, a);
+    assertEquals(2, b);
+  }
+  var handler = {
+    apply: function(target, this_arg, args) {
+      target.apply(this_arg, args);
+      called_handler = true;
+    }
+  }
+  var proxy = new Proxy(target, handler);
+  assertFalse(called_target);
+  assertFalse(called_handler);
+  Reflect.apply(proxy, {rec:1}, [1,2]);
+  assertTrue(called_target);
+  assertTrue(called_handler);
+})();
+
+
+(function testCallProxyNonCallableTarget() {
+  var values = [NaN, 1.5, 100, /RegExp/, "string", {}, [], Symbol(),
+                new Map(), new Set(), new WeakMap(), new WeakSet()];
+  values.forEach(target => {
+    target = Object(target);
+    var proxy = new Proxy(target, { apply() { assertUnreachable(); } });
+    assertThrows(() => { proxy(); }, TypeError);
+    assertThrows(() => { ({ proxy }).proxy(); }, TypeError);
+    assertThrows(() => { Reflect.apply(proxy, null, []); }, TypeError);
+    assertThrows(() => { Reflect.apply(proxy, { proxy }, []); }, TypeError);
+    assertThrows(() => {
+          Function.prototype.call.apply(proxy, [null]);
+        }, TypeError);
+    assertThrows(() => {
+          Function.prototype.apply.apply(proxy, [null, []]);
+        }, TypeError);
+
+    var proxy_to_proxy = new Proxy(proxy, { apply() { assertUnreachable(); } });
+    assertThrows(() => { proxy_to_proxy(); }, TypeError);
+    assertThrows(() => { ({ proxy_to_proxy }).proxy_to_proxy(); }, TypeError);
+    assertThrows(() => { Reflect.apply(proxy_to_proxy, null, []); }, TypeError);
+    assertThrows(() => { Reflect.apply(proxy_to_proxy, { proxy }, []); },
+                 TypeError);
+    assertThrows(() => {
+          Function.prototype.call.apply(proxy_to_proxy, [null]);
+        }, TypeError);
+    assertThrows(() => {
+          Function.prototype.apply.apply(proxy_to_proxy, [null, []]);
+        }, TypeError);
+  });
+})();
diff --git a/test/mjsunit/es6/proxies-bind.js b/test/mjsunit/es6/proxies-bind.js
new file mode 100644
index 0000000..83876a0
--- /dev/null
+++ b/test/mjsunit/es6/proxies-bind.js
@@ -0,0 +1,135 @@
+// 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.
+
+// Tests the interaction of Function.prototype.bind with proxies.
+
+
+// (Helper)
+
+var log = [];
+var logger = {};
+var handler = new Proxy({}, logger);
+
+logger.get = function(t, trap, r) {
+  return function() {
+    log.push([trap, ...arguments]);
+    return Reflect[trap](...arguments);
+  }
+};
+
+
+// Simple case
+
+var target = function(a, b, c) { "use strict"; return this };
+var proxy = new Proxy(target, handler);
+var this_value = Symbol();
+
+log.length = 0;
+result = Function.prototype.bind.call(proxy, this_value, "foo");
+assertEquals(2, result.length);
+assertEquals(target.__proto__, result.__proto__);
+assertEquals(this_value, result());
+assertEquals(5, log.length);
+for (var i in log) assertSame(target, log[i][1]);
+assertEquals(["getPrototypeOf", target], log[0]);
+assertEquals(["getOwnPropertyDescriptor", target, "length"], log[1]);
+assertEquals(["get", target, "length", proxy], log[2]);
+assertEquals(["get", target, "name", proxy], log[3]);
+assertEquals(["apply", target, this_value, ["foo"]], log[4]);
+assertEquals(new target(), new result());
+
+
+// Custom prototype
+
+log.length = 0;
+target.__proto__ = {radio: "gaga"};
+result = Function.prototype.bind.call(proxy, this_value, "foo");
+assertEquals(2, result.length);
+assertSame(target.__proto__, result.__proto__);
+assertEquals(this_value, result());
+assertEquals(5, log.length);
+for (var i in log) assertSame(target, log[i][1]);
+assertEquals(["getPrototypeOf", target], log[0]);
+assertEquals(["getOwnPropertyDescriptor", target, "length"], log[1]);
+assertEquals(["get", target, "length", proxy], log[2]);
+assertEquals(["get", target, "name", proxy], log[3]);
+assertEquals(["apply", target, this_value, ["foo"]], log[4]);
+
+
+// Custom length
+
+handler = {
+  get() {return 42},
+  getOwnPropertyDescriptor() {return {configurable: true}}
+};
+proxy = new Proxy(target, handler);
+
+result = Function.prototype.bind.call(proxy, this_value, "foo");
+assertEquals(41, result.length);
+assertEquals(this_value, result());
+
+
+// Long length
+
+handler = {
+  get() {return Math.pow(2, 100)},
+  getOwnPropertyDescriptor() {return {configurable: true}}
+};
+proxy = new Proxy(target, handler);
+
+result = Function.prototype.bind.call(proxy, this_value, "foo");
+assertEquals(Math.pow(2, 100) - 1, result.length);
+assertEquals(this_value, result());
+
+
+// Very long length
+
+handler = {
+  get() {return 1/0},
+  getOwnPropertyDescriptor() {return {configurable: true}}
+};
+proxy = new Proxy(target, handler);
+
+result = Function.prototype.bind.call(proxy, this_value, "foo");
+assertEquals(1/0, result.length);
+assertEquals(this_value, result());
+
+
+// Non-integer length
+
+handler = {
+  get() {return 4.2},
+  getOwnPropertyDescriptor() {return {configurable: true}}
+};
+proxy = new Proxy(target, handler);
+
+result = Function.prototype.bind.call(proxy, this_value, "foo");
+assertEquals(3, result.length);
+assertEquals(this_value, result());
+
+
+// Undefined length
+
+handler = {
+  get() {},
+  getOwnPropertyDescriptor() {return {configurable: true}}
+};
+proxy = new Proxy(target, handler);
+
+result = Function.prototype.bind.call(proxy, this_value, "foo");
+assertEquals(0, result.length);
+assertEquals(this_value, result());
+
+
+// Non-callable
+
+assertThrows(() => Function.prototype.bind.call(new Proxy({}, {})), TypeError);
+assertThrows(() => Function.prototype.bind.call(new Proxy([], {})), TypeError);
+
+
+// Non-constructable
+
+result = Function.prototype.bind.call(() => 42, this_value, "foo");
+assertEquals(42, result());
+assertThrows(() => new result());
diff --git a/test/mjsunit/es6/proxies-construct.js b/test/mjsunit/es6/proxies-construct.js
new file mode 100644
index 0000000..344c50a
--- /dev/null
+++ b/test/mjsunit/es6/proxies-construct.js
@@ -0,0 +1,156 @@
+// 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 testNonConstructable() {
+  var proxy = new Proxy({},{});
+  assertThrows(function(){ new proxy() }, TypeError);
+
+  var proxy2 = new Proxy(proxy, {});
+  assertThrows(function(){ proxy2() }, TypeError);
+})();
+
+(function testFailingConstructRevoked() {
+  var pair = Proxy.revocable(Array, {});
+  var instance = new pair.proxy();
+  pair.revoke();
+  assertThrows(function(){ new pair.proxy() }, TypeError);
+})();
+
+(function testFailingGetTrap() {
+  var handler = {
+    get() {
+      throw TypeError();
+    }
+  }
+  var proxy = new Proxy({},{});
+  var proxy2 = new Proxy({}, proxy);
+  assertThrows(function(){ new proxy2() }, TypeError);
+})();
+
+(function testConstructFallback() {
+  var called = false;
+  function Target() {
+    called = true;
+    this.property1 = 'value1';
+  };
+  Target.prototype = {};
+  var proxy = new Proxy(Target, {});
+
+  assertFalse(called);
+  var instance = new proxy();
+  assertTrue(called);
+  assertEquals('value1', instance.property1);
+  assertSame(Target.prototype, Reflect.getPrototypeOf(instance));
+
+  var proxy2 = new Proxy(proxy, {});
+  called = false;
+  var instance2 = new proxy2();
+  assertTrue(called);
+  assertEquals('value1', instance2.property1);
+  assertSame(Target.prototype, Reflect.getPrototypeOf(instance));
+})();
+
+(function testConstructTrapDirectReturn() {
+  function Target(a, b) {
+      this.sum = a + b;
+  };
+  var handler = {
+      construct(t, c, args) {
+          return { sum: 42 };
+      }
+  };
+  var proxy = new Proxy(Target, handler);
+  assertEquals(42, (new proxy(1, 2)).sum);
+})();
+
+(function testConstructTrap() {
+  function Target(arg1, arg2) {
+    this.arg1 = arg1;
+    this.arg2 = arg2;
+  }
+  var seen_target, seen_arguments, seen_new_target;
+  var handler = {
+    construct(target, args, new_target) {
+      seen_target = target;
+      seen_arguments = args;
+      seen_new_target = new_target;
+      return Reflect.construct(target, args, new_target);
+    }
+  }
+  var proxy = new Proxy(Target, handler);
+  var instance = new proxy('a', 'b');
+  assertEquals(Target, seen_target);
+  assertEquals(['a','b'], seen_arguments);
+  assertEquals(proxy, seen_new_target);
+  assertEquals('a', instance.arg1);
+  assertEquals('b', instance.arg2);
+
+  var instance2 = Reflect.construct(proxy, ['a1', 'b1'], Array);
+  assertEquals(Target, seen_target);
+  assertEquals(['a1', 'b1'], seen_arguments);
+  assertEquals(Array, seen_new_target);
+  assertEquals('a1', instance2.arg1);
+  assertEquals('b1', instance2.arg2);
+})();
+
+(function testConstructCrossRealm() {
+  var realm1 = Realm.create();
+  var handler = {
+    construct(target, args, new_target) {
+      return args;
+    }
+  };
+  var OtherProxy = Realm.eval(realm1, "Proxy");
+  var otherArrayPrototype = Realm.eval(realm1, 'Array.prototype');
+
+  // Proxy and handler are from this realm.
+  var proxy = new Proxy(Array, handler);
+  var result = new proxy();
+  assertSame(Array.prototype, Reflect.getPrototypeOf(result));
+
+  // Proxy is from this realm, handler is from realm1.
+  var otherProxy = new OtherProxy(Array, handler);
+  var otherResult = new otherProxy();
+  assertSame(Array.prototype, Reflect.getPrototypeOf(otherResult));
+
+  // Proxy and handler are from realm1.
+  var otherProxy2 = Realm.eval(realm1, 'new Proxy('+
+        'Array, { construct(target, args, new_target) { return args }} )');
+  var otherResult2 = new otherProxy2();
+  assertSame(Array.prototype, Reflect.getPrototypeOf(otherResult2));
+})();
+
+(function testReflectConstructCrossReal() {
+  var realm1 = Realm.create();
+  var realm2 = Realm.create();
+  var realm3 = Realm.create();
+  var realm4 = Realm.create();
+
+  var argsRealm1 = Realm.eval(realm1, '[]');
+  var ProxyRealm2 = Realm.eval(realm2, 'Proxy');
+  var constructorRealm3 = Realm.eval(realm3, '(function(){})');
+  var handlerRealm4 = Realm.eval(realm4,
+      '({ construct(target, args, new_target) {return args} })');
+
+  var proxy = new ProxyRealm2(constructorRealm3, handlerRealm4);
+
+  // Check that the arguments array returned by handlerRealm4 is created in the
+  // realm of the Reflect.construct function.
+  var result = Reflect.construct(proxy, argsRealm1);
+  assertSame(Array.prototype, Reflect.getPrototypeOf(result));
+
+  var ReflectConstructRealm1 = Realm.eval(realm1, 'Reflect.construct');
+  var result2 = ReflectConstructRealm1(proxy, argsRealm1);
+  assertSame(Realm.eval(realm1, 'Array.prototype'),
+    Reflect.getPrototypeOf(result2));
+
+  var result3 = ReflectConstructRealm1(proxy, []);
+  assertSame(Realm.eval(realm1, 'Array.prototype'),
+    Reflect.getPrototypeOf(result3));
+
+  var ReflectConstructRealm2 = Realm.eval(realm2, 'Reflect.construct');
+  var result4 = ReflectConstructRealm2(proxy, argsRealm1);
+  assertSame(Realm.eval(realm2, 'Array.prototype'),
+    Reflect.getPrototypeOf(result4));
+})();
diff --git a/test/mjsunit/es6/proxies-cross-realm-exception.js b/test/mjsunit/es6/proxies-cross-realm-exception.js
new file mode 100644
index 0000000..ffba5c2
--- /dev/null
+++ b/test/mjsunit/es6/proxies-cross-realm-exception.js
@@ -0,0 +1,53 @@
+// 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
+
+// Do not read out the prototype from a cross-realm object.
+var realm = Realm.create();
+
+__proto__ = {};
+assertEquals(null,
+  Realm.eval(realm, "3; Reflect.getPrototypeOf(Realm.global(0))"));
+assertFalse(Realm.eval(realm, "3; Realm.global(0) instanceof Object"));
+
+__proto__ = new Proxy({}, { getPrototypeOf() { assertUnreachable() } });
+assertEquals(null,
+    Realm.eval(realm, "1; Reflect.getPrototypeOf(Realm.global(0))"));
+assertFalse(Realm.eval(realm, "1; Realm.global(0) instanceof Object"));
+
+// Test that the instannceof check works in optimized code.
+var test = Realm.eval(realm,
+    "()=>{1.1; return Realm.global(0) instanceof Object; }");
+assertFalse(test());
+test();
+test();
+%OptimizeFunctionOnNextCall(test);
+assertFalse(test());
+
+__proto__ = {};
+__proto__ = new Proxy({}, { get(t, p, r) { assertUnreachable() } });
+assertEquals(null,
+    Realm.eval(realm, "2; Reflect.getPrototypeOf(Realm.global(0))"));
+assertFalse(Realm.eval(realm, "2; Realm.global(0) instanceof Object"));
+
+
+__proto__ = {};
+__proto__.__proto__ = new Proxy({}, {
+  getPrototypeOf() { assertUnreachable() }
+});
+assertEquals(null,
+  Realm.eval(realm, "4; Reflect.getPrototypeOf(Realm.global(0))"));
+assertFalse(Realm.eval(realm, "4; Realm.global(0) instanceof Object"));
+
+// 2-level proxy indirection
+__proto__ = {};
+__proto__ = new Proxy({},
+  new Proxy({}, {
+    get() { assertUnreachable() }
+  })
+);
+assertEquals(null,
+  Realm.eval(realm, "5; Reflect.getPrototypeOf(Realm.global(0))"));
+assertFalse(Realm.eval(realm, "5; Realm.global(0) instanceof Object"));
diff --git a/test/mjsunit/es6/proxies-define-property.js b/test/mjsunit/es6/proxies-define-property.js
new file mode 100644
index 0000000..14c95bf
--- /dev/null
+++ b/test/mjsunit/es6/proxies-define-property.js
@@ -0,0 +1,82 @@
+// 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.
+
+// Check basic call to trap.
+
+var g_target, g_name, g_desc;
+var handler = {
+  defineProperty: function(target, name, desc) {
+    g_target = target;
+    g_name = name;
+    g_desc = desc;
+    return true;
+  }
+}
+var target = {}
+var proxy = new Proxy(target, handler);
+var desc = { value: 1, writable: true, configurable: true, enumerable: true };
+Object.defineProperty(proxy, "foo", desc);
+assertSame(target, g_target);
+assertEquals("foo", g_name);
+assertEquals(desc, g_desc);
+
+// Check specific steps in the spec
+
+// Step 4: revoked handler
+var pair = Proxy.revocable(target, handler);
+Object.defineProperty(proxy, "foo2", desc);
+assertSame(target, g_target);
+assertEquals("foo2", g_name);
+assertEquals(desc, g_desc);
+pair.revoke();
+assertThrows('Object.defineProperty(pair.proxy, "bar", desc);', TypeError);
+
+// Step 6: Trap isn't callable.
+handler.defineProperty = 1;
+assertThrows("Object.defineProperty(proxy, 'foo', {value: 2})", TypeError);
+
+// Step 7: Trap is undefined.
+handler.defineProperty = undefined;
+Object.defineProperty(proxy, "prop1", desc);
+assertEquals(desc, Object.getOwnPropertyDescriptor(target, "prop1"));
+var target2 = {};
+var proxy2 = new Proxy(target2, {});
+Object.defineProperty(proxy2, "prop2", desc);
+assertEquals(desc, Object.getOwnPropertyDescriptor(target2, "prop2"));
+
+// Step 9: Property name is passed to the trap as a string.
+handler.defineProperty = function(t, name, d) { g_name = name; return true; };
+Object.defineProperty(proxy, 0, desc);
+assertTrue(typeof g_name === "string");
+assertEquals("0", g_name);
+
+// Step 10: Trap returns false.
+handler.defineProperty = function(t, n, d) { return false; }
+assertThrows("Object.defineProperty(proxy, 'foo', desc)", TypeError);
+
+// Step 15a: Trap returns true for adding a property to a non-extensible target.
+handler.defineProperty = function(t, n, d) { return true; }
+Object.preventExtensions(target);
+assertThrows("Object.defineProperty(proxy, 'foo', desc)", TypeError);
+
+// Step 15b: Trap returns true for adding a non-configurable property.
+target = {};
+proxy = new Proxy(target, handler);
+desc = {value: 1, writable: true, configurable: false, enumerable: true};
+assertThrows("Object.defineProperty(proxy, 'foo', desc)", TypeError);
+// No exception is thrown if a non-configurable property exists on the target.
+Object.defineProperty(target, "nonconf",
+                      {value: 1, writable: true, configurable: false});
+Object.defineProperty(proxy, "nonconf", {value: 2, configurable: false});
+
+// Step 16a: Trap returns true for non-compatible property descriptor.
+Object.defineProperty(target, "foo",
+                      {value: 1, writable: false, configurable: false});
+assertThrows("Object.defineProperty(proxy, 'foo', {value: 2})", TypeError);
+
+// Step 16b: Trap returns true for overwriting a configurable property
+// with a non-configurable descriptor.
+target.bar = "baz";
+assertThrows("Object.defineProperty(proxy, 'bar', {configurable: false})",
+             TypeError);
diff --git a/test/mjsunit/es6/proxies-delete-property.js b/test/mjsunit/es6/proxies-delete-property.js
new file mode 100644
index 0000000..7a46b9b
--- /dev/null
+++ b/test/mjsunit/es6/proxies-delete-property.js
@@ -0,0 +1,188 @@
+// 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 properties =
+    ["bla", "0", 1, Symbol(), {[Symbol.toPrimitive]() {return "a"}}];
+
+
+function TestForwarding(handler, myDelete, shouldThrow) {
+  var target = {};
+  var proxy = new Proxy(target, handler);
+
+  assertFalse(target.hasOwnProperty("doesnotexist"));
+  assertTrue(myDelete(proxy, "doesnotexist"));
+
+  for (p of properties) {
+    target[p] = 42;
+    assertTrue(myDelete(proxy, p));
+    assertFalse(target.hasOwnProperty(p));
+  }
+
+  for (p of properties) {
+    Object.defineProperty(target, p, {value: 42, configurable: false});
+    if (shouldThrow) {
+      assertThrows(() => myDelete(proxy, p), TypeError);
+    } else {
+      assertFalse(myDelete(proxy, p));
+    }
+    assertTrue(target.hasOwnProperty(p));
+  }
+};
+
+
+(function () {
+  // No trap.
+
+  var handler = {};
+
+  TestForwarding(handler,
+      (o, p) => delete o[p], false);
+  TestForwarding(handler,
+      (o, p) => Reflect.deleteProperty(o, p), false);
+  TestForwarding(handler,
+      (o, p) => {"use strict"; return delete o[p]}, true);
+  TestForwarding(handler,
+      (o, p) => {"use strict"; return Reflect.deleteProperty(o, p)}, false);
+})();
+
+
+(function () {
+  // "Undefined" trap.
+
+  var handler = { deleteProperty: null };
+
+  TestForwarding(handler,
+      (o, p) => delete o[p], false);
+  TestForwarding(handler,
+      (o, p) => Reflect.deleteProperty(o, p), false);
+  TestForwarding(handler,
+      (o, p) => {"use strict"; return delete o[p]}, true);
+  TestForwarding(handler,
+      (o, p) => {"use strict"; return Reflect.deleteProperty(o, p)}, false);
+})();
+
+
+(function () {
+  // Invalid trap.
+
+  var target = {};
+  var handler = { deleteProperty: true };
+  var proxy = new Proxy(target, handler);
+
+  assertThrows(() => delete proxy[0], TypeError);
+  assertThrows(() => Reflect.deleteProperty(proxy, 0), TypeError);
+})();
+
+
+function TestTrappingTrueish(myDelete) {
+  var handler = { deleteProperty() {return 42} };
+  var target = {};
+  var proxy = new Proxy(target, handler);
+
+  // Trap returns trueish and target doesn't own property.
+  for (p of properties) {
+    assertTrue(myDelete(proxy, p));
+  }
+
+  // Trap returns trueish and target property is configurable.
+  for (p of properties) {
+    target[p] = 42;
+    assertTrue(myDelete(proxy, p));
+  }
+
+  // Trap returns trueish but target property is not configurable.
+  for (p of properties) {
+    Object.defineProperty(target, p, {value: 42, configurable: false});
+    assertThrows(() => myDelete(proxy, p), TypeError);
+  }
+};
+
+
+TestTrappingTrueish(
+    (o, p) => delete o[p]);
+TestTrappingTrueish(
+    (o, p) => Reflect.deleteProperty(o, p));
+TestTrappingTrueish(
+    (o, p) => {"use strict"; return delete o[p]});
+TestTrappingTrueish(
+    (o, p) => {"use strict"; return Reflect.deleteProperty(o, p)});
+
+
+function TestTrappingTrueish2(myDelete) {
+  var handler = {
+      deleteProperty(target, p) {
+          Object.defineProperty(target, p, {configurable: false});
+          return 42
+      }
+  };
+  var target = {};
+  var proxy = new Proxy(target, handler);
+
+  // Trap returns trueish but target property is not configurable.  In contrast
+  // to above, here the target property was configurable before the trap call.
+  for (p of properties) {
+    target[p] = 42;
+    assertThrows(() => myDelete(proxy, p), TypeError);
+  }
+};
+
+
+TestTrappingTrueish2(
+    (o, p) => delete o[p]);
+TestTrappingTrueish2(
+    (o, p) => Reflect.deleteProperty(o, p));
+TestTrappingTrueish2(
+    (o, p) => {"use strict"; return delete o[p]});
+TestTrappingTrueish2(
+    (o, p) => {"use strict"; return Reflect.deleteProperty(o, p)});
+
+
+function TestTrappingFalsish(myDelete, shouldThrow) {
+  var handler = { deleteProperty() {return ""} };
+  var target = {};
+  var proxy = new Proxy(target, handler);
+
+  var properties =
+      ["bla", "0", 1, Symbol(), {[Symbol.toPrimitive]() {return "a"}}];
+
+  // Trap returns falsish and target doesn't own property.
+  for (p of properties) {
+    if (shouldThrow) {
+      assertThrows(() => myDelete(proxy, p), TypeError);
+    } else {
+      assertFalse(myDelete(proxy, p));
+    }
+  }
+
+  // Trap returns falsish and target property is configurable.
+  for (p of properties) {
+    target[p] = 42;
+    if (shouldThrow) {
+      assertThrows(() => myDelete(proxy, p), TypeError);
+    } else {
+      assertFalse(myDelete(proxy, p));
+    }
+  }
+
+  // Trap returns falsish and target property is not configurable.
+  for (p of properties) {
+    Object.defineProperty(target, p, {value: 42, configurable: false});
+    if (shouldThrow) {
+      assertThrows(() => myDelete(proxy, p), TypeError);
+    } else {
+      assertFalse(myDelete(proxy, p));
+    }
+  }
+};
+
+
+TestTrappingFalsish(
+    (o, p) => delete o[p], false);
+TestTrappingFalsish(
+    (o, p) => Reflect.deleteProperty(o, p), false);
+TestTrappingFalsish(
+    (o, p) => {"use strict"; return delete o[p]}, true);
+TestTrappingFalsish(
+    (o, p) => {"use strict"; return Reflect.deleteProperty(o, p)}, false);
diff --git a/test/mjsunit/es6/proxies-example-membrane.js b/test/mjsunit/es6/proxies-example-membrane.js
new file mode 100644
index 0000000..dd373b7
--- /dev/null
+++ b/test/mjsunit/es6/proxies-example-membrane.js
@@ -0,0 +1,308 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// A simple membrane. Adapted from:
+// http://wiki.ecmascript.org/doku.php?id=harmony:proxies#a_simple_membrane
+
+function createSimpleMembrane(target) {
+  let enabled = true;
+
+  function wrap(obj) {
+    if (obj !== Object(obj)) return obj;
+
+    let handler = new Proxy({}, {get: function(_, key) {
+      if (!enabled) throw new Error("disabled");
+      switch (key) {
+      case "apply":
+        return (_, that, args) => {
+          try {
+            return wrap(Reflect.apply(
+                obj, wrap(that), args.map((x) => wrap(x))));
+          } catch(e) {
+            throw wrap(e);
+          }
+        }
+      case "construct":
+        return (_, args, newt) => {
+          try {
+            return wrap(Reflect.construct(
+                obj, args.map((x) => wrap(x)), wrap(newt)));
+          } catch(e) {
+            throw wrap(e);
+          }
+        }
+      default:
+        return (_, ...args) => {
+          try {
+            return wrap(Reflect[key](obj, ...(args.map(wrap))));
+          } catch(e) {
+            throw wrap(e);
+          }
+        }
+      }
+    }});
+
+    return new Proxy(obj, handler);
+  }
+
+  const gate = Object.freeze({
+    enable: () => enabled = true,
+    disable: () => enabled = false
+  });
+
+  return Object.freeze({
+    wrapper: wrap(target),
+    gate: gate
+  });
+}
+
+
+// Test the simple membrane.
+{
+  var o = {
+    a: 6,
+    b: {bb: 8},
+    f: function(x) { return x },
+    g: function(x) { return x.a },
+    h: function(x) { this.q = x }
+  };
+  o[2] = {c: 7};
+  var m = createSimpleMembrane(o);
+  var w = m.wrapper;
+  var f = w.f;
+  var x = f(66);
+  var x = f({a: 1});
+  var x = w.f({a: 1});
+  var a = x.a;
+  assertEquals(6, w.a);
+  assertEquals(8, w.b.bb);
+  assertEquals(7, w[2]["c"]);
+  assertEquals(undefined, w.c);
+  assertEquals(1, w.f(1));
+  assertEquals(1, w.f({a: 1}).a);
+  assertEquals(2, w.g({a: 2}));
+  assertEquals(3, (w.r = {a: 3}).a);
+  assertEquals(3, w.r.a);
+  assertEquals(3, o.r.a);
+  w.h(3);
+  assertEquals(3, w.q);
+  assertEquals(3, o.q);
+  assertEquals(4, (new w.h(4)).q);
+
+  var wb = w.b;
+  var wr = w.r;
+  var wf = w.f;
+  var wf3 = w.f(3);
+  var wfx = w.f({a: 6});
+  var wgx = w.g({a: {aa: 7}});
+  var wh4 = new w.h(4);
+  m.gate.disable();
+  assertEquals(3, wf3);
+  assertThrows(function() { w.a }, Error);
+  assertThrows(function() { w.r }, Error);
+  assertThrows(function() { w.r = {a: 4} }, Error);
+  assertThrows(function() { o.r.a }, Error);
+  assertEquals("object", typeof o.r);
+  assertEquals(5, (o.r = {a: 5}).a);
+  assertEquals(5, o.r.a);
+  assertThrows(function() { w[1] }, Error);
+  assertThrows(function() { w.c }, Error);
+  assertThrows(function() { wb.bb }, Error);
+  assertThrows(function() { wr.a }, Error);
+  assertThrows(function() { wf(4) }, Error);
+  assertThrows(function() { wfx.a }, Error);
+  assertThrows(function() { wgx.aa }, Error);
+  assertThrows(function() { wh4.q }, Error);
+
+  m.gate.enable();
+  assertEquals(6, w.a);
+  assertEquals(5, w.r.a);
+  assertEquals(5, o.r.a);
+  assertEquals(7, w.r = 7);
+  assertEquals(7, w.r);
+  assertEquals(7, o.r);
+  assertEquals(8, w.b.bb);
+  assertEquals(7, w[2]["c"]);
+  assertEquals(undefined, w.c);
+  assertEquals(8, wb.bb);
+  assertEquals(3, wr.a);
+  assertEquals(4, wf(4));
+  assertEquals(3, wf3);
+  assertEquals(6, wfx.a);
+  assertEquals(7, wgx.aa);
+  assertEquals(4, wh4.q);
+}
+
+
+
+// An identity-preserving membrane. Adapted from:
+// http://wiki.ecmascript.org/doku.php?id=harmony:proxies#an_identity-preserving_membrane
+
+function createMembrane(target) {
+  const wet2dry = 0;
+  const dry2wet = 1;
+
+  function flip(dir) { return (dir + 1) % 2 }
+
+  let maps = [new WeakMap(), new WeakMap()];
+
+  let revoked = false;
+
+  function wrap(dir, obj) {
+    if (obj !== Object(obj)) return obj;
+
+    let wrapper = maps[dir].get(obj);
+    if (wrapper) return wrapper;
+
+    let handler = new Proxy({}, {get: function(_, key) {
+      if (revoked) throw new Error("revoked");
+      switch (key) {
+      case "apply":
+        return (_, that, args) => {
+          try {
+            return wrap(dir, Reflect.apply(
+                obj, wrap(flip(dir), that),
+                args.map((x) => wrap(flip(dir), x))));
+          } catch(e) {
+            throw wrap(dir, e);
+          }
+        }
+      case "construct":
+        return (_, args, newt) => {
+          try {
+            return wrap(dir, Reflect.construct(
+                obj, args.map((x) => wrap(flip(dir), x)),
+                wrap(flip(dir), newt)));
+          } catch(e) {
+            throw wrap(dir, e);
+          }
+        }
+      default:
+        return (_, ...args) => {
+          try {
+            return wrap(dir, Reflect[key](
+                obj, ...(args.map((x) => wrap(flip(dir), x)))))
+          } catch(e) {
+            throw wrap(dir, e);
+          }
+        }
+      }
+    }});
+
+    wrapper = new Proxy(obj, handler);
+    maps[dir].set(obj, wrapper);
+    maps[flip(dir)].set(wrapper, obj);
+    return wrapper;
+  }
+
+  const gate = Object.freeze({
+    revoke: () => revoked = true
+  });
+
+  return Object.freeze({
+    wrapper: wrap(wet2dry, target),
+    gate: gate
+  });
+}
+
+
+// Test the identity-preserving membrane.
+{
+  var receiver
+  var argument
+  var o = {
+    a: 6,
+    b: {bb: 8},
+    f: function(x) {receiver = this; argument = x; return x},
+    g: function(x) {receiver = this; argument = x; return x.a},
+    h: function(x) {receiver = this; argument = x; this.q = x},
+    s: function(x) {receiver = this; argument = x; this.x = {y: x}; return this}
+  }
+  o[2] = {c: 7}
+  var m = createMembrane(o)
+  var w = m.wrapper
+  var f = w.f
+  var x = f(66)
+  var x = f({a: 1})
+  var x = w.f({a: 1})
+  var a = x.a
+  assertEquals(6, w.a)
+  assertEquals(8, w.b.bb)
+  assertEquals(7, w[2]["c"])
+  assertEquals(undefined, w.c)
+  assertEquals(1, w.f(1))
+  assertSame(o, receiver)
+  assertEquals(1, w.f({a: 1}).a)
+  assertSame(o, receiver)
+  assertEquals(2, w.g({a: 2}))
+  assertSame(o, receiver)
+  assertSame(w, w.f(w))
+  assertSame(o, receiver)
+  assertSame(o, argument)
+  assertSame(o, w.f(o))
+  assertSame(o, receiver)
+  // Note that argument !== o, since o isn't dry, so gets wrapped wet again.
+  assertEquals(3, (w.r = {a: 3}).a)
+  assertEquals(3, w.r.a)
+  assertEquals(3, o.r.a)
+  w.h(3)
+  assertEquals(3, w.q)
+  assertEquals(3, o.q)
+  assertEquals(4, (new w.h(4)).q)
+  assertEquals(5, w.s(5).x.y)
+  assertSame(o, receiver)
+
+  var wb = w.b
+  var wr = w.r
+  var wf = w.f
+  var wf3 = w.f(3)
+  var wfx = w.f({a: 6})
+  var wgx = w.g({a: {aa: 7}})
+  var wh4 = new w.h(4)
+  var ws5 = w.s(5)
+  var ws5x = ws5.x
+  m.gate.revoke()
+  assertEquals(3, wf3)
+  assertThrows(function() { w.a }, Error)
+  assertThrows(function() { w.r }, Error)
+  assertThrows(function() { w.r = {a: 4} }, Error)
+  assertThrows(function() { o.r.a }, Error)
+  assertEquals("object", typeof o.r)
+  assertEquals(5, (o.r = {a: 5}).a)
+  assertEquals(5, o.r.a)
+  assertThrows(function() { w[1] }, Error)
+  assertThrows(function() { w.c }, Error)
+  assertThrows(function() { wb.bb }, Error)
+  assertEquals(3, wr.a)
+  assertThrows(function() { wf(4) }, Error)
+  assertEquals(6, wfx.a)
+  assertEquals(7, wgx.aa)
+  assertThrows(function() { wh4.q }, Error)
+  assertThrows(function() { ws5.x }, Error)
+  assertThrows(function() { ws5x.y }, Error)
+}
diff --git a/test/mjsunit/es6/proxies-for.js b/test/mjsunit/es6/proxies-for.js
new file mode 100644
index 0000000..5b81845
--- /dev/null
+++ b/test/mjsunit/es6/proxies-for.js
@@ -0,0 +1,218 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Helper.
+
+function TestWithProxies(test, x, y, z) {
+  test(function(h){ return new Proxy({}, h) }, x, y, z)
+}
+
+
+// Iterate over a proxy.
+
+function TestForIn(properties, handler) {
+  TestWithProxies(TestForIn2, properties, handler)
+}
+
+function TestForIn2(create, properties, handler) {
+  var p = create(handler)
+  var found = []
+  for (var x in p) found.push(x)
+  assertArrayEquals(properties, found)
+}
+
+TestForIn(["0", "a"], {
+  ownKeys() { return ["0", "a"] },
+  has(target, property) { return true },
+  getOwnPropertyDescriptor() { return { enumerable: true, configurable: true }}
+})
+
+TestForIn(["null", "a"], {
+  ownKeys() { return this.enumerate() },
+  enumerate() { return ["null", "a"] },
+  has(target, property) { return true },
+  getOwnPropertyDescriptor() { return { enumerable: true, configurable: true }}
+})
+
+
+// Iterate over an object with a proxy prototype.
+
+function TestForInDerived(properties, handler) {
+  TestWithProxies(TestForInDerived2, properties, handler)
+}
+
+function TestForInDerived2(create, properties, handler) {
+  var p = create(handler)
+  var o = Object.create(p)
+  o.z = 0
+  var found = []
+  for (var x in o) found.push(x)
+  assertArrayEquals(["z"].concat(properties), found)
+
+  var oo = Object.create(o)
+  oo.y = 0
+  var found = []
+  for (var x in oo) found.push(x)
+  assertArrayEquals(["y", "z"].concat(properties), found)
+}
+
+TestForInDerived(["0", "a"], {
+  ownKeys: function() { return ["0", "a"] },
+  has: function(t, k) { return k == "0" || k == "a" },
+  getOwnPropertyDescriptor() { return { enumerable: true, configurable: true }}
+})
+
+TestForInDerived(["null", "a"], {
+  ownKeys: function() { return this.enumerate() },
+  enumerate: function() { return ["null", "a"] },
+  has: function(t, k) { return k == "null" || k == "a" },
+  getOwnPropertyDescriptor() { return { enumerable: true, configurable: true }}
+})
+
+
+
+// Throw exception in ownKeys trap.
+
+function TestForInThrow(handler) {
+  TestWithProxies(TestForInThrow2, handler)
+}
+
+function TestForInThrow2(create, handler) {
+  var p = create(handler)
+  var o = Object.create(p)
+  assertThrowsEquals(function(){ for (var x in p) {} }, "myexn")
+  assertThrowsEquals(function(){ for (var x in o) {} }, "myexn")
+}
+
+TestForInThrow({
+  ownKeys: function() { throw "myexn" }
+})
+
+TestForInThrow({
+  ownKeys: function() { return this.enumerate() },
+  enumerate: function() { throw "myexn" }
+})
+
+TestForInThrow(new Proxy({}, {
+  get: function(pr, pk) {
+    return function() { throw "myexn" }
+  }
+}));
+
+
+function keys(object) {
+  var keys = [];
+  for (var k in object) {
+    keys.push(k);
+  }
+  return keys;
+}
+
+(function testKeysProxyOnProtoEmpty() {
+  var p = new Proxy({}, {
+    ownKeys() { return []; },
+  });
+  var o = [0];
+  o.__proto__ = p;
+  assertEquals(["0"], keys(o));
+
+  delete o[0];
+  assertEquals([], keys(o));
+})();
+
+(function testKeysProxyOnProto() {
+  var handler = {ownKeys() { return ["0"]; }};
+  var proxy = new Proxy({}, handler);
+  var object = [0];
+  object.__proto__ = proxy;
+  assertEquals(["0"], keys(object));
+
+  // The Proxy doesn't set his ownKeys enumerable.
+  delete object[0];
+  assertEquals([], keys(object));
+
+  // The [[Has]] trap has no influence on which are enumerable properties are
+  // shown in for-in.
+  handler.has = function() { return true };
+  assertEquals([], keys(object));
+
+  handler.getOwnPropertyDescriptor = function() {
+    return {enumerable: true, configurable: true}
+  }
+  assertEquals(["0"], keys(object));
+})();
+
+(function testKeysProxyProto() {
+  var target = {t1:true, t2:true};
+  var handler = {};
+  var proxy = new Proxy(target, handler);
+
+  assertEquals(["t1", "t2"], keys(proxy));
+
+  target.__proto__ = {p1:true, p2:true};
+  assertEquals(["t1", "t2", "p1", "p2"], keys(proxy));
+
+  handler.getPrototypeOf = function(target) {
+    return {p3:true, p4:true};
+  };
+  // for-in walks the prototype chain for the [[Has]] / Enumerable check.
+  assertEquals(["t1", "t2", "p3", "p4"], keys(proxy));
+
+  // [[Has]] is not used in for-in.
+  handler.has = function() { return false };
+  assertEquals(["t1", "t2", "p3", "p4"], keys(proxy));
+
+  // Proxy intercepts enumerability check.
+  handler.getOwnPropertyDescriptor = function() {
+    return {enumerable: false, configurable: true}
+  }
+  assertEquals([], keys(proxy));
+
+  handler.getOwnPropertyDescriptor = function() {
+    return {enumerable: true, configurable: true}
+  }
+  assertEquals(["t1", "t2", "p3", "p4"], keys(proxy));
+
+  handler.getOwnPropertyDescriptor = function(target, key) {
+    return {
+      enumerable: key in target,
+      configurable: true
+    }
+  }
+  assertEquals(["t1", "t2"], keys(proxy));
+
+  handler.getPrototypeOf = function() { throw "error" };
+  assertThrowsEquals(() => {keys(proxy)}, "error");
+})();
+
+
+(function () {
+  var symbol = Symbol();
+  var p = new Proxy({}, {ownKeys() { return ["1", symbol, "2"] }});
+  assertEquals(["1","2"], Object.getOwnPropertyNames(p));
+  assertEquals([symbol], Object.getOwnPropertySymbols(p));
+})();
diff --git a/test/mjsunit/es6/proxies-function.js b/test/mjsunit/es6/proxies-function.js
new file mode 100644
index 0000000..cb3a26c
--- /dev/null
+++ b/test/mjsunit/es6/proxies-function.js
@@ -0,0 +1,630 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+
+var handler = {
+  get : function(r, n) { return n == "length" ? 2 : undefined }
+}
+
+
+// Calling (call, Function.prototype.call, Function.prototype.apply,
+//          Function.prototype.bind).
+
+var global_object = this
+var receiver
+
+function TestCall(isStrict, callTrap) {
+  assertEquals(42, callTrap(undefined, undefined, [5, 37]))
+
+  var handler = {
+    get: function(r, k) {
+      return k == "length" ? 2 : Function.prototype[k]
+    },
+    apply: callTrap
+  }
+  var f = new Proxy(()=>{}, handler)
+  var o = {f: f}
+  global_object.f = f
+
+  receiver = 333
+  assertEquals(42, f(11, 31))
+  receiver = 333
+  assertEquals(42, o.f(10, 32))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(42, o["f"](9, 33))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(42, (1, o).f(8, 34))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(42, (1, o)["f"](7, 35))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(42, f.call(o, 32, 10))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(42, f.call(undefined, 33, 9))
+  receiver = 333
+  assertEquals(42, f.call(null, 33, 9))
+  receiver = 333
+  assertEquals(44, f.call(2, 21, 23))
+  assertSame(2, receiver.valueOf())
+  receiver = 333
+  assertEquals(42, Function.prototype.call.call(f, o, 20, 22))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(43, Function.prototype.call.call(f, null, 20, 23))
+  assertEquals(44, Function.prototype.call.call(f, 2, 21, 23))
+  assertEquals(2, receiver.valueOf())
+  receiver = 333
+  assertEquals(32, f.apply(o, [16, 16]))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(32, Function.prototype.apply.call(f, o, [17, 15]))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(42, %Call(f, o, 11, 31));
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(42, %Call(f, null, 11, 31));
+  receiver = 333
+  assertEquals(42, %_Call(f, o, 11, 31))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(42, %_Call(f, null, 11, 31))
+
+  var ff = Function.prototype.bind.call(f, o, 12)
+  assertTrue(ff.length <= 1)  // TODO(rossberg): Not spec'ed yet, be lax.
+  receiver = 333
+  assertEquals(42, ff(30))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(33, Function.prototype.call.call(ff, {}, 21))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(32, Function.prototype.apply.call(ff, {}, [20]))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(23, %Call(ff, {}, 11));
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(23, %Call(ff, {}, 11, 3));
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(34, %_Call(ff, {}, 22))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(34, %_Call(ff, {}, 22, 3))
+  assertSame(o, receiver)
+
+  var fff = Function.prototype.bind.call(ff, o, 30)
+  assertEquals(0, fff.length)
+  receiver = 333
+  assertEquals(42, fff())
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(42, Function.prototype.call.call(fff, {}))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(42, Function.prototype.apply.call(fff, {}))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(42, %Call(fff, {}));
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(42, %Call(fff, {}, 11, 3))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(42, %_Call(fff, {}))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(42, %_Call(fff, {}, 3, 4, 5))
+  assertSame(o, receiver)
+
+  var f = new Proxy(()=>{}, {apply: callTrap})
+  receiver = 333
+  assertEquals(42, f(11, 31))
+  var o = {f: f}
+  receiver = 333
+  assertEquals(42, o.f(10, 32))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(42, o["f"](9, 33))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(42, (1, o).f(8, 34))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(42, (1, o)["f"](7, 35))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(42, Function.prototype.call.call(f, o, 20, 22))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(32, Function.prototype.apply.call(f, o, [17, 15]))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(23, %Call(f, o, 11, 12))
+  assertSame(o, receiver)
+  receiver = 333
+  assertEquals(42, %_Call(f, o, 18, 24))
+  assertSame(o, receiver)
+}
+
+TestCall(false, function(_, that, [x, y]) {
+  receiver = that
+  return x + y
+})
+
+TestCall(true, function(_, that, args) {
+  "use strict"
+  receiver = that
+  return args[0] + args[1]
+})
+
+TestCall(false, function() {
+  receiver = arguments[1]
+  return arguments[2][0] + arguments[2][1]
+})
+
+TestCall(false, new Proxy(function(_, that, [x, y]) {
+    receiver = that
+    return x + y
+  }, handler))
+
+TestCall(true, new Proxy(function(_, that, args) {
+    "use strict"
+    receiver = that
+    return args[0] + args[1]
+  }, handler))
+
+TestCall(false, Object.freeze(new Proxy(function(_, that, [x, y]) {
+    receiver = that
+    return x + y
+  }, handler)))
+
+
+
+// Using intrinsics as call traps.
+
+function TestCallIntrinsic(type, callTrap) {
+  var f = new Proxy(()=>{}, {apply: (_, that, args) => callTrap(...args)})
+  var x = f()
+  assertTrue(typeof x == type)
+}
+
+TestCallIntrinsic("boolean", Boolean)
+TestCallIntrinsic("number", Number)
+TestCallIntrinsic("string", String)
+TestCallIntrinsic("object", Object)
+TestCallIntrinsic("function", Function)
+
+
+
+// Throwing from call trap.
+
+function TestCallThrow(callTrap) {
+  var f = new Proxy(()=>{}, {apply: callTrap})
+  assertThrowsEquals(() => f(11), "myexn")
+  assertThrowsEquals(() => ({x: f}).x(11), "myexn")
+  assertThrowsEquals(() => ({x: f})["x"](11), "myexn")
+  assertThrowsEquals(() => Function.prototype.call.call(f, {}, 2), "myexn")
+  assertThrowsEquals(() => Function.prototype.apply.call(f, {}, [1]), "myexn")
+  assertThrowsEquals(() => %Call(f, {}), "myexn")
+  assertThrowsEquals(() => %Call(f, {}, 1, 2), "myexn")
+  assertThrowsEquals(() => %_Call(f, {}), "myexn")
+  assertThrowsEquals(() => %_Call(f, {}, 1, 2), "myexn")
+
+  var f = Object.freeze(new Proxy(()=>{}, {apply: callTrap}))
+  assertThrowsEquals(() => f(11), "myexn")
+  assertThrowsEquals(() => ({x: f}).x(11), "myexn")
+  assertThrowsEquals(() => ({x: f})["x"](11), "myexn")
+  assertThrowsEquals(() => Function.prototype.call.call(f, {}, 2), "myexn")
+  assertThrowsEquals(() => Function.prototype.apply.call(f, {}, [1]), "myexn")
+  assertThrowsEquals(() => %Call(f, {}), "myexn")
+  assertThrowsEquals(() => %Call(f, {}, 1, 2), "myexn")
+  assertThrowsEquals(() => %_Call(f, {}), "myexn")
+  assertThrowsEquals(() => %_Call(f, {}, 1, 2), "myexn")
+}
+
+TestCallThrow(function() { throw "myexn" })
+TestCallThrow(new Proxy(() => {throw "myexn"}, {}))
+TestCallThrow(Object.freeze(new Proxy(() => {throw "myexn"}, {})))
+
+
+
+// Construction (new).
+
+var prototype = {myprop: 0}
+var receiver
+
+var handlerWithPrototype = {
+  get: function(r, n) {
+    if (n == "length") return 2;
+    assertEquals("prototype", n);
+    return prototype;
+  }
+}
+
+var handlerSansPrototype = {
+  get: function(r, n) {
+    if (n == "length") return 2;
+    assertEquals("prototype", n);
+    return undefined;
+  }
+}
+
+function ReturnUndef(_, args, newt) {
+  "use strict";
+  newt.sum = args[0] + args[1];
+}
+
+function ReturnThis(x, y) {
+  "use strict";
+  receiver = this;
+  this.sum = x + y;
+  return this;
+}
+
+function ReturnNew(_, args, newt) {
+  "use strict";
+  return {sum: args[0] + args[1]};
+}
+
+function ReturnNewWithProto(_, args, newt) {
+  "use strict";
+  var result = Object.create(prototype);
+  result.sum = args[0] + args[1];
+  return result;
+}
+
+function TestConstruct(proto, constructTrap) {
+  TestConstruct2(proto, constructTrap, handlerWithPrototype)
+  TestConstruct2(proto, constructTrap, handlerSansPrototype)
+}
+
+function TestConstruct2(proto, constructTrap, handler) {
+  var f = new Proxy(function(){}, {construct: constructTrap})
+  var o = new f(11, 31)
+  assertEquals(42, o.sum)
+  assertSame(proto, Object.getPrototypeOf(o))
+
+  var f = Object.freeze(new Proxy(function(){}, {construct: constructTrap}))
+  var o = new f(11, 32)
+  assertEquals(43, o.sum)
+  assertSame(proto, Object.getPrototypeOf(o))
+}
+
+TestConstruct(Object.prototype, ReturnNew)
+TestConstruct(prototype, ReturnNewWithProto)
+
+TestConstruct(Object.prototype, new Proxy(ReturnNew, {}))
+TestConstruct(prototype, new Proxy(ReturnNewWithProto, {}))
+
+TestConstruct(Object.prototype, Object.freeze(new Proxy(ReturnNew, {})))
+TestConstruct(prototype, Object.freeze(new Proxy(ReturnNewWithProto, {})))
+
+
+
+// Throwing from the construct trap.
+
+function TestConstructThrow(trap) {
+  var f = new Proxy(function(){}, {construct: trap});
+  assertThrowsEquals(() => new f(11), "myexn")
+  Object.freeze(f)
+  assertThrowsEquals(() => new f(11), "myexn")
+}
+
+TestConstructThrow(function() { throw "myexn" })
+TestConstructThrow(new Proxy(function() { throw "myexn" }, {}))
+TestConstructThrow(Object.freeze(new Proxy(function() { throw "myexn" }, {})))
+
+
+
+// Using function proxies as getters and setters.
+
+var value
+var receiver
+
+function TestAccessorCall(getterCallTrap, setterCallTrap) {
+  var pgetter = new Proxy(()=>{}, {apply: getterCallTrap})
+  var psetter = new Proxy(()=>{}, {apply: setterCallTrap})
+
+  var o = {}
+  var oo = Object.create(o)
+  Object.defineProperty(o, "a", {get: pgetter, set: psetter})
+  Object.defineProperty(o, "b", {get: pgetter})
+  Object.defineProperty(o, "c", {set: psetter})
+  Object.defineProperty(o, "3", {get: pgetter, set: psetter})
+  Object.defineProperty(oo, "a", {value: 43})
+
+  receiver = ""
+  assertEquals(42, o.a)
+  assertSame(o, receiver)
+  receiver = ""
+  assertEquals(42, o.b)
+  assertSame(o, receiver)
+  receiver = ""
+  assertEquals(undefined, o.c)
+  assertEquals("", receiver)
+  receiver = ""
+  assertEquals(42, o["a"])
+  assertSame(o, receiver)
+  receiver = ""
+  assertEquals(42, o[3])
+  assertSame(o, receiver)
+
+  receiver = ""
+  assertEquals(43, oo.a)
+  assertEquals("", receiver)
+  receiver = ""
+  assertEquals(42, oo.b)
+  assertSame(oo, receiver)
+  receiver = ""
+  assertEquals(undefined, oo.c)
+  assertEquals("", receiver)
+  receiver = ""
+  assertEquals(43, oo["a"])
+  assertEquals("", receiver)
+  receiver = ""
+  assertEquals(42, oo[3])
+  assertSame(oo, receiver)
+
+  receiver = ""
+  assertEquals(50, o.a = 50)
+  assertSame(o, receiver)
+  assertEquals(50, value)
+  receiver = ""
+  assertEquals(51, o.b = 51)
+  assertEquals("", receiver)
+  assertEquals(50, value)  // no setter
+  assertThrows(function() { "use strict"; o.b = 51 }, TypeError)
+  receiver = ""
+  assertEquals(52, o.c = 52)
+  assertSame(o, receiver)
+  assertEquals(52, value)
+  receiver = ""
+  assertEquals(53, o["a"] = 53)
+  assertSame(o, receiver)
+  assertEquals(53, value)
+  receiver = ""
+  assertEquals(54, o[3] = 54)
+  assertSame(o, receiver)
+  assertEquals(54, value)
+
+  value = 0
+  receiver = ""
+  assertEquals(60, oo.a = 60)
+  assertEquals("", receiver)
+  assertEquals(0, value)  // oo has own 'a'
+  assertEquals(61, oo.b = 61)
+  assertSame("", receiver)
+  assertEquals(0, value)  // no setter
+  assertThrows(function() { "use strict"; oo.b = 61 }, TypeError)
+  receiver = ""
+  assertEquals(62, oo.c = 62)
+  assertSame(oo, receiver)
+  assertEquals(62, value)
+  receiver = ""
+  assertEquals(63, oo["c"] = 63)
+  assertSame(oo, receiver)
+  assertEquals(63, value)
+  receiver = ""
+  assertEquals(64, oo[3] = 64)
+  assertSame(oo, receiver)
+  assertEquals(64, value)
+}
+
+TestAccessorCall(
+  function(_, that) { receiver = that; return 42 },
+  function(_, that, [x]) { receiver = that; value = x }
+)
+
+TestAccessorCall(
+  function(_, that) { "use strict"; receiver = that; return 42 },
+  function(_, that, args) { "use strict"; receiver = that; value = args[0] }
+)
+
+TestAccessorCall(
+  new Proxy(function(_, that) { receiver = that; return 42 }, {}),
+  new Proxy(function(_, that, [x]) { receiver = that; value = x }, {})
+)
+
+TestAccessorCall(
+  Object.freeze(
+    new Proxy(function(_, that) { receiver = that; return 42 }, {})),
+  Object.freeze(
+    new Proxy(function(_, that, [x]) { receiver = that; value = x }, {}))
+)
+
+
+// Passing a proxy function to higher-order library functions.
+
+function TestHigherOrder(f) {
+  assertEquals(6, [6, 2].map(f)[0])
+  assertEquals(4, [5, 2].reduce(f, 4))
+  assertTrue([1, 2].some(f))
+  assertEquals("a.b.c", "a.b.c".replace(".", f))
+}
+
+TestHigherOrder(function(x) { return x })
+TestHigherOrder(function(x) { "use strict"; return x })
+TestHigherOrder(new Proxy(function(x) { return x }, {}))
+TestHigherOrder(Object.freeze(new Proxy(function(x) { return x }, {})))
+
+
+
+// TODO(rossberg): Ultimately, I want to have the following test function
+// run through, but it currently fails on so many cases (some not even
+// involving proxies), that I leave that for later...
+/*
+function TestCalls() {
+  var handler = {
+    get: function(r, k) {
+      return k == "length" ? 2 : Function.prototype[k]
+    }
+  }
+  var bind = Function.prototype.bind
+  var o = {}
+
+  var traps = [
+    function(x, y) {
+      return {receiver: this, result: x + y, strict: false}
+    },
+    function(x, y) { "use strict";
+      return {receiver: this, result: x + y, strict: true}
+    },
+    function() {
+      var x = arguments[0], y = arguments[1]
+      return {receiver: this, result: x + y, strict: false}
+    },
+    Proxy.createFunction(handler, function(x, y) {
+      return {receiver: this, result: x + y, strict: false}
+    }),
+    Proxy.createFunction(handler, function() {
+      var x = arguments[0], y = arguments[1]
+      return {receiver: this, result: x + y, strict: false}
+    }),
+    Proxy.createFunction(handler, function(x, y) { "use strict"
+      return {receiver: this, result: x + y, strict: true}
+    }),
+    CreateFrozen(handler, function(x, y) {
+      return {receiver: this, result: x + y, strict: false}
+    }),
+    CreateFrozen(handler, function(x, y) { "use strict"
+      return {receiver: this, result: x + y, strict: true}
+    }),
+  ]
+  var creates = [
+    function(trap) { return trap },
+    function(trap) { return CreateFrozen({}, callTrap) },
+    function(trap) { return Proxy.createFunction(handler, callTrap) },
+    function(trap) {
+      return Proxy.createFunction(handler, CreateFrozen({}, callTrap))
+    },
+    function(trap) {
+      return Proxy.createFunction(handler, Proxy.createFunction(handler, callTrap))
+    },
+  ]
+  var binds = [
+    function(f, o, x, y) { return f },
+    function(f, o, x, y) { return bind.call(f, o) },
+    function(f, o, x, y) { return bind.call(f, o, x) },
+    function(f, o, x, y) { return bind.call(f, o, x, y) },
+    function(f, o, x, y) { return bind.call(f, o, x, y, 5) },
+    function(f, o, x, y) { return bind.call(bind.call(f, o), {}, x, y) },
+    function(f, o, x, y) { return bind.call(bind.call(f, o, x), {}, y) },
+    function(f, o, x, y) { return bind.call(bind.call(f, o, x, y), {}, 5) },
+  ]
+  var calls = [
+    function(f, x, y) { return f(x, y) },
+    function(f, x, y) { var g = f; return g(x, y) },
+    function(f, x, y) { with ({}) return f(x, y) },
+    function(f, x, y) { var g = f; with ({}) return g(x, y) },
+    function(f, x, y, o) { with (o) return f(x, y) },
+    function(f, x, y, o) { return f.call(o, x, y) },
+    function(f, x, y, o) { return f.apply(o, [x, y]) },
+    function(f, x, y, o) { return Function.prototype.call.call(f, o, x, y) },
+    function(f, x, y, o) { return Function.prototype.apply.call(f, o, [x, y]) },
+    function(f, x, y, o) { return %_Call(f, o, x, y) },
+    function(f, x, y, o) { return %Call(f, o, x, y) },
+    function(f, x, y, o) { return %Apply(f, o, [null, x, y, null], 1, 2) },
+    function(f, x, y, o) { return %Apply(f, o, arguments, 2, 2) },
+    function(f, x, y, o) { if (typeof o == "object") return o.f(x, y) },
+    function(f, x, y, o) { if (typeof o == "object") return o["f"](x, y) },
+    function(f, x, y, o) { if (typeof o == "object") return (1, o).f(x, y) },
+    function(f, x, y, o) { if (typeof o == "object") return (1, o)["f"](x, y) },
+  ]
+  var receivers = [o, global_object, undefined, null, 2, "bla", true]
+  var expectedSloppies = [o, global_object, global_object, global_object]
+
+  for (var t = 0; t < traps.length; ++t) {
+    for (var i = 0; i < creates.length; ++i) {
+      for (var j = 0; j < binds.length; ++j) {
+        for (var k = 0; k < calls.length; ++k) {
+          for (var m = 0; m < receivers.length; ++m) {
+            for (var n = 0; n < receivers.length; ++n) {
+              var bound = receivers[m]
+              var receiver = receivers[n]
+              var func = binds[j](creates[i](traps[t]), bound, 31, 11)
+              var expected = j > 0 ? bound : receiver
+              var expectedSloppy = expectedSloppies[j > 0 ? m : n]
+              o.f = func
+              global_object.f = func
+              var x = calls[k](func, 11, 31, receiver)
+              if (x !== undefined) {
+                assertEquals(42, x.result)
+                if (calls[k].length < 4)
+                  assertSame(x.strict ? undefined : global_object, x.receiver)
+                else if (x.strict)
+                  assertSame(expected, x.receiver)
+                else if (expectedSloppy === undefined)
+                  assertSame(expected, x.receiver.valueOf())
+                else
+                  assertSame(expectedSloppy, x.receiver)
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+TestCalls()
+*/
+
+var realms = [Realm.create(), Realm.create()];
+Realm.shared = {};
+
+Realm.eval(realms[0], "function f(_, that) { return that; };");
+Realm.eval(realms[0], "Realm.shared.f = f;");
+Realm.eval(realms[0], "Realm.shared.fg = this;");
+Realm.eval(realms[1], "function g(_, that) { return that; };");
+Realm.eval(realms[1], "Realm.shared.g = g;");
+Realm.eval(realms[1], "Realm.shared.gg = this;");
+
+var fp = new Proxy(()=>{}, {apply: Realm.shared.f});
+var gp = new Proxy(()=>{}, {apply: Realm.shared.g});
+
+for (var i = 0; i < 10; i++) {
+  assertEquals(undefined, fp());
+  assertEquals(undefined, gp());
+
+  with (this) {
+    assertEquals(this, fp());
+    assertEquals(this, gp());
+  }
+
+  with ({}) {
+    assertEquals(undefined, fp());
+    assertEquals(undefined, gp());
+  }
+}
diff --git a/test/mjsunit/es6/proxies-get-own-property-descriptor.js b/test/mjsunit/es6/proxies-get-own-property-descriptor.js
new file mode 100644
index 0000000..441ff16
--- /dev/null
+++ b/test/mjsunit/es6/proxies-get-own-property-descriptor.js
@@ -0,0 +1,127 @@
+// 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 target = {};
+var configurable_desc = {
+  value: 123,
+  configurable: true,
+  writable: true,
+  enumerable: false,
+};
+Object.defineProperty(target, "configurable", configurable_desc);
+var nonconfigurable_desc = {
+  value: 234,
+  configurable: false,
+  writable: false,
+  enumerable: true
+}
+Object.defineProperty(target, "nonconfigurable", nonconfigurable_desc);
+
+var proxied_desc = {
+  value: 345,
+  configurable: true
+};
+
+var handler = {
+  "getOwnPropertyDescriptor": function(target, name) {
+    if (name === "proxied") {
+      return proxied_desc;
+    }
+    if (name === "return_null") {
+      return null;
+    }
+    return Object.getOwnPropertyDescriptor(target, name);
+  }
+};
+
+var proxy = new Proxy(target, handler);
+var proxy_without_handler = new Proxy(target, {});
+
+// Checking basic functionality:
+
+assertEquals(configurable_desc,
+             Object.getOwnPropertyDescriptor(proxy, "configurable"));
+assertEquals(nonconfigurable_desc,
+             Object.getOwnPropertyDescriptor(proxy, "nonconfigurable"));
+assertEquals({ value: proxied_desc.value,
+               configurable: proxied_desc.configurable,
+               enumerable: false,
+               writable: false },
+             Object.getOwnPropertyDescriptor(proxy, "proxied"));
+assertEquals(configurable_desc,
+             Object.getOwnPropertyDescriptor(proxy_without_handler,
+                                             "configurable"));
+assertEquals(nonconfigurable_desc,
+             Object.getOwnPropertyDescriptor(proxy_without_handler,
+                                             "nonconfigurable"));
+
+assertThrows('Object.getOwnPropertyDescriptor(proxy, "return_null")');
+
+handler.getOwnPropertyDescriptor = undefined;
+assertEquals(configurable_desc,
+             Object.getOwnPropertyDescriptor(proxy, "configurable"));
+
+// Checking invariants mentioned explicitly by the ES spec:
+
+// (Inv-1) "A property cannot be reported as non-existent, if it exists as a
+// non-configurable own property of the target object."
+handler.getOwnPropertyDescriptor = function(target, name) { return undefined; };
+assertThrows('Object.getOwnPropertyDescriptor(proxy, "nonconfigurable")');
+assertEquals(undefined, Object.getOwnPropertyDescriptor(proxy, "configurable"));
+
+// (Inv-2) "A property cannot be reported as non-configurable, if it does not
+// exist as an own property of the target object or if it exists as a
+// configurable own property of the target object."
+handler.getOwnPropertyDescriptor = function(target, name) {
+  return {value: 234, configurable: false, enumerable: true};
+};
+assertThrows('Object.getOwnPropertyDescriptor(proxy, "nonexistent")');
+assertThrows('Object.getOwnPropertyDescriptor(proxy, "configurable")');
+assertEquals(
+    false,
+    Object.getOwnPropertyDescriptor(proxy, "nonconfigurable").configurable);
+
+// (Inv-3) "A property cannot be reported as non-existent, if it exists as an
+// own property of the target object and the target object is not extensible."
+Object.seal(target);
+handler.getOwnPropertyDescriptor = function(target, name) { return undefined; };
+assertThrows('Object.getOwnPropertyDescriptor(proxy, "configurable")');
+assertThrows('Object.getOwnPropertyDescriptor(proxy, "nonconfigurable")');
+assertEquals(undefined, Object.getOwnPropertyDescriptor(proxy, "nonexistent"));
+
+// (Inv-4) "A property cannot be reported as existent, if it does not exist as
+// an own property of the target object and the target object is not
+// extensible."
+var existent_desc = {value: "yes"};
+handler.getOwnPropertyDescriptor = function() { return existent_desc; };
+assertThrows('Object.getOwnPropertyDescriptor(proxy, "nonexistent")');
+assertEquals(
+    {value: "yes", writable: false, enumerable: false, configurable: false},
+    Object.getOwnPropertyDescriptor(proxy, "configurable"));
+
+// Checking individual bailout points in the implementation:
+
+// Step 6: Trap is not callable.
+handler.getOwnPropertyDescriptor = {};
+assertThrows('Object.getOwnPropertyDescriptor(proxy, "configurable")');
+
+// Step 8: Trap throws.
+handler.getOwnPropertyDescriptor = function() { throw "ball"; };
+assertThrows('Object.getOwnPropertyDescriptor(proxy, "configurable")');
+
+// Step 9: Trap result is neither undefined nor an object.
+handler.getOwnPropertyDescriptor = function() { return 1; }
+assertThrows('Object.getOwnPropertyDescriptor(proxy, "configurable")');
+
+// Step 11b: See (Inv-1) above.
+// Step 11e: See (Inv-3) above.
+
+// Step 16: Incompatible PropertyDescriptor; a non-configurable property
+// cannot be reported as configurable. (Inv-4) above checks more cases.
+handler.getOwnPropertyDescriptor = function(target, name) {
+  return {value: 456, configurable: true, writable: true}
+};
+assertThrows('Object.getOwnPropertyDescriptor(proxy, "nonconfigurable")');
+
+// Step 17: See (Inv-2) above.
diff --git a/test/mjsunit/es6/proxies-get-prototype-of.js b/test/mjsunit/es6/proxies-get-prototype-of.js
new file mode 100644
index 0000000..a628f3f
--- /dev/null
+++ b/test/mjsunit/es6/proxies-get-prototype-of.js
@@ -0,0 +1,91 @@
+// 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 target = { target: 1 };
+target.__proto__ = {};
+var handler = { handler: 1 };
+var proxy = new Proxy(target, handler);
+
+assertSame(Object.getPrototypeOf(proxy), target.__proto__ );
+
+target.__proto__ = [];
+assertSame(Object.getPrototypeOf(proxy), target.__proto__);
+
+handler.getPrototypeOf = function() {
+  return 1;
+}
+assertThrows(function() { Object.getPrototypeOf(proxy) }, TypeError);
+
+var target_prototype = {a:1, b:2};
+handler.getPrototypeOf = function() {
+  return target_prototype ;
+}
+assertSame(Object.getPrototypeOf(proxy), target_prototype);
+
+// Test with proxy target:
+var proxy2 = new Proxy(proxy, {'handler':1});
+assertSame(Object.getPrototypeOf(proxy2), target_prototype);
+
+// Test with Proxy handler:
+var proxy3_prototype = {'proto3':true};
+var handler_proxy = new Proxy({
+  getPrototypeOf: function() { return proxy3_prototype }
+}, {});
+var proxy3 = new Proxy(target, handler_proxy);
+assertSame(Object.getPrototypeOf(proxy3), proxy3_prototype);
+
+
+// Some tests with Object.prototype.isPrototypeOf
+
+(function () {
+  var object = {};
+  var handler = {};
+  var proto = new Proxy({}, handler);
+  object.__proto__ = proto;
+
+  assertTrue(proto.isPrototypeOf(object));
+  assertTrue(Object.prototype.isPrototypeOf.call(proto, object));
+
+  handler.getPrototypeOf = function () { return Object.prototype };
+  assertTrue(proto.isPrototypeOf(object));
+  assertTrue(Object.prototype.isPrototypeOf.call(proto, object));
+  assertTrue(Object.prototype.isPrototypeOf(object));
+  assertFalse(Object.prototype.isPrototypeOf.call(Array.prototype, object));
+  assertFalse(Array.prototype.isPrototypeOf(object));
+
+  handler.getPrototypeOf = function () { return object };
+  assertTrue(Object.prototype.isPrototypeOf.call(proto, object));
+  assertTrue(proto.isPrototypeOf(object));
+  assertTrue(Object.prototype.isPrototypeOf.call(object, object));
+  assertTrue(object.isPrototypeOf(object));
+
+  handler.getPrototypeOf = function () { throw "foo" };
+  assertTrue(proto.isPrototypeOf(object));
+  assertTrue(Object.prototype.isPrototypeOf.call(proto, object));
+  assertThrows(()=> Object.prototype.isPrototypeOf(object));
+  assertThrows(()=> Object.prototype.isPrototypeOf.call(Array.prototype, object));
+  assertThrows(()=> Array.prototype.isPrototypeOf(object));
+})();
+
+(function () {
+  var handler = {};
+  var object = new Proxy({}, handler);
+  var proto = {};
+
+  assertFalse(Object.prototype.isPrototypeOf.call(object, object));
+  assertFalse(Object.prototype.isPrototypeOf.call(proto, object));
+  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, object));
+
+  handler.getPrototypeOf = function () { return proto };
+  assertTrue(Object.prototype.isPrototypeOf.call(proto, object));
+  assertFalse(Object.prototype.isPrototypeOf.call({}, object));
+  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, object));
+
+  handler.getPrototypeOf = function () { return object };
+  assertTrue(Object.prototype.isPrototypeOf.call(object, object));
+
+  handler.getPrototypeOf = function () { throw "foo" };
+  assertThrows(()=> Object.prototype.isPrototypeOf.call(object, object));
+  assertThrows(()=> Object.prototype.isPrototypeOf(object));
+})();
diff --git a/test/mjsunit/es6/proxies-get.js b/test/mjsunit/es6/proxies-get.js
new file mode 100644
index 0000000..b1b92db
--- /dev/null
+++ b/test/mjsunit/es6/proxies-get.js
@@ -0,0 +1,127 @@
+// 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
+
+(function testBasicFunctionality() {
+   var target = {
+     target_one: 1,
+     property: "value"
+   };
+
+   var handler = {handler:1};
+
+   var proxy = new Proxy(target, handler);
+   assertEquals("value", proxy.property);
+   assertEquals(undefined, proxy.nothing);
+   assertEquals(undefined, proxy.handler);
+
+   handler.get = function() { return "value 2" };
+   assertEquals("value 2", proxy.property);
+   assertEquals("value 2", proxy.nothing);
+   assertEquals("value 2", proxy.handler);
+
+   var handler2 = new Proxy({get: function() { return "value 3" }},{});
+   var proxy2 = new Proxy(target, handler2);
+   assertEquals("value 3", proxy2.property);
+   assertEquals("value 3", proxy2.nothing);
+   assertEquals("value 3", proxy2.handler);
+})();
+
+(function testThrowOnGettingTrap() {
+  var handler = new Proxy({}, {get: function(){ throw Error() }});
+  var proxy = new Proxy({}, handler);
+  assertThrows("proxy.property", Error);
+})();
+
+(function testFallback() {
+  var target = {property:"value"};
+  var proxy = new Proxy(target, {});
+  assertEquals("value", proxy.property);
+  assertEquals(undefined, proxy.property2);
+})();
+
+(function testFallbackUndefinedTrap() {
+  var handler = new Proxy({}, {get: function(){ return undefined }});
+  var target = {property:"value"};
+  var proxy = new Proxy(target, handler);
+  assertEquals("value", proxy.property);
+  assertEquals(undefined, proxy.property2);
+})();
+
+(function testFailingInvariant() {
+  var target = {};
+  var handler = { get: function(r, p){ if (p != "key4") return "value" }}
+  var proxy = new Proxy(target, handler);
+  assertEquals("value", proxy.property);
+  assertEquals("value", proxy.key);
+  assertEquals("value", proxy.key2);
+  assertEquals("value", proxy.key3);
+
+  // Define a non-configurable, non-writeable property on the target for
+  // which the handler will return a different value.
+  Object.defineProperty(target, "key", {
+    configurable: false,
+    writable: false,
+    value: "different value"
+  });
+  assertEquals("value", proxy.property);
+  assertThrows(function(){ proxy.key }, TypeError);
+  assertEquals("value", proxy.key2);
+  assertEquals("value", proxy.key3);
+
+  // Define a non-configurable getter on the target for which the handler
+  // will return a value, according to the spec we do not throw.
+  Object.defineProperty(target, "key2", {
+    configurable: false,
+    get: function() { return "different value" }
+  });
+  assertEquals("value", proxy.property);
+  assertThrows(function(){ proxy.key }, TypeError);
+  assertEquals("value", proxy.key2);
+  assertEquals("value", proxy.key3);
+
+  // Define a non-configurable setter without a corresponding getter on the
+  // target for which the handler will return a value.
+  Object.defineProperty(target, "key3", {
+    configurable: false,
+    set: function() { }
+  });
+  assertEquals("value", proxy.property);
+  assertThrows(function(){ proxy.key }, TypeError);
+  assertEquals("value", proxy.key2);
+  assertThrows(function(){ proxy.key3 }, TypeError);
+
+  // Define a non-configurable setter without a corresponding getter on the
+  // target for which the handler will return undefined.
+  Object.defineProperty(target, "key4", {
+    configurable: false,
+    set: function() { }
+  });
+  assertSame(undefined, proxy.key4);
+})();
+
+(function testGetInternalIterators() {
+  var log = [];
+  var array = [1,2,3,4,5]
+  var origIt = array[Symbol.iterator]();
+  var it = new Proxy(origIt, {
+    get(t, name) {
+      log.push(`[[Get]](iterator, ${String(name)})`);
+      return Reflect.get(t, name);
+    },
+    set(t, name, val) {
+      log.push(`[[Set]](iterator, ${String(name)}, ${String(val)})`);
+      return Reflect.set(t, name, val);
+    }
+  });
+
+  assertThrows(function() {
+    for (var v of it) log.push(v);
+  }, TypeError);
+  assertEquals([
+    "[[Get]](iterator, Symbol(Symbol.iterator))",
+    "[[Get]](iterator, next)"
+  ], log);
+})();
diff --git a/test/mjsunit/es6/proxies-global-reference.js b/test/mjsunit/es6/proxies-global-reference.js
new file mode 100644
index 0000000..975d7f7
--- /dev/null
+++ b/test/mjsunit/es6/proxies-global-reference.js
@@ -0,0 +1,12 @@
+// 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 failing_proxy = new Proxy({}, new Proxy({}, {
+  get() { throw "No trap should fire" }}));
+
+Object.setPrototypeOf(Object.prototype, failing_proxy);
+assertThrows(()=>a, TypeError);
+
+Object.setPrototypeOf(this, failing_proxy);
+assertThrows(()=>a, TypeError);
diff --git a/test/mjsunit/es6/proxies-has-own-property.js b/test/mjsunit/es6/proxies-has-own-property.js
new file mode 100644
index 0000000..5b9ddbc
--- /dev/null
+++ b/test/mjsunit/es6/proxies-has-own-property.js
@@ -0,0 +1,37 @@
+// 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 handler = {};
+var target = {a:1};
+var proxy = new Proxy(target, handler);
+
+assertTrue(target.hasOwnProperty('a'));
+assertTrue(proxy.hasOwnProperty('a'));
+assertFalse(target.hasOwnProperty('b'));
+assertFalse(proxy.hasOwnProperty('b'));
+
+
+handler.has = function() { assertUnreachable() }
+handler.getOwnPropertyDescriptor = function () {}
+
+assertTrue(target.hasOwnProperty('a'));
+assertFalse(proxy.hasOwnProperty('a'));
+assertFalse(target.hasOwnProperty('b'));
+assertFalse(proxy.hasOwnProperty('b'));
+
+
+handler.getOwnPropertyDescriptor = function() { return {configurable: true} }
+
+assertTrue(target.hasOwnProperty('a'));
+assertTrue(proxy.hasOwnProperty('a'));
+assertFalse(target.hasOwnProperty('b'));
+assertTrue(proxy.hasOwnProperty('b'));
+
+
+handler.getOwnPropertyDescriptor = function() { throw Error(); }
+
+assertTrue(target.hasOwnProperty('a'));
+assertThrows(function(){ proxy.hasOwnProperty('a') }, Error);
+assertFalse(target.hasOwnProperty('b'));
+assertThrows(function(){ proxy.hasOwnProperty('b') }, Error);
diff --git a/test/mjsunit/es6/proxies-has.js b/test/mjsunit/es6/proxies-has.js
new file mode 100644
index 0000000..7294196
--- /dev/null
+++ b/test/mjsunit/es6/proxies-has.js
@@ -0,0 +1,61 @@
+// 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 target = {
+  "target_one": 1
+};
+target.__proto__ = {
+  "target_two": 2
+};
+var handler = {
+  has: function(target, name) {
+    return name == "present";
+  }
+}
+
+var proxy = new Proxy(target, handler);
+
+// Test simple cases.
+assertTrue("present" in proxy);
+assertFalse("nonpresent" in proxy);
+
+// Test interesting algorithm steps:
+
+// Step 7: Fall through to target if trap is undefined.
+handler.has = undefined;
+assertTrue("target_one" in proxy);
+assertTrue("target_two" in proxy);
+assertFalse("in_your_dreams" in proxy);
+
+// Step 8: Result is converted to boolean.
+var result = 1;
+handler.has = function(t, n) { return result; }
+assertTrue("foo" in proxy);
+result = {};
+assertTrue("foo" in proxy);
+result = undefined;
+assertFalse("foo" in proxy);
+result = "string";
+assertTrue("foo" in proxy);
+
+// Step 9b i. Trap result must confirm presence of non-configurable properties
+// of the target.
+Object.defineProperty(target, "nonconf", {value: 1, configurable: false});
+result = false;
+assertThrows("'nonconf' in proxy", TypeError);
+
+// Step 9b iii. Trap result must confirm presence of all own properties of
+// non-extensible targets.
+Object.preventExtensions(target);
+assertThrows("'nonconf' in proxy", TypeError);
+assertThrows("'target_one' in proxy", TypeError);
+assertFalse("target_two" in proxy);
+assertFalse("in_your_dreams" in proxy);
+
+// Regression test for crbug.com/570120 (stray JSObject::cast).
+(function TestHasPropertyFastPath() {
+  var proxy = new Proxy({}, {});
+  var object = Object.create(proxy);
+  object.hasOwnProperty(0);
+})();
diff --git a/test/mjsunit/es6/proxies-hash.js b/test/mjsunit/es6/proxies-hash.js
new file mode 100644
index 0000000..05433f0
--- /dev/null
+++ b/test/mjsunit/es6/proxies-hash.js
@@ -0,0 +1,121 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// Helper.
+
+function TestWithProxies(test, construct, handler) {
+  test(construct, handler, function(h) { return new Proxy({}, h) })
+  // TODO(cbruni): Adapt and enable once we have [[Call]] working.
+  // test(construct, handler, function(h) {
+  //  return Proxy.createFunction(h, function() {})
+  // })
+}
+
+
+// Sets.
+
+function TestSet(construct, fix) {
+  TestWithProxies(TestSet2, construct, fix)
+}
+
+function TestSet2(construct, fix, create) {
+  var handler = {fix: function() { return {} }}
+  var p1 = create(handler)
+  var p2 = create(handler)
+  var p3 = create(handler)
+  fix(p3)
+
+  var s = new construct();
+  s.add(p1);
+  s.add(p2);
+  assertTrue(s.has(p1));
+  assertTrue(s.has(p2));
+  assertFalse(s.has(p3));
+
+  fix(p1)
+  fix(p2)
+  assertTrue(s.has(p1));
+  assertTrue(s.has(p2));
+  assertFalse(s.has(p3));
+
+  s.delete(p2);
+  assertTrue(s.has(p1));
+  assertFalse(s.has(p2));
+  assertFalse(s.has(p3));
+}
+
+TestSet(Set, Object.seal)
+TestSet(Set, Object.freeze)
+TestSet(Set, Object.preventExtensions)
+
+
+// Maps and weak maps.
+
+function TestMap(construct, fix) {
+  TestWithProxies(TestMap2, construct, fix)
+}
+
+function TestMap2(construct, fix, create) {
+  var handler = {fix: function() { return {} }}
+  var p1 = create(handler)
+  var p2 = create(handler)
+  var p3 = create(handler)
+  fix(p3)
+
+  var m = new construct();
+  m.set(p1, 123);
+  m.set(p2, 321);
+  assertTrue(m.has(p1));
+  assertTrue(m.has(p2));
+  assertFalse(m.has(p3));
+  assertSame(123, m.get(p1));
+  assertSame(321, m.get(p2));
+
+  fix(p1)
+  fix(p2)
+  assertTrue(m.has(p1));
+  assertTrue(m.has(p2));
+  assertFalse(m.has(p3));
+  assertSame(123, m.get(p1));
+  assertSame(321, m.get(p2));
+
+  m.delete(p2);
+  assertTrue(m.has(p1));
+  assertFalse(m.has(p2));
+  assertFalse(m.has(p3));
+  assertSame(123, m.get(p1));
+  assertSame(undefined, m.get(p2));
+}
+
+TestMap(Map, Object.seal)
+TestMap(Map, Object.freeze)
+TestMap(Map, Object.preventExtensions)
+
+TestMap(WeakMap, Object.seal)
+TestMap(WeakMap, Object.freeze)
+TestMap(WeakMap, Object.preventExtensions)
diff --git a/test/mjsunit/es6/proxies-integrity.js b/test/mjsunit/es6/proxies-integrity.js
new file mode 100644
index 0000000..4cdf770
--- /dev/null
+++ b/test/mjsunit/es6/proxies-integrity.js
@@ -0,0 +1,211 @@
+// 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 toKey(x) {
+  if (typeof x === "symbol") return x;
+  return String(x);
+}
+
+
+const noconf = {configurable: false};
+const noconf_nowrite = {configurable: false, writable: false};
+
+
+var symbol = Symbol();
+
+
+var log = [];
+var logger = {};
+var handler = new Proxy({}, logger);
+
+logger.get = function(t, trap, r) {
+  return function() {
+    log.push([trap, ...arguments]);
+    return Reflect[trap](...arguments);
+  }
+};
+
+
+(function Seal() {
+  var target = [];
+  var proxy = new Proxy(target, handler);
+  log.length = 0;
+
+  target.wurst = 42;
+  target[0] = true;
+  Object.defineProperty(target, symbol, {get: undefined});
+
+  Object.seal(proxy);
+  assertEquals(6, log.length)
+  for (var i in log) assertSame(target, log[i][1]);
+
+  assertArrayEquals(
+      ["preventExtensions", target], log[0]);
+  assertArrayEquals(
+      ["ownKeys", target], log[1]);
+  assertArrayEquals(
+      ["defineProperty", target, toKey(0), noconf], log[2]);
+  assertArrayEquals(
+      ["defineProperty", target, toKey("length"), noconf], log[3]);
+  assertArrayEquals(
+      ["defineProperty", target, toKey("wurst"), noconf], log[4]);
+  assertArrayEquals(
+      ["defineProperty", target, toKey(symbol), noconf], log[5]);
+})();
+
+
+(function Freeze() {
+  var target = [];
+  var proxy = new Proxy(target, handler);
+  log.length = 0;
+
+  target.wurst = 42;
+  target[0] = true;
+  Object.defineProperty(target, symbol, {get: undefined});
+
+  Object.freeze(proxy);
+  assertEquals(10, log.length)
+  for (var i in log) assertSame(target, log[i][1]);
+
+  assertArrayEquals(
+      ["preventExtensions", target], log[0]);
+  assertArrayEquals(
+      ["ownKeys", target], log[1]);
+  assertArrayEquals(
+      ["getOwnPropertyDescriptor", target, toKey(0)], log[2]);
+  assertArrayEquals(
+      ["defineProperty", target, toKey(0), noconf_nowrite], log[3]);
+  assertArrayEquals(
+      ["getOwnPropertyDescriptor", target, toKey("length")], log[4]);
+  assertArrayEquals(
+      ["defineProperty", target, toKey("length"), noconf_nowrite], log[5]);
+  assertArrayEquals(
+      ["getOwnPropertyDescriptor", target, toKey("wurst")], log[6]);
+  assertArrayEquals(
+      ["defineProperty", target, toKey("wurst"), noconf_nowrite], log[7]);
+  assertArrayEquals(
+      ["getOwnPropertyDescriptor", target, toKey(symbol)], log[8]);
+  assertArrayEquals(
+      ["defineProperty", target, toKey(symbol), noconf], log[9]);
+})();
+
+
+(function IsSealed() {
+  var target = [];
+  var proxy = new Proxy(target, handler);
+
+  target.wurst = 42;
+  target[0] = true;
+  Object.defineProperty(target, symbol, {get: undefined});
+
+  // Extensible.
+
+  log.length = 0;
+
+  Object.isSealed(proxy);
+  assertEquals(1, log.length)
+  for (var i in log) assertSame(target, log[i][1]);
+
+  assertArrayEquals(
+      ["isExtensible", target], log[0]);
+
+  // Not extensible but not sealed.
+
+  log.length = 0;
+  Object.preventExtensions(target);
+
+  Object.isSealed(proxy);
+  assertEquals(3, log.length)
+  for (var i in log) assertSame(target, log[i][1]);
+
+  assertArrayEquals(
+      ["isExtensible", target], log[0]);
+  assertArrayEquals(
+      ["ownKeys", target], log[1]);
+  assertArrayEquals(
+      ["getOwnPropertyDescriptor", target, toKey(0)], log[2]);
+
+  // Sealed.
+
+  log.length = 0;
+  Object.seal(target);
+
+  Object.isSealed(proxy);
+  assertEquals(6, log.length)
+  for (var i in log) assertSame(target, log[i][1]);
+
+  assertArrayEquals(
+      ["isExtensible", target], log[0]);
+  assertArrayEquals(
+      ["ownKeys", target], log[1]);
+  assertArrayEquals(
+      ["getOwnPropertyDescriptor", target, toKey(0)], log[2]);
+  assertArrayEquals(
+      ["getOwnPropertyDescriptor", target, toKey("length")], log[3]);
+  assertArrayEquals(
+      ["getOwnPropertyDescriptor", target, toKey("wurst")], log[4]);
+  assertArrayEquals(
+      ["getOwnPropertyDescriptor", target, toKey(symbol)], log[5]);
+})();
+
+
+(function IsFrozen() {
+  var target = [];
+  var proxy = new Proxy(target, handler);
+
+  target.wurst = 42;
+  target[0] = true;
+  Object.defineProperty(target, symbol, {get: undefined});
+
+  // Extensible.
+
+  log.length = 0;
+
+  Object.isFrozen(proxy);
+  assertEquals(1, log.length)
+  for (var i in log) assertSame(target, log[i][1]);
+
+  assertArrayEquals(
+      ["isExtensible", target], log[0]);
+
+  // Not extensible but not frozen.
+
+  log.length = 0;
+  Object.preventExtensions(target);
+
+  Object.isFrozen(proxy);
+  assertEquals(3, log.length)
+  for (var i in log) assertSame(target, log[i][1]);
+
+  assertArrayEquals(
+      ["isExtensible", target], log[0]);
+  assertArrayEquals(
+      ["ownKeys", target], log[1]);
+  assertArrayEquals(
+      ["getOwnPropertyDescriptor", target, toKey(0)], log[2]);
+
+  // Frozen.
+
+  log.length = 0;
+  Object.freeze(target);
+
+  Object.isFrozen(proxy);
+  assertEquals(6, log.length)
+  for (var i in log) assertSame(target, log[i][1]);
+
+  assertArrayEquals(
+      ["isExtensible", target], log[0]);
+  assertArrayEquals(
+      ["ownKeys", target], log[1]);
+  assertArrayEquals(
+      ["getOwnPropertyDescriptor", target, toKey(0)], log[2]);
+  assertArrayEquals(
+      ["getOwnPropertyDescriptor", target, toKey("length")], log[3]);
+  assertArrayEquals(
+      ["getOwnPropertyDescriptor", target, toKey("wurst")], log[4]);
+  assertArrayEquals(
+      ["getOwnPropertyDescriptor", target, toKey(symbol)], log[5]);
+})();
diff --git a/test/mjsunit/es6/proxies-is-extensible.js b/test/mjsunit/es6/proxies-is-extensible.js
new file mode 100644
index 0000000..9ab2c05
--- /dev/null
+++ b/test/mjsunit/es6/proxies-is-extensible.js
@@ -0,0 +1,72 @@
+// 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 () {
+  // No trap.
+
+  var target = {};
+  var handler = {};
+  var proxy = new Proxy(target, handler);
+
+  assertTrue(Reflect.isExtensible(target));
+  assertTrue(Reflect.isExtensible(proxy));
+  assertTrue(Reflect.preventExtensions(proxy));
+  assertFalse(Reflect.isExtensible(target));
+  assertFalse(Reflect.isExtensible(proxy));
+})();
+
+
+(function () {
+  // "Undefined" trap.
+
+  var target = {};
+  var handler = { isExtensible: null };
+  var proxy = new Proxy(target, handler);
+
+  assertTrue(Reflect.isExtensible(target));
+  assertTrue(Reflect.isExtensible(proxy));
+  assertTrue(Reflect.preventExtensions(proxy));
+  assertFalse(Reflect.isExtensible(target));
+  assertFalse(Reflect.isExtensible(proxy));
+})();
+
+
+(function () {
+  // Invalid trap.
+
+  var target = {};
+  var handler = { isExtensible: true };
+  var proxy = new Proxy(target, handler);
+
+  assertThrows(() => {Reflect.isExtensible(proxy)}, TypeError);
+})();
+
+
+(function () {
+  var target = {};
+  var handler = { isExtensible() {return "bla"} };
+  var proxy = new Proxy(target, handler);
+
+  // Trap returns trueish and target is extensible.
+  assertTrue(Reflect.isExtensible(proxy));
+
+  // Trap returns trueish but target is not extensible.
+  Reflect.preventExtensions(target);
+  assertThrows(() => {Reflect.isExtensible(proxy)}, TypeError);
+})();
+
+
+(function () {
+  var target = {};
+  var handler = { isExtensible() {return 0} };
+  var proxy = new Proxy(target, handler);
+
+  // Trap returns falsish but target is extensible.
+  assertThrows(() => {Reflect.isExtensible(proxy)}, TypeError);
+
+  // Trap returns falsish and target is not extensible.
+  Reflect.preventExtensions(target);
+  assertFalse(Reflect.isExtensible(proxy));
+})();
diff --git a/test/mjsunit/es6/proxies-json.js b/test/mjsunit/es6/proxies-json.js
new file mode 100644
index 0000000..d48d539
--- /dev/null
+++ b/test/mjsunit/es6/proxies-json.js
@@ -0,0 +1,505 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// JSON.stringify
+
+
+function testStringify(expected, object) {
+  // Test fast case that bails out to slow case.
+  assertEquals(expected, JSON.stringify(object));
+  // Test slow case.
+  assertEquals(expected, JSON.stringify(object, undefined, 0));
+}
+
+
+// Test serializing a proxy, a function proxy, and objects that contain them.
+
+var handler1 = {
+  get: function(target, name) {
+    return name.toUpperCase();
+  },
+  ownKeys: function() {
+    return ['a', 'b', 'c'];
+  },
+  getOwnPropertyDescriptor: function() {
+    return { enumerable: true, configurable: true };
+  }
+}
+
+var proxy1 = new Proxy({}, handler1);
+testStringify('{"a":"A","b":"B","c":"C"}', proxy1);
+
+var proxy_fun = new Proxy(() => {}, handler1);
+assertTrue(typeof(proxy_fun) === 'function');
+testStringify(undefined, proxy_fun);
+testStringify('[1,null]', [1, proxy_fun]);
+
+handler1.apply = function() { return 666; };
+testStringify(undefined, proxy_fun);
+testStringify('[1,null]', [1, proxy_fun]);
+
+var parent1a = { b: proxy1 };
+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);
+
+var parent1c = [123, proxy1, true];
+testStringify('[123,{"a":"A","b":"B","c":"C"},true]', parent1c);
+
+
+// Proxy with side effect.
+
+var handler2 = {
+  get: function(target, name) {
+    delete parent2.c;
+    return name.toUpperCase();
+  },
+  ownKeys: function() {
+    return ['a', 'b', 'c'];
+  },
+  getOwnPropertyDescriptor: function() {
+    return { enumerable: true, configurable: true };
+  }
+}
+
+var proxy2 = new Proxy({}, handler2);
+var parent2 = { a: "delete", b: proxy2, c: "remove" };
+var expected2 = '{"a":"delete","b":{"a":"A","b":"B","c":"C"}}';
+assertEquals(expected2, JSON.stringify(parent2));
+parent2.c = "remove";  // Revert side effect.
+assertEquals(expected2, JSON.stringify(parent2, undefined, 0));
+
+
+// Proxy with a get function that uses the receiver argument.
+
+var handler3 = {
+  get: function(target, name, receiver) {
+    if (name == 'valueOf' || name === Symbol.toPrimitive) {
+      return function() { return "proxy" };
+    };
+    if (typeof name !== 'symbol') return name + "(" + receiver + ")";
+  },
+  ownKeys: function() {
+    return ['a', 'b', 'c'];
+  },
+  getOwnPropertyDescriptor: function() {
+    return { enumerable: true, configurable: true };
+  }
+}
+
+var proxy3 = new Proxy({}, handler3);
+var parent3 = { x: 123, y: proxy3 }
+testStringify('{"x":123,"y":{"a":"a(proxy)","b":"b(proxy)","c":"c(proxy)"}}',
+              parent3);
+
+
+// Empty proxy.
+
+var handler4 = {
+  get: function(target, name) {
+    return 0;
+  },
+  has: function() {
+    return true;
+  },
+  getOwnPropertyDescriptor: function(target, name) {
+    return { enumerable: false };
+  }
+}
+
+var proxy4 = new Proxy({}, handler4);
+testStringify('{}', proxy4);
+testStringify('{"a":{}}', { a: proxy4 });
+
+
+// Proxy that provides a toJSON function that uses this.
+
+var handler5 = {
+  get: function(target, name) {
+    if (name == 'z') return 97000;
+    return function(key) { return key.charCodeAt(0) + this.z; };
+  },
+  ownKeys: function(target) {
+    return ['toJSON', 'z'];
+  },
+  has: function() {
+    return true;
+  },
+  getOwnPropertyDescriptor: function(target, name) {
+    return { enumerable: true };
+  }
+}
+
+var proxy5 = new Proxy({}, handler5);
+testStringify('{"a":97097}', { a: proxy5 });
+
+
+// Proxy that provides a toJSON function that returns undefined.
+
+var handler6 = {
+  get: function(target, name) {
+    return function(key) { return undefined; };
+  },
+  ownKeys: function(target) {
+    return ['toJSON'];
+  },
+  has: function() {
+    return true;
+  },
+  getOwnPropertyDescriptor: function(target, name) {
+    return { enumerable: true };
+  }
+}
+
+var proxy6 = new Proxy({}, handler6);
+testStringify('[1,null,true]', [1, proxy6, true]);
+testStringify('{"a":1,"c":true}', {a: 1, b: proxy6, c: true});
+
+
+// Object containing a proxy that changes the parent's properties.
+
+var handler7 = {
+  get: function(target, name) {
+    delete parent7.a;
+    delete parent7.c;
+    parent7.e = "5";
+    return name.toUpperCase();
+  },
+  ownKeys: function() {
+    return ['a', 'b', 'c'];
+  },
+  getOwnPropertyDescriptor: function() {
+    return { enumerable: true, configurable: true };
+  }
+}
+
+var proxy7 = new Proxy({}, handler7);
+var parent7 = { a: "1", b: proxy7, c: "3", d: "4" };
+assertEquals('{"a":"1","b":{"a":"A","b":"B","c":"C"},"d":"4"}',
+             JSON.stringify(parent7));
+assertEquals('{"b":{"a":"A","b":"B","c":"C"},"d":"4","e":"5"}',
+             JSON.stringify(parent7));
+
+
+// (Proxy handler to log trap calls)
+
+var log = [];
+var logger = {};
+var handler = new Proxy({}, logger);
+
+logger.get = function(t, trap, r) {
+  return function() {
+    log.push([trap, ...arguments]);
+    return Reflect[trap](...arguments);
+  }
+};
+
+
+// Object is a callable proxy
+
+log.length = 0;
+var target = () => 42;
+var proxy = new Proxy(target, handler);
+assertTrue(typeof proxy === 'function');
+
+assertEquals(undefined, JSON.stringify(proxy));
+assertEquals(1, log.length)
+for (var i in log) assertSame(target, log[i][1]);
+
+assertEquals(["get", target, "toJSON", proxy], log[0]);
+
+
+// Object is a non-callable non-arraylike proxy
+
+log.length = 0;
+var target = {foo: 42}
+var proxy = new Proxy(target, handler);
+assertFalse(Array.isArray(proxy));
+
+assertEquals('{"foo":42}', JSON.stringify(proxy));
+assertEquals(4, log.length)
+for (var i in log) assertSame(target, log[i][1]);
+
+assertEquals(
+    ["get", target, "toJSON", proxy], log[0]);
+assertEquals(
+    ["ownKeys", target], log[1]);  // EnumerableOwnNames
+assertEquals(
+    ["getOwnPropertyDescriptor", target, "foo"], log[2]);  // EnumerableOwnNames
+assertEquals(
+    ["get", target, "foo", proxy], log[3]);
+
+
+// Object is an arraylike proxy
+
+log.length = 0;
+var target = [42];
+var proxy = new Proxy(target, handler);
+assertTrue(Array.isArray(proxy));
+
+assertEquals('[42]', JSON.stringify(proxy));
+assertEquals(3, log.length)
+for (var i in log) assertSame(target, log[i][1]);
+
+assertEquals(["get", target, "toJSON", proxy], log[0]);
+assertEquals(["get", target, "length", proxy], log[1]);
+assertEquals(["get", target, "0", proxy], log[2]);
+
+
+// Replacer is a callable proxy
+
+log.length = 0;
+var object = {0: "foo", 1: 666};
+var target = (key, val) => key == "1" ? val + 42 : val;
+var proxy = new Proxy(target, handler);
+assertTrue(typeof proxy === 'function');
+
+assertEquals('{"0":"foo","1":708}', JSON.stringify(object, proxy));
+assertEquals(3, log.length)
+for (var i in log) assertSame(target, log[i][1]);
+
+assertEquals(4, log[0].length)
+assertEquals("apply", log[0][0]);
+assertEquals("", log[0][3][0]);
+assertEquals({0: "foo", 1: 666}, log[0][3][1]);
+assertEquals(4, log[1].length)
+assertEquals("apply", log[1][0]);
+assertEquals(["0", "foo"], log[1][3]);
+assertEquals(4, log[2].length)
+assertEquals("apply", log[2][0]);
+assertEquals(["1", 666], log[2][3]);
+
+
+// Replacer is an arraylike proxy
+
+log.length = 0;
+var object = {0: "foo", 1: 666};
+var target = [0];
+var proxy = new Proxy(target, handler);
+assertTrue(Array.isArray(proxy));
+
+assertEquals('{"0":"foo"}', JSON.stringify(object, proxy));
+assertEquals(2, log.length)
+for (var i in log) assertSame(target, log[i][1]);
+
+assertEquals(["get", target, "length", proxy], log[0]);
+assertEquals(["get", target, "0", proxy], log[1]);
+
+
+// Replacer is an arraylike proxy and object is an array
+
+log.length = 0;
+var object = ["foo", 42];
+var target = [0];
+var proxy = new Proxy(target, handler);
+assertTrue(Array.isArray(proxy));
+
+assertEquals('["foo",42]', JSON.stringify(object, proxy));
+assertEquals(2, log.length);
+for (var i in log) assertSame(target, log[i][1]);
+
+assertEquals(["get", target, "length", proxy], log[0]);
+assertEquals(["get", target, "0", proxy], log[1]);
+
+
+// Replacer is an arraylike proxy with a non-trivial length
+
+var getTrap = function(t, key) {
+  if (key === "length") return {[Symbol.toPrimitive]() {return 42}};
+  if (key === "41") return "foo";
+  if (key === "42") return "bar";
+};
+var target = [];
+var proxy = new Proxy(target, {get: getTrap});
+assertTrue(Array.isArray(proxy));
+var object = {foo: true, bar: 666};
+assertEquals('{"foo":true}', JSON.stringify(object, proxy));
+
+
+// Replacer is an arraylike proxy with a bogus length
+
+var getTrap = function(t, key) {
+  if (key === "length") return Symbol();
+  if (key === "41") return "foo";
+  if (key === "42") return "bar";
+};
+var target = [];
+var proxy = new Proxy(target, {get: getTrap});
+assertTrue(Array.isArray(proxy));
+var object = {foo: true, bar: 666};
+assertThrows(() => JSON.stringify(object, proxy), TypeError);
+
+
+// Replacer returns a non-callable non-arraylike proxy
+
+log.length = 0;
+var object = ["foo", 42];
+var target = {baz: 5};
+var proxy = new Proxy(target, handler);
+var replacer = (key, val) => key === "1" ? proxy : val;
+
+assertEquals('["foo",{"baz":5}]', JSON.stringify(object, replacer));
+assertEquals(3, log.length);
+for (var i in log) assertSame(target, log[i][1]);
+
+assertEquals(["ownKeys", target], log[0]);
+assertEquals(["getOwnPropertyDescriptor", target, "baz"], log[1]);
+
+
+// Replacer returns an arraylike proxy
+
+log.length = 0;
+var object = ["foo", 42];
+var target = ["bar"];
+var proxy = new Proxy(target, handler);
+var replacer = (key, val) => key === "1" ? proxy : val;
+
+assertEquals('["foo",["bar"]]', JSON.stringify(object, replacer));
+assertEquals(2, log.length);
+for (var i in log) assertSame(target, log[i][1]);
+
+assertEquals(["get", target, "length", proxy], log[0]);
+assertEquals(["get", target, "0", proxy], log[1]);
+
+
+// Replacer returns an arraylike proxy with a non-trivial length
+
+var getTrap = function(t, key) {
+  if (key === "length") return {[Symbol.toPrimitive]() {return 3}};
+  if (key === "2") return "baz";
+  if (key === "3") return "bar";
+};
+var target = [];
+var proxy = new Proxy(target, {get: getTrap});
+var replacer = (key, val) => key === "goo" ? proxy : val;
+var object = {foo: true, goo: false};
+assertEquals('{"foo":true,"goo":[null,null,"baz"]}',
+    JSON.stringify(object, replacer));
+
+
+// Replacer returns an arraylike proxy with a bogus length
+
+var getTrap = function(t, key) {
+  if (key === "length") return Symbol();
+  if (key === "2") return "baz";
+  if (key === "3") return "bar";
+};
+var target = [];
+var proxy = new Proxy(target, {get: getTrap});
+var replacer = (key, val) => key === "goo" ? proxy : val;
+var object = {foo: true, goo: false};
+assertThrows(() => JSON.stringify(object, replacer), TypeError);
+
+
+// Replacer returns a callable proxy
+
+log.length = 0;
+var target = () => 666;
+var proxy = new Proxy(target, handler);
+var replacer = (key, val) => key === "1" ? proxy : val;
+
+assertEquals('["foo",null]', JSON.stringify(["foo", 42], replacer));
+assertEquals(0, log.length);
+
+assertEquals('{"0":"foo"}', JSON.stringify({0: "foo", 1: 42}, replacer));
+assertEquals(0, log.length);
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// JSON.parse
+
+
+// Reviver is a callable proxy
+
+log.length = 0;
+var target = () => 42;
+var proxy = new Proxy(target, handler);
+assertTrue(typeof proxy === "function");
+
+assertEquals(42, JSON.parse("[true, false]", proxy));
+assertEquals(3, log.length);
+for (var i in log) assertSame(target, log[i][1]);
+
+assertEquals(4, log[0].length);
+assertEquals("apply", log[0][0]);
+assertEquals(["0", true], log[0][3]);
+assertEquals(4, log[1].length);
+assertEquals("apply", log[1][0]);
+assertEquals(["1", false], log[1][3]);
+assertEquals(4, log[2].length);
+assertEquals("apply", log[2][0]);
+assertEquals(["", [42, 42]], log[2][3]);
+
+
+// Reviver plants a non-arraylike proxy into a yet-to-be-visited property
+
+log.length = 0;
+var target = {baz: 42};
+var proxy = new Proxy(target, handler);
+var reviver = function(p, v) {
+  if (p === "baz") return 5;
+  if (p === "foo") this.bar = proxy;
+  return v;
+}
+
+assertEquals({foo: 0, bar: proxy}, JSON.parse('{"foo":0,"bar":1}', reviver));
+assertEquals(4, log.length);
+for (var i in log) assertSame(target, log[i][1]);
+
+assertEquals(["ownKeys", target], log[0]);
+assertEquals(["getOwnPropertyDescriptor", target, "baz"], log[1]);
+assertEquals(["get", target, "baz", proxy], log[2]);
+assertEquals(["defineProperty", target, "baz",
+    {value: 5, configurable: true, writable: true, enumerable: true}], log[3]);
+
+
+// Reviver plants an arraylike proxy into a yet-to-be-visited property
+
+log.length = 0;
+var target = [42];
+var proxy = new Proxy(target, handler);
+assertTrue(Array.isArray(proxy));
+var reviver = function(p, v) {
+  if (p === "0") return undefined;
+  if (p === "foo") this.bar = proxy;
+  return v;
+}
+
+var result = JSON.parse('{"foo":0,"bar":1}', reviver);
+assertEquals({foo: 0, bar: proxy}, result);
+assertSame(result.bar, proxy);
+assertEquals(3, log.length);
+for (var i in log) assertSame(target, log[i][1]);
+
+assertEquals(["get", target, "length", proxy], log[0]);
+assertEquals(["get", target, "0", proxy], log[1]);
+assertEquals(["deleteProperty", target, "0"], log[2]);
diff --git a/test/mjsunit/es6/proxies-keys.js b/test/mjsunit/es6/proxies-keys.js
new file mode 100644
index 0000000..7344032
--- /dev/null
+++ b/test/mjsunit/es6/proxies-keys.js
@@ -0,0 +1,39 @@
+// 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 target = {
+  target: 1
+};
+target.__proto__ = {
+  target_proto: 2
+};
+
+var handler = {
+  ownKeys: function(target) {
+    return ["foo", "bar", Symbol("baz"), "non-enum", "not-found"];
+  },
+  getOwnPropertyDescriptor: function(target, name) {
+    if (name == "non-enum") return {configurable: true};
+    if (name == "not-found") return undefined;
+    return {enumerable: true, configurable: true};
+  }
+}
+
+var proxy = new Proxy(target, handler);
+
+// Object.keys() ignores symbols and non-enumerable keys.
+assertEquals(["foo", "bar"], Object.keys(proxy));
+
+// Edge case: no properties left after filtering.
+handler.getOwnPropertyDescriptor = undefined;
+assertEquals([], Object.keys(proxy));
+
+// Throwing shouldn't crash.
+handler.getOwnPropertyDescriptor = function() { throw new Number(1); };
+assertThrows("Object.keys(proxy)", Number);
+
+// Fall through to target if there is no trap.
+handler.ownKeys = undefined;
+assertEquals(["target"], Object.keys(proxy));
+assertEquals(["target"], Object.keys(target));
diff --git a/test/mjsunit/es6/proxies-object-assign.js b/test/mjsunit/es6/proxies-object-assign.js
new file mode 100644
index 0000000..c350f4e
--- /dev/null
+++ b/test/mjsunit/es6/proxies-object-assign.js
@@ -0,0 +1,28 @@
+// 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 handler = {
+  ownKeys: function(t) { return ["a", "b"]; },
+  getOwnPropertyDescriptor: function(t, p) {
+    return {enumerable: true, configurable: true}
+  },
+  get: function(t, p) {
+    return 1;
+  }
+};
+
+var proxy = new Proxy({}, handler);
+
+var o = {};
+
+Object.assign(o, proxy);
+
+assertEquals({"a": 1, "b": 1}, o);
+
+(function TestStringSources() {
+  var source = "abc";
+  var target = {};
+  Object.assign(target, source);
+  assertEquals({0: "a", 1: "b", 2: "c"}, target);
+})();
diff --git a/test/mjsunit/es6/proxies-ownkeys.js b/test/mjsunit/es6/proxies-ownkeys.js
new file mode 100644
index 0000000..7cc0a87
--- /dev/null
+++ b/test/mjsunit/es6/proxies-ownkeys.js
@@ -0,0 +1,94 @@
+// 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 target = {
+  "target_one": 1
+};
+target.__proto__ = {
+  "target_proto_two": 2
+};
+var handler = {
+  ownKeys: function(target) {
+    return ["foo", "bar"];
+  }
+}
+
+var proxy = new Proxy(target, handler);
+
+// Simple case.
+assertEquals(["foo", "bar"], Reflect.ownKeys(proxy));
+
+// Test interesting steps of the algorithm:
+
+// Step 6: Fall through to target.[[OwnPropertyKeys]] if the trap is undefined.
+handler.ownKeys = undefined;
+assertEquals(["target_one"], Reflect.ownKeys(proxy));
+
+// Step 7: Throwing traps don't crash.
+handler.ownKeys = function(target) { throw 1; };
+assertThrows("Reflect.ownKeys(proxy)");
+
+// Step 8: CreateListFromArrayLike error cases:
+// Returning a non-Object throws.
+var keys = 1;
+handler.ownKeys = function(target) { return keys; };
+assertThrows("Reflect.ownKeys(proxy)", TypeError);
+keys = "string";
+assertThrows("Reflect.ownKeys(proxy)", TypeError);
+keys = Symbol("foo");
+assertThrows("Reflect.ownKeys(proxy)", TypeError);
+keys = null;
+assertThrows("Reflect.ownKeys(proxy)", TypeError);
+
+// "length" property is honored.
+keys = { 0: "a", 1: "b", 2: "c" };
+keys.length = 0;
+assertEquals([], Reflect.ownKeys(proxy));
+keys.length = 1;
+assertEquals(["a"], Reflect.ownKeys(proxy));
+keys.length = 3;
+assertEquals(["a", "b", "c"], Reflect.ownKeys(proxy));
+// The spec wants to allow lengths up to 2^53, but we can't allocate arrays
+// of that size, so we throw even for smaller values.
+keys.length = Math.pow(2, 33);
+assertThrows("Reflect.ownKeys(proxy)", RangeError);
+
+// Check that we allow duplicated keys.
+keys  = ['a', 'a', 'a']
+assertEquals(keys, Reflect.ownKeys(proxy));
+
+// Non-Name results throw.
+keys = [1];
+assertThrows("Reflect.ownKeys(proxy)", TypeError);
+keys = [{}];
+assertThrows("Reflect.ownKeys(proxy)", TypeError);
+keys = [{toString: function() { return "foo"; }}];
+assertThrows("Reflect.ownKeys(proxy)", TypeError);
+keys = [null];
+assertThrows("Reflect.ownKeys(proxy)", TypeError);
+
+// Step 17a: The trap result must include all non-configurable keys.
+Object.defineProperty(target, "nonconf", {value: 1, configurable: false});
+keys = ["foo"];
+assertThrows("Reflect.ownKeys(proxy)", TypeError);
+keys = ["nonconf"];
+assertEquals(keys, Reflect.ownKeys(proxy));
+
+// Check that we allow duplicated keys.
+keys  = ['nonconf', 'nonconf', 'nonconf']
+assertEquals(keys, Reflect.ownKeys(proxy));
+
+// Step 19a: The trap result must all keys of a non-extensible target.
+Object.preventExtensions(target);
+assertThrows("Reflect.ownKeys(proxy)", TypeError);
+keys = ["nonconf", "target_one"];
+assertEquals(keys, Reflect.ownKeys(proxy));
+
+// Step 20: The trap result must not add keys to a non-extensible target.
+keys = ["nonconf", "target_one", "fantasy"];
+assertThrows("Reflect.ownKeys(proxy)", TypeError);
+
+// Check that we allow duplicated keys.
+keys  = ['nonconf', 'target_one', 'nonconf', 'nonconf', 'target_one',]
+assertEquals(keys, Reflect.ownKeys(proxy));
diff --git a/test/mjsunit/es6/proxies-prevent-extensions.js b/test/mjsunit/es6/proxies-prevent-extensions.js
new file mode 100644
index 0000000..dc3c42e
--- /dev/null
+++ b/test/mjsunit/es6/proxies-prevent-extensions.js
@@ -0,0 +1,85 @@
+// 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 () {
+  // No trap.
+
+  var target = {};
+  var handler = {};
+  var proxy = new Proxy(target, handler);
+
+  assertTrue(Reflect.isExtensible(target));
+  assertTrue(Reflect.isExtensible(proxy));
+  assertTrue(Reflect.preventExtensions(proxy));
+  assertFalse(Reflect.isExtensible(target));
+  assertFalse(Reflect.isExtensible(proxy));
+})();
+
+
+(function () {
+  // "Undefined" trap.
+
+  var target = {};
+  var handler = { preventExtensions: null };
+  var proxy = new Proxy(target, handler);
+
+  assertTrue(Reflect.isExtensible(target));
+  assertTrue(Reflect.isExtensible(proxy));
+  assertTrue(Reflect.preventExtensions(proxy));
+  assertFalse(Reflect.isExtensible(target));
+  assertFalse(Reflect.isExtensible(proxy));
+})();
+
+
+(function () {
+  // Invalid trap.
+
+  var target = {};
+  var handler = { preventExtensions: 42 };
+  var proxy = new Proxy(target, handler);
+
+  assertThrows(() => {Reflect.preventExtensions(proxy)}, TypeError);
+})();
+
+
+(function () {
+  var target = {};
+  var handler = { isExtensible() {return "bla"} };
+  var proxy = new Proxy(target, handler);
+
+  // Trap returns trueish and target is extensible.
+  assertTrue(Reflect.isExtensible(proxy));
+
+  // Trap returns trueish but target is not extensible.
+  Reflect.preventExtensions(target);
+  assertThrows(() => {Reflect.isExtensible(proxy)}, TypeError);
+})();
+
+
+(function () {
+  // Trap returns falsish.
+
+  var target = {};
+  var handler = { preventExtensions() {return 0} };
+  var proxy = new Proxy(target, handler);
+
+  assertFalse(Reflect.preventExtensions(proxy));
+  Reflect.preventExtensions(target);
+  assertFalse(Reflect.preventExtensions(proxy));
+})();
+
+
+(function () {
+  var target = {};
+  var handler = { preventExtensions() {return Symbol()} };
+  var proxy = new Proxy(target, handler);
+
+  // Trap returns trueish but target is extensible.
+  assertThrows(() => {Reflect.preventExtensions(proxy)}, TypeError);
+
+  // Trap returns trueish and target is not extensible.
+  Reflect.preventExtensions(target);
+  assertTrue(Reflect.preventExtensions(proxy));
+})();
diff --git a/test/mjsunit/es6/proxies-property-is-enumerable.js b/test/mjsunit/es6/proxies-property-is-enumerable.js
new file mode 100644
index 0000000..0d4a92f
--- /dev/null
+++ b/test/mjsunit/es6/proxies-property-is-enumerable.js
@@ -0,0 +1,28 @@
+// 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 handler = {};
+var target = { a: 1 };
+var proxy = new Proxy(target, handler);
+
+assertTrue(target.propertyIsEnumerable('a'));
+assertTrue(proxy.propertyIsEnumerable('a'));
+assertFalse(target.propertyIsEnumerable('b'));
+assertFalse(proxy.propertyIsEnumerable('b'));
+
+handler.getOwnPropertyDescriptor = function(target, prop) {
+  return { configurable: true, enumerable: true, value: 10 };
+}
+assertTrue(target.propertyIsEnumerable('a'));
+assertTrue(proxy.propertyIsEnumerable('a'));
+assertFalse(target.propertyIsEnumerable('b'));
+assertTrue(proxy.propertyIsEnumerable('b'));
+
+handler.getOwnPropertyDescriptor = function(target, prop) {
+  return { configurable: true, enumerable: false, value: 10 };
+}
+assertTrue(target.propertyIsEnumerable('a'));
+assertFalse(proxy.propertyIsEnumerable('a'));
+assertFalse(target.propertyIsEnumerable('b'));
+assertFalse(proxy.propertyIsEnumerable('b'));
diff --git a/test/mjsunit/es6/proxies-prototype-handler-stackoverflow.js b/test/mjsunit/es6/proxies-prototype-handler-stackoverflow.js
new file mode 100644
index 0000000..3da36c4
--- /dev/null
+++ b/test/mjsunit/es6/proxies-prototype-handler-stackoverflow.js
@@ -0,0 +1,118 @@
+// 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: --stack-size=100
+
+// Test that traps that involve walking the target object's prototype chain
+// don't overflow the stack when the original proxy is on that chain.
+
+(function TestGetPrototype() {
+  var handler = {};
+  var p = new Proxy({}, handler);
+  handler.__proto__ = p;
+  try { return p.__proto__; } catch(e) { assertInstanceof(e, RangeError); }
+})();
+
+(function TestSetPrototype() {
+  var handler = {};
+  var p = new Proxy({}, handler);
+  handler.__proto__ = p;
+  try { p.__proto__ = p; } catch(e) { assertInstanceof(e, RangeError); }
+})();
+
+(function TestHasProperty() {
+  var handler = {};
+  var p = new Proxy({}, handler);
+  handler.__proto__ = p;
+  try {
+    return Reflect.has(p, "foo");
+  } catch(e) { assertInstanceof(e, RangeError); }
+})();
+
+(function TestSet() {
+  var handler = {};
+  var p = new Proxy({}, handler);
+  handler.__proto__ = p;
+  try { p.foo = 1; } catch(e) { assertInstanceof(e, RangeError); }
+})();
+
+(function TestGet() {
+  var handler = {};
+  var p = new Proxy({}, handler);
+  handler.__proto__ = p;
+  try { return p.foo; } catch(e) { assertInstanceof(e, RangeError); }
+})();
+
+(function TestEnumerate() {
+  var handler = {};
+  var p = new Proxy({}, handler);
+  handler.__proto__ = p;
+  try { for (var x in p) {} } catch(e) { assertInstanceof(e, RangeError); }
+})();
+
+(function TestIsExtensible() {
+  var handler = {};
+  var p = new Proxy({}, handler);
+  handler.__proto__ = p;
+  try {
+    return Reflect.isExtensible(p);
+  } catch(e) { assertInstanceof(e, RangeError); }
+})();
+
+(function TestPreventExtensions() {
+  var handler = {};
+  var p = new Proxy({}, handler);
+  handler.__proto__ = p;
+  try {
+    Reflect.preventExtensions(p);
+  } catch(e) { assertInstanceof(e, RangeError); }
+})();
+
+(function TestGetOwnPropertyDescriptor() {
+  var handler = {};
+  var p = new Proxy({}, handler);
+  handler.__proto__ = p;
+  try {
+    return Object.getOwnPropertyDescriptor(p, "foo");
+  } catch(e) { assertInstanceof(e, RangeError); }
+})();
+
+(function TestDeleteProperty() {
+  var handler = {};
+  var p = new Proxy({}, handler);
+  handler.__proto__ = p;
+  try { delete p.foo; } catch(e) { assertInstanceof(e, RangeError); }
+})();
+
+(function TestDefineProperty() {
+  var handler = {};
+  var p = new Proxy({}, handler);
+  handler.__proto__ = p;
+  try {
+    Object.defineProperty(p, "foo", {value: "bar"});
+  } catch(e) { assertInstanceof(e, RangeError); }
+})();
+
+(function TestOwnKeys() {
+  var handler = {};
+  var p = new Proxy({}, handler);
+  handler.__proto__ = p;
+  try {
+    return Reflect.ownKeys(p);
+  } catch(e) { assertInstanceof(e, RangeError); }
+})();
+
+(function TestCall() {
+  var handler = {};
+  var p = new Proxy(function() {}, handler);
+  handler.__proto__ = p;
+  try { return p(); } catch(e) { assertInstanceof(e, RangeError); }
+})();
+
+(function TestConstruct() {
+  var handler = {};
+  var p = new Proxy(function() { this.foo = 1; }, handler);
+  handler.__proto__ = p;
+  try { return new p(); } catch(e) { assertInstanceof(e, RangeError); }
+})();
diff --git a/test/mjsunit/es6/proxies-prototype-target-stackoverflow.js b/test/mjsunit/es6/proxies-prototype-target-stackoverflow.js
new file mode 100644
index 0000000..741a8b0
--- /dev/null
+++ b/test/mjsunit/es6/proxies-prototype-target-stackoverflow.js
@@ -0,0 +1,95 @@
+// 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 that traps that involve walking the target object's prototype chain
+// don't overflow the stack when the original proxy is on that chain.
+
+(function TestGetPrototype() {
+  var p = new Proxy({}, {});
+  p.__proto__ = p;
+  try { return p.__proto__; } catch(e) { assertInstanceof(e, RangeError); }
+})();
+
+(function TestSetPrototype() {
+  var p = new Proxy({}, {});
+  p.__proto__ = p;
+  try { p.__proto__ = p; } catch(e) { assertInstanceof(e, RangeError); }
+})();
+
+(function TestHasProperty() {
+  var p = new Proxy({}, {});
+  p.__proto__ = p;
+  try {
+    return Reflect.has(p, "foo");
+  } catch(e) { assertInstanceof(e, RangeError); }
+})();
+
+(function TestSet() {
+  var p = new Proxy({}, {});
+  p.__proto__ = p;
+  try { p.foo = 1; } catch(e) { assertInstanceof(e, RangeError); }
+})();
+
+(function TestGet() {
+  var p = new Proxy({}, {});
+  p.__proto__ = p;
+  try { return p.foo; } catch(e) { assertInstanceof(e, RangeError); }
+})();
+
+(function TestEnumerate() {
+  var p = new Proxy({}, {});
+  p.__proto__ = p;
+  try { for (var x in p) {} } catch(e) { assertInstanceof(e, RangeError); }
+})();
+
+// The following traps don't involve the target object's prototype chain;
+// we test them anyway for completeness.
+
+(function TestIsExtensible() {
+  var p = new Proxy({}, {});
+  p.__proto__ = p;
+  return Reflect.isExtensible(p);
+})();
+
+(function TestPreventExtensions() {
+  var p = new Proxy({}, {});
+  p.__proto__ = p;
+  Reflect.preventExtensions(p);
+})();
+
+(function TestGetOwnPropertyDescriptor() {
+  var p = new Proxy({}, {});
+  p.__proto__ = p;
+  return Object.getOwnPropertyDescriptor(p, "foo");
+})();
+
+(function TestDeleteProperty() {
+  var p = new Proxy({}, {});
+  p.__proto__ = p;
+  delete p.foo;
+})();
+
+(function TestDefineProperty() {
+  var p = new Proxy({}, {});
+  p.__proto__ = p;
+  Object.defineProperty(p, "foo", {value: "bar"});
+})();
+
+(function TestOwnKeys() {
+  var p = new Proxy({}, {});
+  p.__proto__ = p;
+  return Reflect.ownKeys(p);
+})();
+
+(function TestCall() {
+  var p = new Proxy(function() {}, {});
+  p.__proto__ = p;
+  return p();
+})();
+
+(function TestConstruct() {
+  var p = new Proxy(function() { this.foo = 1; }, {});
+  p.__proto__ = p;
+  return new p();
+})();
diff --git a/test/mjsunit/es6/proxies-revocable.js b/test/mjsunit/es6/proxies-revocable.js
new file mode 100644
index 0000000..1f61174
--- /dev/null
+++ b/test/mjsunit/es6/proxies-revocable.js
@@ -0,0 +1,23 @@
+// 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.
+
+
+traps = [
+    "getPrototypeOf", "setPrototypeOf", "isExtensible", "preventExtensions",
+    "getOwnPropertyDescriptor", "has", "get", "set", "deleteProperty",
+    "defineProperty", "ownKeys", "apply", "construct"
+];
+
+var {proxy, revoke} = Proxy.revocable({}, {});
+assertEquals(0, revoke.length);
+
+assertEquals(undefined, revoke());
+for (var trap of traps) {
+  assertThrows(() => Reflect[trap](proxy), TypeError);
+}
+
+assertEquals(undefined, revoke());
+for (var trap of traps) {
+  assertThrows(() => Reflect[trap](proxy), TypeError);
+}
diff --git a/test/mjsunit/es6/proxies-set-prototype-of.js b/test/mjsunit/es6/proxies-set-prototype-of.js
new file mode 100644
index 0000000..9d9e73f
--- /dev/null
+++ b/test/mjsunit/es6/proxies-set-prototype-of.js
@@ -0,0 +1,128 @@
+// 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 target = { target: 1 };
+target.__proto__ = {};
+var handler = { handler: 1 };
+var proxy = new Proxy(target, handler);
+
+assertSame(Object.getPrototypeOf(proxy), target.__proto__ );
+
+
+assertThrows(function() { Object.setPrototypeOf(proxy, undefined) }, TypeError);
+assertThrows(function() { Object.setPrototypeOf(proxy, 1) }, TypeError);
+
+var prototype = [1];
+assertSame(proxy, Object.setPrototypeOf(proxy, prototype));
+assertSame(prototype, Object.getPrototypeOf(proxy));
+assertSame(prototype, Object.getPrototypeOf(target));
+
+var pair = Proxy.revocable(target, handler);
+assertSame(pair.proxy, Object.setPrototypeOf(pair.proxy, prototype));
+assertSame(prototype, Object.getPrototypeOf(pair.proxy));
+pair.revoke();
+assertThrows('Object.setPrototypeOf(pair.proxy, prototype)', TypeError);
+
+handler.setPrototypeOf = function(target, proto) {
+  return false;
+};
+assertThrows(function() { Object.setPrototypeOf(proxy, {a:1}) }, TypeError);
+
+handler.setPrototypeOf = function(target, proto) {
+  return undefined;
+};
+assertThrows(function() { Object.setPrototypeOf(proxy, {a:2}) }, TypeError);
+
+handler.setPrototypeOf = function(proto) {};
+assertThrows(function() { Object.setPrototypeOf(proxy, {a:3}) }, TypeError);
+
+handler.setPrototypeOf = function(target, proto) {
+  throw Error();
+};
+assertThrows(function() { Object.setPrototypeOf(proxy, {a:4}) }, Error);
+
+var seen_prototype;
+var seen_target;
+handler.setPrototypeOf = function(target, proto) {
+  seen_target = target;
+  seen_prototype = proto;
+  return true;
+}
+assertSame(Object.setPrototypeOf(proxy, {a:5}), proxy);
+assertSame(target, seen_target);
+assertEquals({a:5}, seen_prototype);
+
+(function setPrototypeProxyTarget() {
+  var target = { target: 1 };
+  target.__proto__ = {};
+  var handler = {};
+  var handler2 = {};
+  var target2 = new Proxy(target, handler2);
+  var proxy2 = new Proxy(target2, handler);
+  assertSame(Object.getPrototypeOf(proxy2), target.__proto__ );
+
+  var prototype = [2,3];
+  assertSame(proxy2, Object.setPrototypeOf(proxy2, prototype));
+  assertSame(prototype, Object.getPrototypeOf(proxy2));
+  assertSame(prototype, Object.getPrototypeOf(target));
+})();
+
+(function testProxyTrapInconsistent() {
+  var target = { target: 1 };
+  target.__proto__ = {};
+  var handler = {};
+  var handler2 = {
+  };
+
+  var target2 = new Proxy(target, handler);
+  var proxy2 = new Proxy(target2, handler2);
+
+  // If the final target is extensible we can set any prototype.
+  var prototype = [1];
+  Reflect.setPrototypeOf(proxy2, prototype);
+  assertSame(prototype, Reflect.getPrototypeOf(target));
+
+  handler2.setPrototypeOf = function(target, value) {
+    Reflect.setPrototypeOf(target, value);
+    return true;
+  };
+  prototype = [2];
+  Reflect.setPrototypeOf(proxy2, prototype);
+  assertSame(prototype, Reflect.getPrototypeOf(target));
+
+  // Prevent getting the target's prototype used to check the invariant.
+  var gotPrototype = false;
+  handler.getPrototypeOf = function() {
+    gotPrototype = true;
+    throw TypeError()
+  };
+  // If the target is extensible we do not check the invariant.
+  prototype = [3];
+  Reflect.setPrototypeOf(proxy2, prototype);
+  assertFalse(gotPrototype);
+  assertSame(prototype, Reflect.getPrototypeOf(target));
+
+  // Changing the prototype of a non-extensible target will trigger the
+  // invariant-check and throw in the above handler.
+  Reflect.preventExtensions(target);
+  assertThrows(() => {Reflect.setPrototypeOf(proxy2, [4])}, TypeError);
+  assertTrue(gotPrototype);
+  assertEquals([3], Reflect.getPrototypeOf(target));
+
+  // Setting the prototype of a non-extensible target is fine if the prototype
+  // doesn't change.
+  delete handler.getPrototypeOf;
+  Reflect.setPrototypeOf(proxy2, prototype);
+  // Changing the prototype will throw.
+  prototype = [5];
+  assertThrows(() => {Reflect.setPrototypeOf(proxy2, prototype)}, TypeError);
+})();
+
+(function testProxyTrapReturnsFalse() {
+  var handler = {};
+  handler.setPrototypeOf = () => false;
+  var target = new Proxy({}, {isExtensible: () => assertUnreachable()});
+  var object = new Proxy(target, handler);
+  assertFalse(Reflect.setPrototypeOf(object, {}));
+})();
diff --git a/test/mjsunit/es6/proxies-set.js b/test/mjsunit/es6/proxies-set.js
new file mode 100644
index 0000000..19f39f9
--- /dev/null
+++ b/test/mjsunit/es6/proxies-set.js
@@ -0,0 +1,310 @@
+// 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 sloppyDefaultSet(o, p, v) { return o[p] = v }
+function sloppyReflectSet(o, p, v) { return Reflect.set(o, p, v) }
+function strictDefaultSet(o, p, v) { "use strict"; return o[p] = v }
+function strictReflectSet(o, p, v) { "use strict"; return Reflect.set(o, p, v) }
+
+sloppyDefaultSet.shouldThrow = false;
+sloppyReflectSet.shouldThrow = false;
+strictDefaultSet.shouldThrow = true;
+strictReflectSet.shouldThrow = false;
+
+sloppyDefaultSet.returnsBool = false;
+sloppyReflectSet.returnsBool = true;
+strictDefaultSet.returnsBool = false;
+strictReflectSet.returnsBool = true;
+
+
+function assertTrueIf(flag, x) { if (flag) assertTrue(x) }
+function assertFalseIf(flag, x) { if (flag) assertFalse(x) }
+function assertSetFails(mySet, o, p, v) {
+  if (mySet.shouldThrow) {
+    assertThrows(() => mySet(o, p, v), TypeError);
+  } else {
+    assertFalseIf(mySet.returnsBool, mySet(o, p, v));
+  }
+}
+
+
+function dataDescriptor(x) {
+  return {value: x, writable: true, enumerable: true, configurable: true};
+}
+
+
+function toKey(x) {
+  if (typeof x === "symbol") return x;
+  return String(x);
+}
+
+
+var properties =
+    ["bla", "0", 1, Symbol(), {[Symbol.toPrimitive]() {return "a"}}];
+
+
+function TestForwarding(handler, mySet) {
+  assertTrue(undefined == handler.set);
+  assertTrue(undefined == handler.getOwnPropertyDescriptor);
+  assertTrue(undefined == handler.defineProperty);
+
+  var target = {};
+  var proxy = new Proxy(target, handler);
+
+  // Property does not exist on target.
+  for (var p of properties) {
+    assertTrueIf(mySet.returnsBool, mySet(proxy, p, 42));
+    assertSame(42, target[p]);
+  }
+
+  // Property exists as writable data on target.
+  for (var p of properties) {
+    assertTrueIf(mySet.returnsBool, mySet(proxy, p, 0));
+    assertSame(0, target[p]);
+  }
+
+  // Property exists as non-writable data on target.
+  for (var p of properties) {
+    Object.defineProperty(target, p,
+        {value: 42, configurable: true, writable: false});
+    assertSetFails(mySet, proxy, p, 42);
+    assertSetFails(mySet, proxy, p, 0);
+    assertEquals(42, target[p]);
+  }
+};
+
+(function () {
+  // No trap.
+  var handler = {};
+  TestForwarding(handler, sloppyDefaultSet);
+  TestForwarding(handler, sloppyReflectSet);
+  TestForwarding(handler, strictDefaultSet);
+  TestForwarding(handler, strictReflectSet);
+})();
+
+(function () {
+  // "Undefined" trap.
+  var handler = { set: null };
+  TestForwarding(handler, sloppyDefaultSet);
+  TestForwarding(handler, sloppyReflectSet);
+  TestForwarding(handler, strictDefaultSet);
+  TestForwarding(handler, strictReflectSet);
+})();
+
+
+function TestForwarding2(mySet) {
+  // Check that setting on a proxy without "set" trap correctly triggers its
+  // "getOwnProperty" trap and its "defineProperty" trap.
+
+  var target = {};
+  var handler = {};
+  var observations = [];
+  var proxy = new Proxy(target, handler);
+
+  handler.getOwnPropertyDescriptor = function() {
+      observations.push(arguments);
+      return Reflect.getOwnPropertyDescriptor(...arguments);
+  }
+
+  handler.defineProperty = function() {
+      observations.push(arguments);
+      return Reflect.defineProperty(...arguments);
+  }
+
+  for (var p of properties) {
+    mySet(proxy, p, 42);
+    assertEquals(2, observations.length)
+    assertArrayEquals([target, toKey(p)], observations[0]);
+    assertSame(target, observations[0][0]);
+    assertArrayEquals([target, toKey(p), dataDescriptor(42)], observations[1]);
+    assertSame(target, observations[1][0]);
+    observations = [];
+
+    mySet(proxy, p, 42);
+    assertEquals(2, observations.length)
+    assertArrayEquals([target, toKey(p)], observations[0]);
+    assertSame(target, observations[0][0]);
+    assertArrayEquals([target, toKey(p), {value: 42}], observations[1]);
+    assertSame(target, observations[1][0]);
+    observations = [];
+  }
+}
+
+TestForwarding2(sloppyDefaultSet);
+TestForwarding2(sloppyReflectSet);
+TestForwarding2(strictDefaultSet);
+TestForwarding2(strictReflectSet);
+
+
+function TestInvalidTrap(proxy, mySet) {
+  for (var p of properties) {
+    assertThrows(() => mySet(proxy, p, 42), TypeError);
+  }
+}
+
+(function () {
+  var target = {};
+  var handler = { set: true };
+  var proxy = new Proxy(target, handler);
+
+  TestInvalidTrap(proxy, sloppyDefaultSet);
+  TestInvalidTrap(proxy, sloppyReflectSet);
+  TestInvalidTrap(proxy, strictDefaultSet);
+  TestInvalidTrap(proxy, strictReflectSet);
+})();
+
+
+function TestTrappingFalsish(mySet) {
+  var target = {};
+  var handler = { set() {return ""} };
+  var proxy = new Proxy(target, handler);
+
+  for (var p of properties) {
+    assertSetFails(mySet, proxy, p, 42);
+  }
+}
+
+TestTrappingFalsish(sloppyDefaultSet);
+TestTrappingFalsish(sloppyReflectSet);
+TestTrappingFalsish(strictDefaultSet);
+TestTrappingFalsish(strictReflectSet);
+
+
+function TestTrappingTrueish(mySet) {
+  var target = {};
+  var handler = { set() {return 42} };
+  var proxy = new Proxy(target, handler);
+
+  // Trap returns trueish and property does not exist in target.
+  for (var p of properties) {
+    assertTrueIf(mySet.returnsBool, mySet(proxy, p, 0));
+  }
+
+  // Trap returns trueish and target property is configurable or writable data.
+  for (var p of properties) {
+    Object.defineProperty(target, p, {configurable: true, writable: true});
+    assertTrueIf(mySet.returnsBool, mySet(proxy, p, 0));
+    Object.defineProperty(target, p, {configurable: true, writable: false});
+    assertTrueIf(mySet.returnsBool, mySet(proxy, p, 0));
+    Object.defineProperty(target, p, {configurable: false, writable: true});
+    assertTrueIf(mySet.returnsBool, mySet(proxy, p, 0));
+  }
+}
+
+TestTrappingTrueish(sloppyDefaultSet);
+TestTrappingTrueish(sloppyReflectSet);
+TestTrappingTrueish(strictDefaultSet);
+TestTrappingTrueish(strictReflectSet);
+
+
+function TestTrappingTrueish2(mySet) {
+  var target = {};
+  var handler = { set() {return 42} };
+  var proxy = new Proxy(target, handler);
+
+  // Trap returns trueish but target property is frozen data.
+  for (var p of properties) {
+    Object.defineProperty(target, p, {
+        configurable: false, writable: false, value: 0
+    });
+    assertThrows(() => mySet(proxy, p, 666), TypeError);  // New value.
+    assertTrueIf(mySet.returnsBool, mySet(proxy, p, 0));  // Old value.
+  }
+};
+
+TestTrappingTrueish2(sloppyDefaultSet);
+TestTrappingTrueish2(sloppyReflectSet);
+TestTrappingTrueish2(strictDefaultSet);
+TestTrappingTrueish2(strictReflectSet);
+
+
+function TestTrappingTrueish3(mySet) {
+  var target = {};
+  var handler = { set() {return 42} };
+  var proxy = new Proxy(target, handler);
+
+  // Trap returns trueish and target property is configurable accessor.
+  for (var p of properties) {
+    Object.defineProperty(target, p, { configurable: true, set: undefined });
+    assertTrueIf(mySet.returnsBool, mySet(proxy, p, 0));
+  }
+
+  // Trap returns trueish and target property is non-configurable accessor.
+  for (var p of properties) {
+    Object.defineProperty(target, p, { configurable: false, set: undefined });
+    assertThrows(() => mySet(proxy, p, 0));
+  }
+};
+
+TestTrappingTrueish3(sloppyDefaultSet);
+TestTrappingTrueish3(sloppyReflectSet);
+TestTrappingTrueish3(strictDefaultSet);
+TestTrappingTrueish3(strictReflectSet);
+
+
+function TestTrapReceiverArgument(mySet) {
+  var target = {};
+  var handler = {};
+  var observations = [];
+  var proxy = new Proxy(target, handler);
+  var object = Object.create(proxy);
+
+  handler.set = function() {
+      observations.push(arguments);
+      return Reflect.set(...arguments);
+  }
+
+  for (var p of properties) {
+    mySet(object, p, 42);
+    assertEquals(1, observations.length)
+    assertArrayEquals([target, toKey(p), 42, object], observations[0]);
+    assertSame(target, observations[0][0]);
+    assertSame(object, observations[0][3]);
+    observations = [];
+  }
+};
+
+TestTrapReceiverArgument(sloppyDefaultSet);
+TestTrapReceiverArgument(sloppyReflectSet);
+TestTrapReceiverArgument(strictDefaultSet);
+TestTrapReceiverArgument(strictReflectSet);
+
+
+(function TestTrapReceiverArgument2() {
+  // Check that non-object receiver is passed through as well.
+
+  var target = {};
+  var handler = {};
+  var observations = [];
+  var proxy = new Proxy(target, handler);
+
+  handler.set = function() {
+      observations.push(arguments);
+      return Reflect.set(...arguments);
+  }
+
+  for (var p of properties) {
+    for (var receiver of [null, undefined, 1]) {
+      Reflect.set(proxy, p, 42, receiver);
+      assertEquals(1, observations.length)
+      assertArrayEquals([target, toKey(p), 42, receiver], observations[0]);
+      assertSame(target, observations[0][0]);
+      assertSame(receiver, observations[0][3]);
+      observations = [];
+    }
+  }
+
+  var object = Object.create(proxy);
+  for (var p of properties) {
+    for (var receiver of [null, undefined, 1]) {
+      Reflect.set(object, p, 42, receiver);
+      assertEquals(1, observations.length);
+      assertArrayEquals([target, toKey(p), 42, receiver], observations[0]);
+      assertSame(target, observations[0][0]);
+      assertSame(receiver, observations[0][3]);
+      observations = [];
+    }
+  }
+})();
diff --git a/test/mjsunit/es6/proxies-with-unscopables.js b/test/mjsunit/es6/proxies-with-unscopables.js
new file mode 100644
index 0000000..b9a7ad8
--- /dev/null
+++ b/test/mjsunit/es6/proxies-with-unscopables.js
@@ -0,0 +1,146 @@
+// 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.
+
+
+function TestBasics() {
+  var log = [];
+
+  var proxy = new Proxy({}, {
+    get: function(target, key) {
+      log.push("get " + String(key));
+      if (key === 'x') return 1;
+    },
+    has: function(target, key) {
+      log.push("has " + String(key));
+      if (key === 'x') return true;
+      return false;
+    }
+  });
+
+  var x = 'local';
+
+  with (proxy) {
+    assertEquals(1, x);
+  }
+
+  assertEquals(['has assertEquals', 'has x', 'get Symbol(Symbol.unscopables)',
+                'get x'], log);
+}
+TestBasics();
+
+
+function TestInconsistent() {
+  var log = [];
+
+  var proxy = new Proxy({}, {
+    get: function(target, key) {
+      log.push("get " + String(key));
+      return undefined;
+    },
+    has: function(target, key) {
+      log.push("has " + String(key));
+      if (key === 'x') return true;
+      return false;
+    }
+  });
+
+  var x = 'local';
+
+  with (proxy) {
+    assertEquals(void 0, x);
+  }
+
+  assertEquals(['has assertEquals', 'has x', 'get Symbol(Symbol.unscopables)',
+                'get x'], log);
+}
+TestInconsistent();
+
+
+function TestUseProxyAsUnscopables() {
+  var x = 1;
+  var object = {
+    x: 2
+  };
+  var calls = 0;
+  var proxy = new Proxy({}, {
+    has: function() {
+      assertUnreachable();
+    },
+    get: function(target, key) {
+      assertEquals('x', key);
+      calls++;
+      return calls === 2 ? true : undefined;
+    }
+  });
+
+  object[Symbol.unscopables] = proxy;
+
+  with (object) {
+    assertEquals(2, x);
+    assertEquals(1, x);
+  }
+
+  // HasBinding, HasBinding
+  assertEquals(2, calls);
+}
+TestUseProxyAsUnscopables();
+
+
+function TestThrowInHasUnscopables() {
+  var x = 1;
+  var object = {
+    x: 2
+  };
+
+  function CustomError() {}
+
+  var calls = 0;
+  var proxy = new Proxy({}, {
+    has: function() {
+      assertUnreachable();
+    },
+    get: function(target, key) {
+      if (calls++ === 0) {
+        throw new CustomError();
+      }
+      assertUnreachable();
+    }
+  });
+
+  object[Symbol.unscopables] = proxy;
+
+  assertThrows(function() {
+    with (object) {
+      x;
+    }
+  }, CustomError);
+}
+TestThrowInHasUnscopables();
+
+
+var global = this;
+function TestGlobalShouldIgnoreUnscopables() {
+  global.x = 1;
+  var proxy = new Proxy({}, {
+    get: function() {
+      assertUnreachable();
+    },
+    has: function() {
+      assertUnreachable();
+    }
+  });
+  global[Symbol.unscopables] = proxy;
+
+  assertEquals(1, global.x);
+  assertEquals(1, x);
+
+  global.x = 2;
+  assertEquals(2, global.x);
+  assertEquals(2, x);
+
+  x = 3;
+  assertEquals(3, global.x);
+  assertEquals(3, x);
+}
+TestGlobalShouldIgnoreUnscopables();
diff --git a/test/mjsunit/es6/proxies-with.js b/test/mjsunit/es6/proxies-with.js
new file mode 100644
index 0000000..710e8b5
--- /dev/null
+++ b/test/mjsunit/es6/proxies-with.js
@@ -0,0 +1,351 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// Helper.
+
+function TestWithProxies(test, x, y, z) {
+  test(function(h) { return new Proxy({}, h) }, x, y, z)
+  test(function(h) {
+      return new Proxy(function() {}, h)
+  }, x, y, z)
+}
+
+
+
+// Getting.
+
+function TestWithGet(handler) {
+  TestWithProxies(TestWithGet2, handler)
+}
+
+var c = "global"
+var key = ""
+
+function TestWithGet2(create, handler) {
+  var b = "local"
+
+  var p = create(handler);
+  assertEquals("onproxy", p.a);
+  assertEquals(undefined, p.b);
+  assertEquals(undefined, p.c);
+
+  with (p) {
+    assertEquals("onproxy", a);
+    assertEquals("local", b);
+    assertEquals("global", c);
+  }
+
+  var o = Object.create(p, {d: {value: "own"}})
+  with (o) {
+    assertEquals("onproxy", a)
+    assertEquals("local", b);
+    assertEquals("global", c)
+    assertEquals("own", d)
+  }
+}
+
+TestWithGet({
+  get(target, k) {
+    key = k;
+    return k === "a" ? "onproxy" : undefined
+  },
+  has(target, k) { return k === 'a' }
+})
+
+TestWithGet({
+  get: function(r, k) { return this.get2(r, k) },
+  get2: function(r, k) { key = k; return k === "a" ? "onproxy" : undefined },
+  has(target, k) { return k === 'a' }
+})
+
+
+
+
+// Invoking.
+
+function TestWithGetCall(handler) {
+  TestWithProxies(TestWithGetCall2, handler)
+}
+
+var receiver = null
+var c = function() { return "global" }
+
+function TestWithGetCall2(create, handler) {
+  var b = function() { return "local" }
+
+  var p = create(handler)
+  with (p) {
+    receiver = null
+    assertEquals("onproxy", a())
+    assertSame(p, receiver)
+    assertEquals("local", b())
+    assertEquals("global", c())
+  }
+
+  var o = Object.create(p, {d: {value: function() { return "own" }}})
+  with (o) {
+    receiver = null
+    assertEquals("onproxy", a())
+    assertSame(o, receiver)
+    assertEquals("local", b())
+    assertEquals("global", c())
+    assertEquals("own", d())
+  }
+}
+
+function onproxy() { receiver = this; return "onproxy" }
+
+TestWithGetCall({
+  get: function(r, k) { key = k; return k === "a" ? onproxy : undefined },
+  has: function(t, k) {
+    key = k;
+    return k === "a";
+  }
+})
+
+TestWithGetCall({
+  get: function(r, k) { return this.get2(r, k) },
+  get2: function(r, k) { key = k; return k === "a" ? onproxy : undefined },
+  has: function(t, k) {
+    key = k;
+    return k === "a";
+  }
+})
+
+TestWithGetCall({
+  get: function(r, k) { key = k; return k === "a" ? onproxy : undefined },
+  has: function(t, k) {
+    return this.has2(k)
+  },
+  has2: function(k) {
+    key = k;
+    return k === "a";
+  }
+})
+
+TestWithGetCall({
+  get: function(r, k) { key = k; return k === "a" ? onproxy : undefined },
+  has: function(t, k) {
+    key = k;
+    return k === "a";
+  }
+})
+
+
+function TestWithGetCallThrow(handler) {
+  TestWithProxies(TestWithGetCallThrow2, handler)
+}
+
+function TestWithGetCallThrow2(create, handler) {
+  var b = function() { return "local" }
+
+  var p = create(handler)
+  with (p) {
+    assertThrowsEquals(function(){ a() }, "myexn")
+    assertEquals("local", b())
+    assertEquals("global", c())
+  }
+
+  var o = Object.create(p, {d: {value: function() { return "own" }}})
+  with (o) {
+    assertThrowsEquals(function(){ a() }, "myexn")
+    assertEquals("local", b())
+    assertEquals("global", c())
+    assertEquals("own", d())
+  }
+}
+
+function onproxythrow() { throw "myexn" }
+
+TestWithGetCallThrow({
+  has: function(r, k) { return k === "a"; },
+  get: function(r, k) { key = k; return k === "a" ? onproxythrow : undefined },
+})
+
+TestWithGetCallThrow({
+  has: function(r, k) { return k === "a"; },
+  get: function(r, k) { return this.get2(r, k) },
+  get2: function(r, k) { key = k; return k === "a" ? onproxythrow : undefined },
+})
+
+
+
+// Setting.
+
+var key
+var val
+
+function TestWithSet(handler, hasSetter) {
+  TestWithProxies(TestWithSet2, handler, hasSetter)
+}
+
+var c = "global"
+
+function TestWithSet2(create, handler, hasSetter) {
+  var b = "local"
+
+  var p = create(handler)
+  key = val = undefined
+  with (p) {
+    a = "set"
+    assertEquals("a", key)
+    assertEquals("set", val)
+    assertEquals("local", b)
+    assertEquals("global", c)
+    b = "local"
+    c = "global"
+    assertEquals("a", key)
+    assertEquals("set", val)
+  }
+
+  if (!hasSetter) return
+
+  var o = Object.create(p, {d: {value: "own"}})
+  key = val = undefined
+  with (o) {
+    a = "set"
+    assertEquals("a", key)
+    assertEquals("set", val)
+    assertEquals("local", b)
+    assertEquals("global", c)
+    assertEquals("own", d)
+    b = "local"
+    c = "global"
+    d = "own"
+    assertEquals("a", key)
+    assertEquals("set", val)
+  }
+}
+
+TestWithSet({
+  set: function(r, k, v) { key = k; val = v; return true },
+  has: function(t, k) {
+    return k === "a"
+  }
+})
+
+TestWithSet({
+  set: function(r, k, v) { return this.set2(r, k, v) },
+  set2: function(r, k, v) { key = k; val = v; return true },
+  has: function(t, k) {
+    return k === "a"
+  }
+})
+
+TestWithSet({
+  has: function(t, k) {
+    return k === "a"
+  },
+  defineProperty: function(t, k, desc) { key = k; val = desc.value }
+})
+
+TestWithSet({
+  has: function(t, k) {
+    return this.has2(k)
+  },
+  has2: function(k) {
+    return k === "a"
+  },
+  defineProperty: function(t, k, desc) { this.defineProperty2(k, desc) },
+  defineProperty2: function(k, desc) { key = k; val = desc.value }
+})
+
+TestWithSet({
+  has: function(t, k) {
+    return k === "a"
+  },
+  defineProperty: function(t, k, desc) { key = k; val = desc.value }
+})
+
+TestWithSet({
+  has: function(t, k) {
+    return this.has2(k) },
+  has2: function(k) {
+    return k === "a"
+  },
+  set: function(t, k, v) { key = k; val = v; return true }
+}, true)
+
+TestWithSet({
+  has: function(t, k) {
+    return k === "a"
+  },
+  defineProperty: function(t, k, desc) { key = k; val = desc.value }
+})
+
+
+function TestWithSetThrow(handler, hasSetter) {
+  TestWithProxies(TestWithSetThrow2, handler, hasSetter)
+}
+
+function TestWithSetThrow2(create, handler, hasSetter) {
+  var p = create(handler)
+  assertThrowsEquals(function(){
+    with (p) {
+      a = 1
+    }
+  }, "myexn")
+
+  if (!hasSetter) return
+
+  var o = Object.create(p, {})
+  assertThrowsEquals(function(){
+    with (o) {
+      a = 1
+    }
+  }, "myexn")
+}
+
+TestWithSetThrow({
+  set: function() { throw "myexn" },
+  has: function(t, k) {
+    return k === "a"
+  }
+})
+
+TestWithSetThrow({
+  has: function() { throw "myexn" },
+})
+
+TestWithSetThrow({
+  has: function() { throw "myexn" },
+})
+
+TestWithSetThrow({
+  has: function(t, k) {
+    return k === "a"
+  },
+  defineProperty: function() { throw "myexn" }
+})
+
+TestWithSetThrow({
+  has: function(t, k) {
+    return k === "a"
+  },
+  set: function() { throw "myexn" }
+}, true)
diff --git a/test/mjsunit/es6/proxies.js b/test/mjsunit/es6/proxies.js
new file mode 100644
index 0000000..3b9a4c5
--- /dev/null
+++ b/test/mjsunit/es6/proxies.js
@@ -0,0 +1,1506 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// We change the stack size for the ARM64 simulator because at one point this
+// test enters an infinite recursion which goes through the runtime and we
+// overflow the system stack before the simulator stack.
+
+// Flags: --sim-stack-size=500 --allow-natives-syntax
+
+
+// Helper.
+
+function TestWithProxies(test, x, y, z) {
+  // Separate function for nicer stack traces.
+  TestWithObjectProxy(test, x, y, z);
+  TestWithFunctionProxy(test, x, y, z);
+}
+
+function TestWithObjectProxy(test, x, y, z) {
+  test((handler) => { return new Proxy({}, handler) }, x, y, z)
+
+}
+
+function TestWithFunctionProxy(test, x, y, z) {
+  test((handler) => { return new Proxy(() => {}, handler) }, x, y, z)
+}
+
+// ---------------------------------------------------------------------------
+// Getting property descriptors (Object.getOwnPropertyDescriptor).
+
+var key
+
+function TestGetOwnProperty(handler) {
+  TestWithProxies(TestGetOwnProperty2, handler)
+}
+
+function TestGetOwnProperty2(create, handler) {
+  var p = create(handler)
+  assertEquals(42, Object.getOwnPropertyDescriptor(p, "a").value)
+  assertEquals("a", key)
+  assertEquals(42, Object.getOwnPropertyDescriptor(p, 99).value)
+  assertEquals("99", key)
+}
+
+TestGetOwnProperty({
+  getOwnPropertyDescriptor(target, k) {
+    key = k
+    return {value: 42, configurable: true}
+  }
+})
+
+TestGetOwnProperty({
+  getOwnPropertyDescriptor(target, k) {
+    return this.getOwnPropertyDescriptor2(k)
+  },
+  getOwnPropertyDescriptor2(k) {
+    key = k
+    return {value: 42, configurable: true}
+  }
+})
+
+TestGetOwnProperty({
+  getOwnPropertyDescriptor(target, k) {
+    key = k
+    return {get value() { return 42 }, get configurable() { return true }}
+  }
+})
+
+TestGetOwnProperty(new Proxy({}, {
+  get(target, pk, receiver) {
+    return function(t, k) { key = k; return {value: 42, configurable: true} }
+  }
+}))
+
+
+// ---------------------------------------------------------------------------
+function TestGetOwnPropertyThrow(handler) {
+  TestWithProxies(TestGetOwnPropertyThrow2, handler)
+}
+
+function TestGetOwnPropertyThrow2(create, handler) {
+  var p = create(handler)
+  assertThrowsEquals(() => Object.getOwnPropertyDescriptor(p, "a"), "myexn")
+  assertThrowsEquals(() => Object.getOwnPropertyDescriptor(p, 77), "myexn")
+}
+
+TestGetOwnPropertyThrow({
+  getOwnPropertyDescriptor: function(k) { throw "myexn" }
+})
+
+TestGetOwnPropertyThrow({
+  getOwnPropertyDescriptor: function(k) {
+    return this.getOwnPropertyDescriptor2(k)
+  },
+  getOwnPropertyDescriptor2: function(k) { throw "myexn" }
+})
+
+TestGetOwnPropertyThrow({
+  getOwnPropertyDescriptor: function(k) {
+    return {get value() { throw "myexn" }}
+  }
+})
+
+TestGetOwnPropertyThrow(new Proxy({}, {
+  get: function(pr, pk) {
+    return function(k) { throw "myexn" }
+  }
+}))
+
+
+// ---------------------------------------------------------------------------
+// Getters (dot, brackets).
+
+var key
+
+function TestGet(handler) {
+  TestWithProxies(TestGet2, handler)
+}
+
+function TestGet2(create, handler) {
+  var p = create(handler)
+  assertEquals(42, p.a)
+  assertEquals("a", key)
+  assertEquals(42, p["b"])
+  assertEquals("b", key)
+  assertEquals(42, p[99])
+  assertEquals("99", key)
+  assertEquals(42, (function(n) { return p[n] })("c"))
+  assertEquals("c", key)
+  assertEquals(42, (function(n) { return p[n] })(101))
+  assertEquals("101", key)
+
+  var o = Object.create(p, {x: {value: 88}})
+  assertEquals(42, o.a)
+  assertEquals("a", key)
+  assertEquals(42, o["b"])
+  assertEquals("b", key)
+  assertEquals(42, o[99])
+  assertEquals("99", key)
+  assertEquals(88, o.x)
+  assertEquals(88, o["x"])
+  assertEquals(42, (function(n) { return o[n] })("c"))
+  assertEquals("c", key)
+  assertEquals(42, (function(n) { return o[n] })(101))
+  assertEquals("101", key)
+  assertEquals(88, (function(n) { return o[n] })("x"))
+}
+
+TestGet({
+  get(t, k, r) { key = k; return 42 }
+})
+
+TestGet({
+  get(t, k, r) { return this.get2(r, k) },
+  get2(r, k) { key = k; return 42 }
+})
+
+TestGet(new Proxy({}, {
+  get(pt, pk, pr) {
+    return function(t, k, r) { key = k; return 42 }
+  }
+}))
+
+
+// ---------------------------------------------------------------------------
+function TestGetCall(handler) {
+  TestWithProxies(TestGetCall2, handler)
+}
+
+function TestGetCall2(create, handler) {
+  var p = create(handler)
+  assertEquals(55, p.f())
+  assertEquals(55, p["f"]())
+  assertEquals(55, p.f("unused", "arguments"))
+  assertEquals(55, p.f.call(p))
+  assertEquals(55, p["f"].call(p))
+  assertEquals(55, p[101].call(p))
+  assertEquals(55, p.withargs(45, 5))
+  assertEquals(55, p.withargs.call(p, 11, 22))
+  assertEquals(55, (function(n) { return p[n]() })("f"))
+  assertEquals(55, (function(n) { return p[n].call(p) })("f"))
+  assertEquals(55, (function(n) { return p[n](15, 20) })("withargs"))
+  assertEquals(55, (function(n) { return p[n].call(p, 13, 21) })("withargs"))
+  assertEquals("6655", "66" + p)  // calls p.toString
+
+  var o = Object.create(p, {g: {value: function(x) { return x + 88 }}})
+  assertEquals(55, o.f())
+  assertEquals(55, o["f"]())
+  assertEquals(55, o.f("unused", "arguments"))
+  assertEquals(55, o.f.call(o))
+  assertEquals(55, o.f.call(p))
+  assertEquals(55, o["f"].call(p))
+  assertEquals(55, o[101].call(p))
+  assertEquals(55, o.withargs(45, 5))
+  assertEquals(55, o.withargs.call(p, 11, 22))
+  assertEquals(90, o.g(2))
+  assertEquals(91, o.g.call(o, 3))
+  assertEquals(92, o.g.call(p, 4))
+  assertEquals(55, (function(n) { return o[n]() })("f"))
+  assertEquals(55, (function(n) { return o[n].call(o) })("f"))
+  assertEquals(55, (function(n) { return o[n](15, 20) })("withargs"))
+  assertEquals(55, (function(n) { return o[n].call(o, 13, 21) })("withargs"))
+  assertEquals(93, (function(n) { return o[n](5) })("g"))
+  assertEquals(94, (function(n) { return o[n].call(o, 6) })("g"))
+  assertEquals(95, (function(n) { return o[n].call(p, 7) })("g"))
+  assertEquals("6655", "66" + o)  // calls o.toString
+}
+
+TestGetCall({
+  get(t, k, r) { return () => { return 55 } }
+})
+
+TestGetCall({
+  get(t, k, r)  { return this.get2(t, k, r) },
+  get2(t, k, r) { return () => { return 55 } }
+})
+
+TestGetCall({
+  get(t, k, r) {
+    if (k == "gg") {
+      return () => { return 55 }
+    } else if (k == "withargs") {
+      return (n, m) => { return n + m * 2 }
+    } else {
+      return () => { return r.gg() }
+    }
+  }
+})
+
+TestGetCall(new Proxy({}, {
+  get(pt, pk, pr) {
+    return (t, k, r) => { return () => { return 55 } }
+  }
+}))
+
+
+// ---------------------------------------------------------------------------
+function TestGetThrow(handler) {
+  TestWithProxies(TestGetThrow2, handler)
+}
+
+function TestGetThrow2(create, handler) {
+  var p = create(handler)
+  assertThrowsEquals(function(){ p.a }, "myexn")
+  assertThrowsEquals(function(){ p["b"] }, "myexn")
+  assertThrowsEquals(function(){ p[3] }, "myexn")
+  assertThrowsEquals(function(){ (function(n) { p[n] })("c") }, "myexn")
+  assertThrowsEquals(function(){ (function(n) { p[n] })(99) }, "myexn")
+
+  var o = Object.create(p, {x: {value: 88}, '4': {value: 89}})
+  assertThrowsEquals(function(){ o.a }, "myexn")
+  assertThrowsEquals(function(){ o["b"] }, "myexn")
+  assertThrowsEquals(function(){ o[3] }, "myexn")
+  assertThrowsEquals(function(){ (function(n) { o[n] })("c") }, "myexn")
+  assertThrowsEquals(function(){ (function(n) { o[n] })(99) }, "myexn")
+}
+
+TestGetThrow({
+  get(r, k) { throw "myexn" }
+})
+
+TestGetThrow({
+  get(r, k) { return this.get2(r, k) },
+  get2(r, k) { throw "myexn" }
+})
+
+TestGetThrow(new Proxy({}, {
+  get(pr, pk) { throw "myexn" }
+}))
+
+TestGetThrow(new Proxy({}, {
+  get(pr, pk) {
+    return function(r, k) { throw "myexn" }
+  }
+}))
+
+
+// ---------------------------------------------------------------------------
+// Setters.
+
+var key
+var val
+
+function TestSet(handler) {
+  TestWithProxies(TestSet2, handler)
+}
+
+function TestSet2(create, handler) {
+  var p = create(handler)
+  assertEquals(42, p.a = 42)
+  assertEquals("a", key)
+  assertEquals(42, val)
+  assertEquals(43, p["b"] = 43)
+  assertEquals("b", key)
+  assertEquals(43, val)
+  assertEquals(44, p[77] = 44)
+  assertEquals("77", key)
+  assertEquals(44, val)
+
+  assertEquals(45, (function(n) { return p[n] = 45 })("c"))
+  assertEquals("c", key)
+  assertEquals(45, val)
+  assertEquals(46, (function(n) { return p[n] = 46 })(99))
+  assertEquals("99", key)
+  assertEquals(46, val)
+
+  assertEquals(47, p["0"] = 47)
+  assertEquals("0", key)
+  assertEquals(47, val)
+}
+
+TestSet({
+  set: function(r, k, v) { key = k; val = v; return true }
+})
+
+TestSet({
+  set: function(r, k, v) { return this.set2(r, k, v) },
+  set2: function(r, k, v) { key = k; val = v; return true }
+})
+
+TestSet(new Proxy({}, {
+  get(pk, pr) {
+    return (r, k, v) => { key = k; val = v; return true }
+  }
+}))
+
+
+// ---------------------------------------------------------------------------
+function TestSetThrow(handler) {
+  TestWithProxies(TestSetThrow2, handler)
+}
+
+function TestSetThrow2(create, handler) {
+  var p = create(handler)
+  assertThrowsEquals(function(){ p.a = 42 }, "myexn")
+  assertThrowsEquals(function(){ p["b"] = 42 }, "myexn")
+  assertThrowsEquals(function(){ p[22] = 42 }, "myexn")
+  assertThrowsEquals(function(){ (function(n) { p[n] = 45 })("c") }, "myexn")
+  assertThrowsEquals(function(){ (function(n) { p[n] = 46 })(99) }, "myexn")
+}
+
+TestSetThrow({
+  set: function(r, k, v) { throw "myexn" }
+})
+
+TestSetThrow({
+  set: function(r, k, v) { return this.set2(r, k, v) },
+  set2: function(r, k, v) { throw "myexn" }
+})
+
+TestSetThrow({
+  getOwnPropertyDescriptor: function(k) { throw "myexn" },
+  defineProperty: function(k, desc) { key = k; val = desc.value }
+})
+
+TestSetThrow({
+  getOwnPropertyDescriptor: function(k) {
+    return {configurable: true, writable: true}
+  },
+  defineProperty: function(k, desc) { throw "myexn" }
+})
+
+TestSetThrow({
+  getOwnPropertyDescriptor: function(k) {
+    return this.getOwnPropertyDescriptor2(k)
+  },
+  getOwnPropertyDescriptor2: function(k) { throw "myexn" },
+  defineProperty: function(k, desc) { this.defineProperty2(k, desc) },
+  defineProperty2: function(k, desc) { key = k; val = desc.value }
+})
+
+TestSetThrow({
+  getOwnPropertyDescriptor: function(k) {
+    return this.getOwnPropertyDescriptor2(k)
+  },
+  getOwnPropertyDescriptor2: function(k) {
+    return {configurable: true, writable: true}
+  },
+  defineProperty: function(k, desc) { this.defineProperty2(k, desc) },
+  defineProperty2: function(k, desc) { throw "myexn" }
+})
+
+TestSetThrow({
+  getOwnPropertyDescriptor: function(k) { throw "myexn" },
+  defineProperty: function(k, desc) { key = k; val = desc.value }
+})
+
+TestSetThrow({
+  getOwnPropertyDescriptor: function(k) {
+    return {
+      get configurable() { return true },
+      get writable() { return true }
+    }
+  },
+  defineProperty: function(k, desc) { throw "myexn" }
+})
+
+TestSetThrow({
+  getOwnPropertyDescriptor: function(k) { throw "myexn" }
+})
+
+TestSetThrow({
+  getOwnPropertyDescriptor: function(k) { throw "myexn" },
+  defineProperty: function(k, desc) { key = k; val = desc.value }
+})
+
+TestSetThrow(new Proxy({}, {
+  get: function(pr, pk) { throw "myexn" }
+}))
+
+TestSetThrow(new Proxy({}, {
+  get: function(pr, pk) {
+    return function(r, k, v) { throw "myexn" }
+  }
+}))
+
+// ---------------------------------------------------------------------------
+
+// Evil proxy-induced side-effects shouldn't crash.
+TestWithProxies(function(create) {
+  var calls = 0
+  var handler = {
+    getPropertyDescriptor: function() {
+      ++calls
+      return (calls % 2 == 1)
+        ? {get: function() { return 5 }, configurable: true}
+        : {set: function() { return false }, configurable: true}
+    }
+  }
+  var p = create(handler)
+  var o = Object.create(p)
+  // Make proxy prototype property read-only after CanPut check.
+  try { o.x = 4 } catch (e) { assertInstanceof(e, Error) }
+})
+
+TestWithProxies(function(create) {
+  var handler = {
+    getPropertyDescriptor: function() {
+      Object.defineProperty(o, "x", {get: function() { return 5 }});
+      return {set: function() {}}
+    }
+  }
+  var p = create(handler)
+  var o = Object.create(p)
+  // Make object property read-only after CanPut check.
+  try { o.x = 4 } catch (e) { assertInstanceof(e, Error) }
+})
+
+
+// ---------------------------------------------------------------------------
+// Property definition (Object.defineProperty and Object.defineProperties).
+
+var key
+var desc
+
+function TestDefine(handler) {
+  TestWithProxies(TestDefine2, handler)
+}
+
+function TestDefine2(create, handler) {
+  var p = create(handler)
+  assertEquals(p, Object.defineProperty(p, "a", {value: 44}))
+  assertEquals("a", key)
+  assertEquals(1, Object.getOwnPropertyNames(desc).length)
+  assertEquals(44, desc.value)
+
+  assertEquals(p, Object.defineProperty(p, "b", {value: 45, writable: false}))
+  assertEquals("b", key)
+  assertEquals(2, Object.getOwnPropertyNames(desc).length)
+  assertEquals(45, desc.value)
+  assertEquals(false, desc.writable)
+
+  assertEquals(p, Object.defineProperty(p, "c", {value: 46, enumerable: false}))
+  assertEquals("c", key)
+  assertEquals(2, Object.getOwnPropertyNames(desc).length)
+  assertEquals(46, desc.value)
+  assertEquals(false, desc.enumerable)
+
+  assertEquals(p, Object.defineProperty(p, 101, {value: 47, enumerable: false}))
+  assertEquals("101", key)
+  assertEquals(2, Object.getOwnPropertyNames(desc).length)
+  assertEquals(47, desc.value)
+  assertEquals(false, desc.enumerable)
+
+  var attributes = {configurable: true, mine: 66, minetoo: 23}
+  assertEquals(p, Object.defineProperty(p, "d", attributes))
+  assertEquals("d", key);
+  // Modifying the attributes object after the fact should have no effect.
+  attributes.configurable = false
+  attributes.mine = 77
+  delete attributes.minetoo;
+  assertEquals(1, Object.getOwnPropertyNames(desc).length)
+  assertEquals(true, desc.configurable)
+  assertEquals(undefined, desc.mine)
+  assertEquals(undefined, desc.minetoo)
+
+  assertEquals(p, Object.defineProperty(p, "e", {get: function(){ return 5 }}))
+  assertEquals("e", key)
+  assertEquals(1, Object.getOwnPropertyNames(desc).length)
+  assertEquals(5, desc.get())
+
+  assertEquals(p, Object.defineProperty(p, "zzz", {}))
+  assertEquals("zzz", key)
+  assertEquals(0, Object.getOwnPropertyNames(desc).length)
+
+  var props = {
+    '11': {},
+    blub: {get: function() { return true }},
+    '': {get value() { return 20 }},
+    last: {value: 21, configurable: true, mine: "eyes"}
+  }
+  Object.defineProperty(props, "hidden", {value: "hidden", enumerable: false})
+  assertEquals(p, Object.defineProperties(p, props))
+  assertEquals("last", key)
+  assertEquals(2, Object.getOwnPropertyNames(desc).length)
+  assertEquals(21, desc.value)
+  assertEquals(true, desc.configurable)
+  assertEquals(undefined, desc.mine)  // Arguably a bug in the spec...
+
+  var props = {bla: {get value() { throw "myexn" }}}
+  assertThrowsEquals(function(){ Object.defineProperties(p, props) }, "myexn")
+}
+
+TestDefine({
+  defineProperty(t, k, d) { key = k; desc = d; return true }
+})
+
+TestDefine({
+  defineProperty(t, k, d) { return this.defineProperty2(k, d) },
+  defineProperty2(k, d) { key = k; desc = d; return true }
+})
+
+
+// ---------------------------------------------------------------------------
+function TestDefineThrow(handler) {
+  TestWithProxies(TestDefineThrow2, handler)
+}
+
+function TestDefineThrow2(create, handler) {
+  var p = create(handler)
+  assertThrowsEquals(() => Object.defineProperty(p, "a", {value: 44}), "myexn")
+  assertThrowsEquals(() => Object.defineProperty(p, 0, {value: 44}), "myexn")
+
+  var d1 = create({
+    get: function(r, k) { throw "myexn" },
+    getOwnPropertyNames: function() { return ["value"] }
+  })
+  assertThrowsEquals(function(){ Object.defineProperty(p, "p", d1) }, "myexn")
+  var d2 = create({
+    get: function(r, k) { return 77 },
+    getOwnPropertyNames: function() { throw "myexn" }
+  })
+  assertThrowsEquals(function(){ Object.defineProperty(p, "p", d2) }, "myexn")
+
+  var props = {bla: {get value() { throw "otherexn" }}}
+  assertThrowsEquals(() => Object.defineProperties(p, props), "otherexn")
+}
+
+TestDefineThrow({
+  defineProperty: function(k, d) { throw "myexn" }
+})
+
+TestDefineThrow({
+  defineProperty: function(k, d) { return this.defineProperty2(k, d) },
+  defineProperty2: function(k, d) { throw "myexn" }
+})
+
+TestDefineThrow(new Proxy({}, {
+  get: function(pr, pk) { throw "myexn" }
+}))
+
+TestDefineThrow(new Proxy({}, {
+  get: function(pr, pk) {
+    return function(k, d) { throw "myexn" }
+  }
+}))
+
+
+
+// ---------------------------------------------------------------------------
+// Property deletion (delete).
+
+var key
+
+function TestDelete(handler) {
+  TestWithProxies(TestDelete2, handler)
+}
+
+function TestDelete2(create, handler) {
+  var p = create(handler)
+  assertEquals(true, delete p.a)
+  assertEquals("a", key)
+  assertEquals(true, delete p["b"])
+  assertEquals("b", key)
+  assertEquals(true, delete p[1])
+  assertEquals("1", key)
+
+  assertEquals(false, delete p.z1)
+  assertEquals("z1", key)
+  assertEquals(false, delete p["z2"])
+  assertEquals("z2", key);
+
+  (function() {
+    "use strict"
+    assertEquals(true, delete p.c)
+    assertEquals("c", key)
+    assertEquals(true, delete p["d"])
+    assertEquals("d", key)
+    assertEquals(true, delete p[2])
+    assertEquals("2", key)
+
+    assertThrows(function(){ delete p.z3 }, TypeError)
+    assertEquals("z3", key)
+    assertThrows(function(){ delete p["z4"] }, TypeError)
+    assertEquals("z4", key)
+  })()
+}
+
+TestDelete({
+  deleteProperty(target, k) { key = k; return k < "z" }
+})
+
+TestDelete({
+  deleteProperty(target, k) { return this.delete2(k) },
+  delete2: function(k) { key = k; return k < "z" }
+})
+
+TestDelete(new Proxy({}, {
+  get(pt, pk, pr) {
+    return (target, k) => { key = k; return k < "z" }
+  }
+}))
+
+
+// ---------------------------------------------------------------------------
+function TestDeleteThrow(handler) {
+  TestWithProxies(TestDeleteThrow2, handler)
+}
+
+function TestDeleteThrow2(create, handler) {
+  var p = create(handler)
+  assertThrowsEquals(function(){ delete p.a }, "myexn")
+  assertThrowsEquals(function(){ delete p["b"] }, "myexn");
+  assertThrowsEquals(function(){ delete p[3] }, "myexn");
+
+  (function() {
+    "use strict"
+    assertThrowsEquals(function(){ delete p.c }, "myexn")
+    assertThrowsEquals(function(){ delete p["d"] }, "myexn")
+    assertThrowsEquals(function(){ delete p[4] }, "myexn");
+  })()
+}
+
+TestDeleteThrow({
+  deleteProperty(t, k) { throw "myexn" }
+})
+
+TestDeleteThrow({
+  deleteProperty(t, k) { return this.delete2(k) },
+  delete2(k) { throw "myexn" }
+})
+
+TestDeleteThrow(new Proxy({}, {
+  get(pt, pk, pr) { throw "myexn" }
+}))
+
+TestDeleteThrow(new Proxy({}, {
+  get(pt, pk, pr) {
+    return (k) => { throw "myexn" }
+  }
+}))
+
+
+// ---------------------------------------------------------------------------
+// Property descriptors (Object.getOwnPropertyDescriptor).
+
+function TestDescriptor(handler) {
+  TestWithProxies(TestDescriptor2, handler)
+}
+
+function TestDescriptor2(create, handler) {
+  var p = create(handler)
+  var descs = [
+    {configurable: true},
+    {value: 34, enumerable: true, configurable: true},
+    {value: 3, writable: false, mine: "eyes", configurable: true},
+    {get value() { return 20 }, get configurable() { return true }},
+    {get: function() { "get" }, set: function() { "set" }, configurable: true}
+  ]
+  for (var i = 0; i < descs.length; ++i) {
+    assertEquals(p, Object.defineProperty(p, i, descs[i]))
+    var desc = Object.getOwnPropertyDescriptor(p, i)
+    for (prop in descs[i]) {
+      // TODO(rossberg): Ignore user attributes as long as the spec isn't
+      // fixed suitably.
+      if (prop != "mine") assertEquals(descs[i][prop], desc[prop])
+    }
+    assertEquals(undefined, Object.getOwnPropertyDescriptor(p, "absent"))
+  }
+}
+
+TestDescriptor({
+  defineProperty(t, k, d) { this["__" + k] = d; return true },
+  getOwnPropertyDescriptor(t, k) { return this["__" + k] }
+})
+
+TestDescriptor({
+  defineProperty(t, k, d) { this["__" + k] = d; return true },
+  getOwnPropertyDescriptor(t, k) {
+    return this.getOwnPropertyDescriptor2(k)
+  },
+  getOwnPropertyDescriptor2: function(k) { return this["__" + k] }
+})
+
+
+// ---------------------------------------------------------------------------
+function TestDescriptorThrow(handler) {
+  TestWithProxies(TestDescriptorThrow2, handler)
+}
+
+function TestDescriptorThrow2(create, handler) {
+  var p = create(handler)
+  assertThrowsEquals(() => Object.getOwnPropertyDescriptor(p, "a"), "myexn")
+}
+
+TestDescriptorThrow({
+  getOwnPropertyDescriptor: function(k) { throw "myexn" }
+})
+
+TestDescriptorThrow({
+  getOwnPropertyDescriptor: function(k) {
+    return this.getOwnPropertyDescriptor2(k)
+  },
+  getOwnPropertyDescriptor2: function(k) { throw "myexn" }
+})
+
+
+
+// ---------------------------------------------------------------------------
+// Comparison.
+
+function TestComparison(eq) {
+  TestWithProxies(TestComparison2, eq)
+}
+
+function TestComparison2(create, eq) {
+  var p1 = create({})
+  var p2 = create({})
+
+  assertTrue(eq(p1, p1))
+  assertTrue(eq(p2, p2))
+  assertTrue(!eq(p1, p2))
+  assertTrue(!eq(p1, {}))
+  assertTrue(!eq({}, p2))
+  assertTrue(!eq({}, {}))
+}
+
+TestComparison(function(o1, o2) { return o1 == o2 })
+TestComparison(function(o1, o2) { return o1 === o2 })
+TestComparison(function(o1, o2) { return !(o1 != o2) })
+TestComparison(function(o1, o2) { return !(o1 !== o2) })
+
+
+
+// Type (typeof).
+
+function TestTypeof() {
+  assertEquals("object", typeof new Proxy({},{}))
+  assertTrue(typeof new Proxy({}, {}) == "object")
+  assertTrue("object" == typeof new Proxy({},{}))
+
+  assertEquals("function", typeof new Proxy(function() {}, {}))
+  assertTrue(typeof new Proxy(function() {}, {}) == "function")
+  assertTrue("function" == typeof new Proxy(function() {},{}))
+}
+
+TestTypeof()
+
+
+
+// ---------------------------------------------------------------------------
+// Membership test (in).
+
+var key
+
+function TestIn(handler) {
+  TestWithProxies(TestIn2, handler)
+}
+
+function TestIn2(create, handler) {
+  var p = create(handler)
+  assertTrue("a" in p)
+  assertEquals("a", key)
+  assertTrue(99 in p)
+  assertEquals("99", key)
+  assertFalse("z" in p)
+  assertEquals("z", key)
+
+  assertEquals(2, ("a" in p) ? 2 : 0)
+  assertEquals(0, !("a" in p) ? 2 : 0)
+  assertEquals(0, ("zzz" in p) ? 2 : 0)
+  assertEquals(2, !("zzz" in p) ? 2 : 0)
+
+  // Test compilation in conditionals.
+  if ("b" in p) {
+  } else {
+    assertTrue(false)
+  }
+  assertEquals("b", key)
+
+  if ("zz" in p) {
+    assertTrue(false)
+  }
+  assertEquals("zz", key)
+
+  if (!("c" in p)) {
+    assertTrue(false)
+  }
+  assertEquals("c", key)
+
+  if (!("zzz" in p)) {
+  } else {
+    assertTrue(false)
+  }
+  assertEquals("zzz", key)
+}
+
+TestIn({
+  has(t, k) { key = k; return k < "z" }
+})
+
+TestIn({
+  has(t, k) { return this.has2(k) },
+  has2(k) { key = k; return k < "z" }
+})
+
+TestIn(new Proxy({},{
+  get(pt, pk, pr) {
+    return (t, k) => { key = k; return k < "z" }
+  }
+}))
+
+
+// ---------------------------------------------------------------------------
+function TestInThrow(handler) {
+  TestWithProxies(TestInThrow2, handler)
+}
+
+function TestInThrow2(create, handler) {
+  var p = create(handler)
+  assertThrowsEquals(function(){ return "a" in p }, "myexn")
+  assertThrowsEquals(function(){ return 99 in p }, "myexn")
+  assertThrowsEquals(function(){ return !("a" in p) }, "myexn")
+  assertThrowsEquals(function(){ return ("a" in p) ? 2 : 3 }, "myexn")
+  assertThrowsEquals(function(){ if ("b" in p) {} }, "myexn")
+  assertThrowsEquals(function(){ if (!("b" in p)) {} }, "myexn")
+  assertThrowsEquals(function(){ if ("zzz" in p) {} }, "myexn")
+}
+
+TestInThrow({
+  has: function(k) { throw "myexn" }
+})
+
+TestInThrow({
+  has: function(k) { return this.has2(k) },
+  has2: function(k) { throw "myexn" }
+})
+
+TestInThrow(new Proxy({},{
+  get: function(pr, pk) { throw "myexn" }
+}))
+
+TestInThrow(new Proxy({},{
+  get: function(pr, pk) {
+    return function(k) { throw "myexn" }
+  }
+}))
+
+
+
+// ---------------------------------------------------------------------------
+// Own Properties (Object.prototype.hasOwnProperty).
+
+var key
+
+function TestHasOwn(handler) {
+  TestWithProxies(TestHasOwn2, handler)
+}
+
+function TestHasOwn2(create, handler) {
+  var p = create(handler)
+  assertTrue(Object.prototype.hasOwnProperty.call(p, "a"))
+  assertEquals("a", key)
+  assertTrue(Object.prototype.hasOwnProperty.call(p, 99))
+  assertEquals("99", key)
+  assertFalse(Object.prototype.hasOwnProperty.call(p, "z"))
+  assertEquals("z", key)
+}
+
+TestHasOwn({
+  getOwnPropertyDescriptor(t, k) {
+    key = k; if (k < "z") return {configurable: true}
+  },
+  has() { assertUnreachable() }
+})
+
+TestHasOwn({
+  getOwnPropertyDescriptor(t, k) { return this.getOwnPropertyDescriptor2(k) },
+  getOwnPropertyDescriptor2(k) {
+    key = k; if (k < "z") return {configurable: true}
+  }
+})
+
+
+
+// ---------------------------------------------------------------------------
+function TestHasOwnThrow(handler) {
+  TestWithProxies(TestHasOwnThrow2, handler)
+}
+
+function TestHasOwnThrow2(create, handler) {
+  var p = create(handler)
+  assertThrowsEquals(function(){ Object.prototype.hasOwnProperty.call(p, "a")},
+    "myexn")
+  assertThrowsEquals(function(){ Object.prototype.hasOwnProperty.call(p, 99)},
+    "myexn")
+}
+
+TestHasOwnThrow({
+  getOwnPropertyDescriptor(t, k) { throw "myexn" }
+})
+
+TestHasOwnThrow({
+  getOwnPropertyDescriptor(t, k) { return this.getOwnPropertyDescriptor2(k) },
+  getOwnPropertyDescriptor2(k) { throw "myexn" }
+});
+
+
+// ---------------------------------------------------------------------------
+// Instanceof (instanceof)
+
+(function TestProxyInstanceof() {
+  var o1 = {}
+  var p1 = new Proxy({}, {})
+  var p2 = new Proxy(o1, {})
+  var p3 = new Proxy(p2, {})
+  var o2 = Object.create(p2)
+
+  var f0 = function() {}
+  f0.prototype = o1
+  var f1 = function() {}
+  f1.prototype = p1
+  var f2 = function() {}
+  f2.prototype = p2
+  var f3 = function() {}
+  f3.prototype = o2
+
+  assertTrue(o1 instanceof Object)
+  assertFalse(o1 instanceof f0)
+  assertFalse(o1 instanceof f1)
+  assertFalse(o1 instanceof f2)
+  assertFalse(o1 instanceof f3)
+  assertTrue(p1 instanceof Object)
+  assertFalse(p1 instanceof f0)
+  assertFalse(p1 instanceof f1)
+  assertFalse(p1 instanceof f2)
+  assertFalse(p1 instanceof f3)
+  assertTrue(p2 instanceof Object)
+  assertFalse(p2 instanceof f0)
+  assertFalse(p2 instanceof f1)
+  assertFalse(p2 instanceof f2)
+  assertFalse(p2 instanceof f3)
+  assertTrue(p3 instanceof Object)
+  assertFalse(p3 instanceof f0)
+  assertFalse(p3 instanceof f1)
+  assertFalse(p3 instanceof f2)
+  assertFalse(p3 instanceof f3)
+  assertTrue(o2 instanceof Object)
+  assertFalse(o2 instanceof f0)
+  assertFalse(o2 instanceof f1)
+  assertTrue(o2 instanceof f2)
+  assertFalse(o2 instanceof f3)
+
+  var f = new Proxy(function() {}, {})
+  assertTrue(f instanceof Function)
+})();
+
+
+(function TestInstanceofProxy() {
+  var o0 = Object.create(null)
+  var o1 = {}
+  var o2 = Object.create(o0)
+  var o3 = Object.create(o1)
+  var o4 = Object.create(o2)
+  var o5 = Object.create(o3)
+
+  function handler(o) {
+    return {
+      get: function(r, p) {
+        // We want to test prototype lookup, so ensure the proxy
+        // offers OrdinaryHasInstance behavior.
+        if (p === Symbol.hasInstance) {
+          return undefined;
+        }
+        return o;
+      }
+    }
+  }
+
+  var f0 = new Proxy(function() {}, handler(o0))
+  var f1 = new Proxy(function() {}, handler(o1))
+  var f2 = new Proxy(function() {}, handler(o2))
+  var f3 = new Proxy(function() {}, handler(o3))
+  var f4 = new Proxy(function() {}, handler(o4))
+  var f5 = new Proxy(function() {}, handler(o4))
+
+  assertFalse(null instanceof f0)
+  assertFalse(o0 instanceof f0)
+  assertFalse(o0 instanceof f1)
+  assertFalse(o0 instanceof f2)
+  assertFalse(o0 instanceof f3)
+  assertFalse(o0 instanceof f4)
+  assertFalse(o0 instanceof f5)
+  assertFalse(o1 instanceof f0)
+  assertFalse(o1 instanceof f1)
+  assertFalse(o1 instanceof f2)
+  assertFalse(o1 instanceof f3)
+  assertFalse(o1 instanceof f4)
+  assertFalse(o1 instanceof f5)
+  assertTrue(o2 instanceof f0)
+  assertFalse(o2 instanceof f1)
+  assertFalse(o2 instanceof f2)
+  assertFalse(o2 instanceof f3)
+  assertFalse(o2 instanceof f4)
+  assertFalse(o2 instanceof f5)
+  assertFalse(o3 instanceof f0)
+  assertTrue(o3 instanceof f1)
+  assertFalse(o3 instanceof f2)
+  assertFalse(o3 instanceof f3)
+  assertFalse(o3 instanceof f4)
+  assertFalse(o3 instanceof f5)
+  assertTrue(o4 instanceof f0)
+  assertFalse(o4 instanceof f1)
+  assertTrue(o4 instanceof f2)
+  assertFalse(o4 instanceof f3)
+  assertFalse(o4 instanceof f4)
+  assertFalse(o4 instanceof f5)
+  assertFalse(o5 instanceof f0)
+  assertTrue(o5 instanceof f1)
+  assertFalse(o5 instanceof f2)
+  assertTrue(o5 instanceof f3)
+  assertFalse(o5 instanceof f4)
+  assertFalse(o5 instanceof f5)
+
+  var f = new Proxy(function() {}, {})
+  var ff = new Proxy(function() {}, handler(Function))
+  assertTrue(f instanceof Function)
+  assertFalse(f instanceof ff)
+})();
+
+
+// ---------------------------------------------------------------------------
+// Prototype (Object.getPrototypeOf, Object.prototype.isPrototypeOf).
+
+(function TestPrototype() {
+  var o1 = {}
+  var p1 = new Proxy({}, {})
+  var p2 = new Proxy(o1, {})
+  var p3 = new Proxy(p2, {})
+  var o2 = Object.create(p3)
+
+  assertSame(Object.getPrototypeOf(o1), Object.prototype)
+  assertSame(Object.getPrototypeOf(p1), Object.prototype)
+  assertSame(Object.getPrototypeOf(p2), Object.prototype)
+  assertSame(Object.getPrototypeOf(p3), Object.prototype)
+  assertSame(Object.getPrototypeOf(o2), p3)
+
+  assertTrue(Object.prototype.isPrototypeOf(o1))
+  assertTrue(Object.prototype.isPrototypeOf(p1))
+  assertTrue(Object.prototype.isPrototypeOf(p2))
+  assertTrue(Object.prototype.isPrototypeOf(p3))
+  assertTrue(Object.prototype.isPrototypeOf(o2))
+  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, o1))
+  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p1))
+  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p2))
+  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p3))
+  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, o2))
+  assertFalse(Object.prototype.isPrototypeOf.call(o1, o1))
+  assertFalse(Object.prototype.isPrototypeOf.call(o1, p1))
+  assertFalse(Object.prototype.isPrototypeOf.call(o1, p2))
+  assertFalse(Object.prototype.isPrototypeOf.call(o1, p3))
+  assertFalse(Object.prototype.isPrototypeOf.call(o1, o2))
+  assertFalse(Object.prototype.isPrototypeOf.call(p1, p1))
+  assertFalse(Object.prototype.isPrototypeOf.call(p1, o1))
+  assertFalse(Object.prototype.isPrototypeOf.call(p1, p2))
+  assertFalse(Object.prototype.isPrototypeOf.call(p1, p3))
+  assertFalse(Object.prototype.isPrototypeOf.call(p1, o2))
+  assertFalse(Object.prototype.isPrototypeOf.call(p2, p1))
+  assertFalse(Object.prototype.isPrototypeOf.call(p2, p2))
+  assertFalse(Object.prototype.isPrototypeOf.call(p2, p3))
+  assertFalse(Object.prototype.isPrototypeOf.call(p2, o2))
+  assertFalse(Object.prototype.isPrototypeOf.call(p3, p2))
+  assertTrue(Object.prototype.isPrototypeOf.call(p3, o2))
+  assertFalse(Object.prototype.isPrototypeOf.call(o2, o1))
+  assertFalse(Object.prototype.isPrototypeOf.call(o2, p1))
+  assertFalse(Object.prototype.isPrototypeOf.call(o2, p2))
+  assertFalse(Object.prototype.isPrototypeOf.call(o2, p3))
+  assertFalse(Object.prototype.isPrototypeOf.call(o2, o2))
+
+  var f = new Proxy(function() {}, {})
+  assertSame(Object.getPrototypeOf(f), Function.prototype)
+  assertTrue(Object.prototype.isPrototypeOf(f))
+  assertTrue(Object.prototype.isPrototypeOf.call(Function.prototype, f))
+})();
+
+
+// ---------------------------------------------------------------------------
+function TestPropertyNamesThrow(handler) {
+  TestWithProxies(TestPropertyNamesThrow2, handler)
+}
+
+function TestPropertyNamesThrow2(create, handler) {
+  var p = create(handler)
+  assertThrowsEquals(function(){ Object.getOwnPropertyNames(p) }, "myexn")
+}
+
+TestPropertyNamesThrow({
+  ownKeys() { throw "myexn" }
+})
+
+TestPropertyNamesThrow({
+  ownKeys() { return this.getOwnPropertyNames2() },
+  getOwnPropertyNames2() { throw "myexn" }
+})
+
+// ---------------------------------------------------------------------------
+
+function TestKeys(names, handler) {
+  var p = new Proxy({}, handler);
+  assertArrayEquals(names, Object.keys(p))
+}
+
+TestKeys([], {
+  ownKeys() { return [] }
+})
+
+TestKeys([], {
+  ownKeys() { return ["a", "zz", " ", "0", "toString"] }
+})
+
+TestKeys(["a", "zz", " ", "0", "toString"], {
+  ownKeys() { return ["a", "zz", " ", "0", "toString"] },
+  getOwnPropertyDescriptor(t, p) {
+    return {configurable: true, enumerable: true}
+  }
+})
+
+TestKeys([], {
+  ownKeys() { return this.keys2() },
+  keys2() { return ["throw", "function "] }
+})
+
+TestKeys(["throw", "function "], {
+  ownKeys() { return this.keys2() },
+  keys2() { return ["throw", "function "] },
+  getOwnPropertyDescriptor(t, p) {
+    return {configurable: true, enumerable: true}
+  }
+})
+
+TestKeys(["a", "0"], {
+  ownKeys() { return ["a", "23", "zz", "", "0"] },
+  getOwnPropertyDescriptor(t, k) {
+    return k == "" ?
+        undefined :
+        { configurable: true, enumerable: k.length == 1}
+  }
+})
+
+TestKeys(["23", "zz", ""], {
+  ownKeys() { return this.getOwnPropertyNames2() },
+  getOwnPropertyNames2() { return ["a", "23", "zz", "", "0"] },
+  getOwnPropertyDescriptor(t, k) {
+    return this.getOwnPropertyDescriptor2(k)
+  },
+  getOwnPropertyDescriptor2(k) {
+    return {configurable: true, enumerable: k.length != 1 }
+  }
+})
+
+TestKeys([], {
+  get ownKeys() {
+    return function() { return ["a", "b", "c"] }
+  },
+  getOwnPropertyDescriptor: function(k) { return {configurable: true} }
+})
+
+
+// ---------------------------------------------------------------------------
+function TestKeysThrow(handler) {
+  TestWithProxies(TestKeysThrow2, handler)
+}
+
+function TestKeysThrow2(create, handler) {
+  var p = create(handler);
+  assertThrowsEquals(function(){ Object.keys(p) }, "myexn");
+}
+
+TestKeysThrow({
+  ownKeys() { throw "myexn" }
+})
+
+TestKeysThrow({
+  ownKeys() { return this.keys2() },
+  keys2() { throw "myexn" }
+})
+
+TestKeysThrow({
+  ownKeys() { return ['1'] },
+  getOwnPropertyDescriptor: function() { throw "myexn" },
+})
+
+TestKeysThrow({
+  ownKeys() { return this.getOwnPropertyNames2() },
+  getOwnPropertyNames2() { return ['1', '2'] },
+  getOwnPropertyDescriptor(k) {
+    return this.getOwnPropertyDescriptor2(k)
+  },
+  getOwnPropertyDescriptor2(k) { throw "myexn" }
+})
+
+TestKeysThrow({
+  get ownKeys() { throw "myexn" }
+})
+
+TestKeysThrow({
+  get ownKeys() {
+    return function() { throw "myexn" }
+  },
+})
+
+TestKeysThrow({
+  get ownKeys() {
+    return function() { return ['1', '2'] }
+  },
+  getOwnPropertyDescriptor(k) { throw "myexn" }
+})
+
+
+
+// ---------------------------------------------------------------------------
+// String conversion (Object.prototype.toString,
+//                    Object.prototype.toLocaleString,
+//                    Function.prototype.toString)
+
+var key
+
+function TestToString(handler) {
+  var p = new Proxy({}, handler)
+  key = ""
+  assertEquals("[object Object]", Object.prototype.toString.call(p))
+  assertEquals(Symbol.toStringTag, key)
+  assertEquals("my_proxy", Object.prototype.toLocaleString.call(p))
+  assertEquals("toString", key)
+
+  var f = new Proxy(function() {}, handler)
+  key = ""
+  assertEquals("[object Function]", Object.prototype.toString.call(f))
+  assertEquals(Symbol.toStringTag, key)
+  assertEquals("my_proxy", Object.prototype.toLocaleString.call(f))
+  assertEquals("toString", key)
+  assertThrows(function(){ Function.prototype.toString.call(f) })
+
+  var o = Object.create(p)
+  key = ""
+  assertEquals("[object Object]", Object.prototype.toString.call(o))
+  assertEquals(Symbol.toStringTag, key)
+  assertEquals("my_proxy", Object.prototype.toLocaleString.call(o))
+  assertEquals("toString", key)
+}
+
+TestToString({
+  get: function(r, k) { key = k; return function() { return "my_proxy" } }
+})
+
+TestToString({
+  get: function(r, k) { return this.get2(r, k) },
+  get2: function(r, k) { key = k; return function() { return "my_proxy" } }
+})
+
+TestToString(new Proxy({}, {
+  get: function(pr, pk) {
+    return function(r, k) { key = k; return function() { return "my_proxy" } }
+  }
+}))
+
+
+function TestToStringThrow(handler) {
+  var p = new Proxy({}, handler)
+  assertThrowsEquals(() => Object.prototype.toString.call(p), "myexn")
+  assertThrowsEquals(() => Object.prototype.toLocaleString.call(p), "myexn")
+
+  var f = new Proxy(function(){}, handler)
+  assertThrowsEquals(() => Object.prototype.toString.call(f), "myexn")
+  assertThrowsEquals(() => Object.prototype.toLocaleString.call(f), "myexn")
+
+  var o = Object.create(p)
+  assertThrowsEquals(() => Object.prototype.toString.call(o), "myexn")
+  assertThrowsEquals(() => Object.prototype.toLocaleString.call(o), "myexn")
+}
+
+TestToStringThrow({
+  get: function(r, k) { throw "myexn" }
+})
+
+TestToStringThrow({
+  get: function(r, k) { return this.get2(r, k) },
+  get2: function(r, k) { throw "myexn" }
+})
+
+TestToStringThrow(new Proxy({}, {
+  get: function(pr, pk) { throw "myexn" }
+}))
+
+TestToStringThrow(new Proxy({}, {
+  get: function(pr, pk) {
+    return function(r, k) { throw "myexn" }
+  }
+}))
+
+
+// ---------------------------------------------------------------------------
+// Value conversion (Object.prototype.toValue)
+
+function TestValueOf(handler) {
+  TestWithProxies(TestValueOf2, handler)
+}
+
+function TestValueOf2(create, handler) {
+  var p = create(handler)
+  assertSame(p, Object.prototype.valueOf.call(p))
+}
+
+TestValueOf({})
+
+
+
+// ---------------------------------------------------------------------------
+// Enumerability (Object.prototype.propertyIsEnumerable)
+
+var key
+
+function TestIsEnumerable(handler) {
+  TestWithProxies(TestIsEnumerable2, handler)
+}
+
+function TestIsEnumerable2(create, handler) {
+  var p = create(handler)
+  assertTrue(Object.prototype.propertyIsEnumerable.call(p, "a"))
+  assertEquals("a", key)
+  assertTrue(Object.prototype.propertyIsEnumerable.call(p, 2))
+  assertEquals("2", key)
+  assertFalse(Object.prototype.propertyIsEnumerable.call(p, "z"))
+  assertEquals("z", key)
+
+  var o = Object.create(p)
+  key = ""
+  assertFalse(Object.prototype.propertyIsEnumerable.call(o, "a"))
+  assertEquals("", key)  // trap not invoked
+}
+
+TestIsEnumerable({
+  getOwnPropertyDescriptor(t, k) {
+    key = k;
+    return {enumerable: k < "z", configurable: true}
+  },
+})
+
+TestIsEnumerable({
+  getOwnPropertyDescriptor: function(t, k) {
+    return this.getOwnPropertyDescriptor2(k)
+  },
+  getOwnPropertyDescriptor2: function(k) {
+    key = k;
+    return {enumerable: k < "z", configurable: true}
+  },
+})
+
+TestIsEnumerable({
+  getOwnPropertyDescriptor: function(t, k) {
+    key = k;
+    return {get enumerable() { return k < "z" }, configurable: true}
+  },
+})
+
+TestIsEnumerable(new Proxy({}, {
+  get: function(pt, pk, pr) {
+    return function(t, k) {
+      key = k;
+      return {enumerable: k < "z", configurable: true}
+    }
+  }
+}))
+
+
+// ---------------------------------------------------------------------------
+function TestIsEnumerableThrow(handler) {
+  TestWithProxies(TestIsEnumerableThrow2, handler)
+}
+
+function TestIsEnumerableThrow2(create, handler) {
+  var p = create(handler)
+  assertThrowsEquals(() => Object.prototype.propertyIsEnumerable.call(p, "a"),
+      "myexn")
+  assertThrowsEquals(() => Object.prototype.propertyIsEnumerable.call(p, 11),
+      "myexn")
+}
+
+TestIsEnumerableThrow({
+  getOwnPropertyDescriptor: function(k) { throw "myexn" }
+})
+
+TestIsEnumerableThrow({
+  getOwnPropertyDescriptor: function(k) {
+    return this.getOwnPropertyDescriptor2(k)
+  },
+  getOwnPropertyDescriptor2: function(k) { throw "myexn" }
+})
+
+TestIsEnumerableThrow({
+  getOwnPropertyDescriptor: function(k) {
+    return {get enumerable() { throw "myexn" }, configurable: true}
+  },
+})
+
+TestIsEnumerableThrow(new Proxy({}, {
+  get: function(pr, pk) { throw "myexn" }
+}))
+
+TestIsEnumerableThrow(new Proxy({}, {
+  get: function(pr, pk) {
+    return function(k) { throw "myexn" }
+  }
+}));
+
+
+
+// ---------------------------------------------------------------------------
+// Constructor functions with proxy prototypes.
+
+(function TestConstructorWithProxyPrototype() {
+  TestWithProxies(TestConstructorWithProxyPrototype2, {})
+})();
+
+function TestConstructorWithProxyPrototype2(create, handler) {
+  function C() {};
+  C.prototype = create(handler);
+
+  var o = new C;
+  assertSame(C.prototype, Object.getPrototypeOf(o));
+};
+
+
+(function TestOptWithProxyPrototype() {
+  var handler = {
+    get(t, k) {
+      return 10;
+    }
+  };
+
+  function C() {};
+  C.prototype = new Proxy({}, handler);
+  var o = new C();
+
+  function f() {
+    return o.x;
+  }
+  assertEquals(10, f());
+  assertEquals(10, f());
+  %OptimizeFunctionOnNextCall(f);
+  assertEquals(10, f());
+})();
diff --git a/test/mjsunit/es6/reflect-apply.js b/test/mjsunit/es6/reflect-apply.js
new file mode 100644
index 0000000..fa38013
--- /dev/null
+++ b/test/mjsunit/es6/reflect-apply.js
@@ -0,0 +1,210 @@
+// 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.
+
+
+(function testReflectApplyArity() {
+  assertEquals(3, Reflect.apply.length);
+})();
+
+
+(function testReflectApplyNonConstructor() {
+  assertThrows(function() {
+    new Reflect.apply(function(){}, null, []);
+  }, TypeError);
+})();
+
+
+(function testAppliedReceiverSloppy() {
+  function returnThis() { return this; }
+  var receiver = {};
+
+  assertSame(this, Reflect.apply(returnThis, void 0, []));
+  assertSame(this, Reflect.apply(returnThis, null, []));
+  assertSame(this, Reflect.apply(returnThis, this, []));
+  assertSame(receiver, Reflect.apply(returnThis, receiver, []));
+
+  // Wrap JS values
+  assertSame(String.prototype,
+             Object.getPrototypeOf(Reflect.apply(returnThis, "str", [])));
+  assertSame(Number.prototype,
+             Object.getPrototypeOf(Reflect.apply(returnThis, 123, [])));
+  assertSame(Boolean.prototype,
+             Object.getPrototypeOf(Reflect.apply(returnThis, true, [])));
+  assertSame(Symbol.prototype,
+             Object.getPrototypeOf(
+                Reflect.apply(returnThis, Symbol("test"), [])));
+})();
+
+
+(function testAppliedReceiverStrict() {
+  function returnThis() { 'use strict'; return this; }
+  var receiver = {};
+
+  assertSame(void 0, Reflect.apply(returnThis, void 0, []));
+  assertSame(this, Reflect.apply(returnThis, this, []));
+  assertSame(receiver, Reflect.apply(returnThis, receiver, []));
+
+  // Don't wrap value types
+  var regexp = /123/;
+  var symbol = Symbol("test");
+  assertSame("str", Reflect.apply(returnThis, "str", []));
+  assertSame(123, Reflect.apply(returnThis, 123, []));
+  assertSame(true, Reflect.apply(returnThis, true, []));
+  assertSame(regexp, Reflect.apply(returnThis, regexp, []));
+  assertSame(symbol, Reflect.apply(returnThis, symbol, []));
+})();
+
+
+(function testAppliedArgumentsLength() {
+  function returnLengthStrict() { 'use strict'; return arguments.length; }
+  function returnLengthSloppy() { return arguments.length; }
+
+  assertEquals(0, Reflect.apply(returnLengthStrict, this, []));
+  assertEquals(0, Reflect.apply(returnLengthSloppy, this, []));
+  assertEquals(0, Reflect.apply(returnLengthStrict, this, {}));
+  assertEquals(0, Reflect.apply(returnLengthSloppy, this, {}));
+
+  for (var i = 0; i < 256; ++i) {
+    assertEquals(i, Reflect.apply(returnLengthStrict, this, new Array(i)));
+    assertEquals(i, Reflect.apply(returnLengthSloppy, this, new Array(i)));
+    assertEquals(i, Reflect.apply(returnLengthStrict, this, { length: i }));
+    assertEquals(i, Reflect.apply(returnLengthSloppy, this, { length: i }));
+  }
+})();
+
+
+(function testAppliedArgumentsLengthThrows() {
+  function noopStrict() { 'use strict'; }
+  function noopSloppy() { }
+  function MyError() {}
+
+  var argsList = {};
+  Object.defineProperty(argsList, "length", {
+    get: function() { throw new MyError(); }
+  });
+
+  assertThrows(function() {
+    Reflect.apply(noopStrict, this, argsList);
+  }, MyError);
+
+  assertThrows(function() {
+    Reflect.apply(noopSloppy, this, argsList);
+  }, MyError);
+})();
+
+
+(function testAppliedArgumentsElementThrows() {
+  function noopStrict() { 'use strict'; }
+  function noopSloppy() { }
+  function MyError() {}
+
+  var argsList = { length: 1 };
+  Object.defineProperty(argsList, "0", {
+    get: function() { throw new MyError(); }
+  });
+
+  assertThrows(function() {
+    Reflect.apply(noopStrict, this, argsList);
+  }, MyError);
+
+  assertThrows(function() {
+    Reflect.apply(noopSloppy, this, argsList);
+  }, MyError);
+})();
+
+
+(function testAppliedNonFunctionStrict() {
+  'use strict';
+  assertThrows(function() { Reflect.apply(void 0); }, TypeError);
+  assertThrows(function() { Reflect.apply(null); }, TypeError);
+  assertThrows(function() { Reflect.apply(123); }, TypeError);
+  assertThrows(function() { Reflect.apply("str"); }, TypeError);
+  assertThrows(function() { Reflect.apply(Symbol("x")); }, TypeError);
+  assertThrows(function() { Reflect.apply(/123/); }, TypeError);
+  assertThrows(function() { Reflect.apply(NaN); }, TypeError);
+  assertThrows(function() { Reflect.apply({}); }, TypeError);
+  assertThrows(function() { Reflect.apply([]); }, TypeError);
+})();
+
+
+(function testAppliedNonFunctionSloppy() {
+  assertThrows(function() { Reflect.apply(void 0); }, TypeError);
+  assertThrows(function() { Reflect.apply(null); }, TypeError);
+  assertThrows(function() { Reflect.apply(123); }, TypeError);
+  assertThrows(function() { Reflect.apply("str"); }, TypeError);
+  assertThrows(function() { Reflect.apply(Symbol("x")); }, TypeError);
+  assertThrows(function() { Reflect.apply(/123/); }, TypeError);
+  assertThrows(function() { Reflect.apply(NaN); }, TypeError);
+  assertThrows(function() { Reflect.apply({}); }, TypeError);
+  assertThrows(function() { Reflect.apply([]); }, TypeError);
+})();
+
+
+(function testAppliedArgumentsNonList() {
+  function noopStrict() { 'use strict'; }
+  function noopSloppy() {}
+  var R = void 0;
+  assertThrows(function() { Reflect.apply(noopStrict, R, null); }, TypeError);
+  assertThrows(function() { Reflect.apply(noopSloppy, R, null); }, TypeError);
+  assertThrows(function() { Reflect.apply(noopStrict, R, 1); }, TypeError);
+  assertThrows(function() { Reflect.apply(noopSloppy, R, 1); }, TypeError);
+  assertThrows(function() { Reflect.apply(noopStrict, R, "BAD"); }, TypeError);
+  assertThrows(function() { Reflect.apply(noopSloppy, R, "BAD"); }, TypeError);
+  assertThrows(function() { Reflect.apply(noopStrict, R, true); }, TypeError);
+  assertThrows(function() { Reflect.apply(noopSloppy, R, true); }, TypeError);
+  var sym = Symbol("x");
+  assertThrows(function() { Reflect.apply(noopStrict, R, sym); }, TypeError);
+  assertThrows(function() { Reflect.apply(noopSloppy, R, sym); }, TypeError);
+})();
+
+
+(function testAppliedArgumentValue() {
+  function returnFirstStrict(a) { 'use strict'; return a; }
+  function returnFirstSloppy(a) { return a; }
+  function returnLastStrict(a) {
+    'use strict'; return arguments[arguments.length - 1]; }
+  function returnLastSloppy(a) { return arguments[arguments.length - 1]; }
+  function returnSumStrict() {
+    'use strict';
+    var sum = arguments[0];
+    for (var i = 1; i < arguments.length; ++i) {
+      sum += arguments[i];
+    }
+    return sum;
+  }
+  function returnSumSloppy() {
+    var sum = arguments[0];
+    for (var i = 1; i < arguments.length; ++i) {
+      sum += arguments[i];
+    }
+    return sum;
+  }
+
+  assertEquals("OK!", Reflect.apply(returnFirstStrict, this, ["OK!"]));
+  assertEquals("OK!", Reflect.apply(returnFirstSloppy, this, ["OK!"]));
+  assertEquals("OK!", Reflect.apply(returnFirstStrict, this,
+                                    { 0: "OK!", length: 1 }));
+  assertEquals("OK!", Reflect.apply(returnFirstSloppy, this,
+                                    { 0: "OK!", length: 1 }));
+  assertEquals("OK!", Reflect.apply(returnLastStrict, this,
+                                    [0, 1, 2, 3, 4, 5, 6, 7, 8, "OK!"]));
+  assertEquals("OK!", Reflect.apply(returnLastSloppy, this,
+                                    [0, 1, 2, 3, 4, 5, 6, 7, 8, "OK!"]));
+  assertEquals("OK!", Reflect.apply(returnLastStrict, this,
+                                    { 9: "OK!", length: 10 }));
+  assertEquals("OK!", Reflect.apply(returnLastSloppy, this,
+                                    { 9: "OK!", length: 10 }));
+  assertEquals("TEST", Reflect.apply(returnSumStrict, this,
+                                     ["T", "E", "S", "T"]));
+  assertEquals("TEST!!", Reflect.apply(returnSumStrict, this,
+                                       ["T", "E", "S", "T", "!", "!"]));
+  assertEquals(10, Reflect.apply(returnSumStrict, this,
+                                 { 0: 1, 1: 2, 2: 3, 3: 4, length: 4 }));
+  assertEquals("TEST", Reflect.apply(returnSumSloppy, this,
+                                     ["T", "E", "S", "T"]));
+  assertEquals("TEST!!", Reflect.apply(returnSumSloppy, this,
+                                       ["T", "E", "S", "T", "!", "!"]));
+  assertEquals(10, Reflect.apply(returnSumSloppy, this,
+                                 { 0: 1, 1: 2, 2: 3, 3: 4, length: 4 }));
+})();
diff --git a/test/mjsunit/es6/reflect-construct.js b/test/mjsunit/es6/reflect-construct.js
new file mode 100644
index 0000000..b37f876
--- /dev/null
+++ b/test/mjsunit/es6/reflect-construct.js
@@ -0,0 +1,376 @@
+// 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.
+
+
+(function testReflectConstructArity() {
+  assertEquals(2, Reflect.construct.length);
+})();
+
+
+(function testReflectConstructNonConstructor() {
+  assertThrows(function() {
+    new Reflect.construct(function(){}, []);
+  }, TypeError);
+})();
+
+
+(function testReflectConstructBasic() {
+  function Constructor() { "use strict"; }
+  assertInstanceof(Reflect.construct(Constructor, []), Constructor);
+})();
+
+
+(function testReflectConstructBasicSloppy() {
+  function Constructor() {}
+  assertInstanceof(Reflect.construct(Constructor, []), Constructor);
+})();
+
+
+(function testReflectConstructReturnSomethingElseStrict() {
+  var R = {};
+  function Constructor() { "use strict"; return R; }
+  assertSame(R, Reflect.construct(Constructor, []));
+})();
+
+
+(function testReflectConstructReturnSomethingElseSloppy() {
+  var R = {};
+  function Constructor() { return R; }
+  assertSame(R, Reflect.construct(Constructor, []));
+})();
+
+
+(function testReflectConstructNewTargetStrict() {
+  "use strict";
+  function Constructor() { this[9] = 1; }
+  var O = Reflect.construct(Constructor, [], Array);
+  assertEquals(1, O[9]);
+  // Ordinary object with Array.prototype --- no exotic Array magic
+  assertFalse(Array.isArray(O));
+  assertEquals(0, O.length);
+  assertSame(Array.prototype, Object.getPrototypeOf(O));
+})();
+
+
+(function testReflectConstructNewTargetSloppy() {
+  function Constructor() { this[9] = 1; }
+  var O = Reflect.construct(Constructor, [], Array);
+  assertEquals(1, O[9]);
+  // Ordinary object with Array.prototype --- no exotic Array magic
+  assertFalse(Array.isArray(O));
+  assertEquals(0, O.length);
+  assertSame(Array.prototype, Object.getPrototypeOf(O));
+})();
+
+
+(function testReflectConstructNewTargetStrict2() {
+  "use strict";
+  function Constructor() { this[9] = 1; }
+  Constructor.prototype.add = function(x) {
+    this[this.length] = x; return this;
+  }
+  var O = Reflect.construct(Array, [1, 2, 3], Constructor);
+  // Exotic Array object with Constructor.prototype
+  assertTrue(Array.isArray(O));
+  assertSame(Constructor.prototype, Object.getPrototypeOf(O));
+  assertFalse(O instanceof Array);
+  assertEquals(3, O.length);
+  assertEquals(undefined, O[9]);
+  assertSame(O, O.add(4));
+  assertEquals(4, O.length);
+  assertEquals(4, O[3]);
+})();
+
+
+(function testReflectConstructNewTargetSloppy2() {
+  function Constructor() { this[9] = 1; }
+  Constructor.prototype.add = function(x) {
+    this[this.length] = x; return this;
+  }
+  var O = Reflect.construct(Array, [1, 2, 3], Constructor);
+  // Exotic Array object with Constructor.prototype
+  assertTrue(Array.isArray(O));
+  assertSame(Constructor.prototype, Object.getPrototypeOf(O));
+  assertFalse(O instanceof Array);
+  assertEquals(3, O.length);
+  assertEquals(undefined, O[9]);
+  assertSame(O, O.add(4));
+  assertEquals(4, O.length);
+  assertEquals(4, O[3]);
+})();
+
+
+(function testReflectConstructNewTargetStrict3() {
+  "use strict";
+  function A() {}
+  function B() {}
+  var O = Reflect.construct(A, [], B);
+  // TODO(caitp): bug: newTarget prototype is not used if it is not
+  // explicitly set.
+  //assertSame(B.prototype, Object.getPrototypeOf(O));
+})();
+
+
+(function testReflectConstructNewTargetSloppy3() {
+  function A() {}
+  function B() {}
+  var O = Reflect.construct(A, [], B);
+  // TODO(caitp): bug: newTarget prototype is not used if it is not
+  // explicitly set.
+  //assertSame(B.prototype, Object.getPrototypeOf(O));
+})();
+
+
+(function testAppliedArgumentsLength() {
+  function lengthStrict() { 'use strict'; this.a = arguments.length; }
+  function lengthSloppy() { this.a = arguments.length; }
+
+  assertEquals(0, Reflect.construct(lengthStrict, []).a);
+  assertEquals(0, Reflect.construct(lengthSloppy, []).a);
+  assertEquals(0, Reflect.construct(lengthStrict, {}).a);
+  assertEquals(0, Reflect.construct(lengthSloppy, {}).a);
+
+  for (var i = 0; i < 256; ++i) {
+    assertEquals(i, Reflect.construct(lengthStrict, new Array(i)).a);
+    assertEquals(i, Reflect.construct(lengthSloppy, new Array(i)).a);
+    assertEquals(i, Reflect.construct(lengthStrict, { length: i }).a);
+    assertEquals(i, Reflect.construct(lengthSloppy, { length: i }).a);
+  }
+})();
+
+
+(function testAppliedArgumentsLengthThrows() {
+  function noopStrict() { 'use strict'; }
+  function noopSloppy() { }
+  function MyError() {}
+
+  var argsList = {};
+  Object.defineProperty(argsList, "length", {
+    get: function() { throw new MyError(); }
+  });
+
+  assertThrows(function() {
+    Reflect.construct(noopStrict, argsList);
+  }, MyError);
+
+  assertThrows(function() {
+    Reflect.construct(noopSloppy, argsList);
+  }, MyError);
+})();
+
+
+(function testAppliedArgumentsElementThrows() {
+  function noopStrict() { 'use strict'; }
+  function noopSloppy() { }
+  function MyError() {}
+
+  var argsList = { length: 1 };
+  Object.defineProperty(argsList, "0", {
+    get: function() { throw new MyError(); }
+  });
+
+  assertThrows(function() {
+    Reflect.construct(noopStrict, argsList);
+  }, MyError);
+
+  assertThrows(function() {
+    Reflect.construct(noopSloppy, argsList);
+  }, MyError);
+})();
+
+
+(function testAppliedNonFunctionStrict() {
+  'use strict';
+  assertThrows(function() { Reflect.construct(void 0, []); }, TypeError);
+  assertThrows(function() { Reflect.construct(null, []); }, TypeError);
+  assertThrows(function() { Reflect.construct(123, []); }, TypeError);
+  assertThrows(function() { Reflect.construct("str", []); }, TypeError);
+  assertThrows(function() { Reflect.construct(Symbol("x"), []); }, TypeError);
+  assertThrows(function() { Reflect.construct(/123/, []); }, TypeError);
+  assertThrows(function() { Reflect.construct(NaN, []); }, TypeError);
+  assertThrows(function() { Reflect.construct({}, []); }, TypeError);
+  assertThrows(function() { Reflect.construct([], []); }, TypeError);
+})();
+
+
+(function testAppliedNonFunctionSloppy() {
+  assertThrows(function() { Reflect.construct(void 0, []); }, TypeError);
+  assertThrows(function() { Reflect.construct(null, []); }, TypeError);
+  assertThrows(function() { Reflect.construct(123, []); }, TypeError);
+  assertThrows(function() { Reflect.construct("str", []); }, TypeError);
+  assertThrows(function() { Reflect.construct(Symbol("x"), []); }, TypeError);
+  assertThrows(function() { Reflect.construct(/123/, []); }, TypeError);
+  assertThrows(function() { Reflect.construct(NaN, []); }, TypeError);
+  assertThrows(function() { Reflect.construct({}, []); }, TypeError);
+  assertThrows(function() { Reflect.construct([], []); }, TypeError);
+})();
+
+
+(function testAppliedArgumentsNonList() {
+  function noopStrict() { 'use strict'; }
+  function noopSloppy() {}
+  assertThrows(function() { Reflect.construct(noopStrict, null); }, TypeError);
+  assertThrows(function() { Reflect.construct(noopSloppy, null); }, TypeError);
+  assertThrows(function() { Reflect.construct(noopStrict, 1); }, TypeError);
+  assertThrows(function() { Reflect.construct(noopSloppy, 1); }, TypeError);
+  assertThrows(function() { Reflect.construct(noopStrict, "BAD"); }, TypeError);
+  assertThrows(function() { Reflect.construct(noopSloppy, "BAD"); }, TypeError);
+  assertThrows(function() { Reflect.construct(noopStrict, true); }, TypeError);
+  assertThrows(function() { Reflect.construct(noopSloppy, true); }, TypeError);
+  var sym = Symbol("x");
+  assertThrows(function() { Reflect.construct(noopStrict, sym); }, TypeError);
+  assertThrows(function() { Reflect.construct(noopSloppy, sym); }, TypeError);
+})();
+
+
+(function testAppliedArgumentValue() {
+  function firstStrict(a) { 'use strict'; this.a = a; }
+  function firstSloppy(a) { this.a = a; }
+  function lastStrict(a) {
+    'use strict'; this.a = arguments[arguments.length - 1]; }
+  function lastSloppy(a) { this.a = arguments[arguments.length - 1]; }
+  function sumStrict() {
+    'use strict';
+    var sum = arguments[0];
+    for (var i = 1; i < arguments.length; ++i) {
+      sum += arguments[i];
+    }
+    this.a = sum;
+  }
+  function sumSloppy() {
+    var sum = arguments[0];
+    for (var i = 1; i < arguments.length; ++i) {
+      sum += arguments[i];
+    }
+    this.a = sum;
+  }
+
+  assertEquals("OK!", Reflect.construct(firstStrict, ["OK!"]).a);
+  assertEquals("OK!", Reflect.construct(firstSloppy, ["OK!"]).a);
+  assertEquals("OK!", Reflect.construct(firstStrict,
+                                        { 0: "OK!", length: 1 }).a);
+  assertEquals("OK!", Reflect.construct(firstSloppy,
+                                        { 0: "OK!", length: 1 }).a);
+  assertEquals("OK!", Reflect.construct(lastStrict,
+                                        [0, 1, 2, 3, 4, 5, 6, 7, 8, "OK!"]).a);
+  assertEquals("OK!", Reflect.construct(lastSloppy,
+                                        [0, 1, 2, 3, 4, 5, 6, 7, 8, "OK!"]).a);
+  assertEquals("OK!", Reflect.construct(lastStrict,
+                                        { 9: "OK!", length: 10 }).a);
+  assertEquals("OK!", Reflect.construct(lastSloppy,
+                                        { 9: "OK!", length: 10 }).a);
+  assertEquals("TEST", Reflect.construct(sumStrict,
+                                         ["T", "E", "S", "T"]).a);
+  assertEquals("TEST!!", Reflect.construct(sumStrict,
+                                           ["T", "E", "S", "T", "!", "!"]).a);
+  assertEquals(10, Reflect.construct(sumStrict,
+                                     { 0: 1, 1: 2, 2: 3, 3: 4, length: 4 }).a);
+  assertEquals("TEST", Reflect.construct(sumSloppy,
+                                         ["T", "E", "S", "T"]).a);
+  assertEquals("TEST!!", Reflect.construct(sumSloppy,
+                                           ["T", "E", "S", "T", "!", "!"]).a);
+  assertEquals(10, Reflect.construct(sumSloppy,
+                                     { 0: 1, 1: 2, 2: 3, 3: 4, length: 4 }).a);
+})();
+
+(function() {
+  function* f() { yield 1; yield 2; }
+  function* g() { yield 3; yield 4; }
+  assertThrows(()=>Reflect.construct(f, [], g));
+})();
+
+(function () {
+  var realm1 = Realm.create();
+  var realm2 = Realm.create();
+
+  var well_known_intrinsic_constructors = [
+      "Array",
+      "ArrayBuffer",
+      "Boolean",
+      ["DataView", [new ArrayBuffer()]],
+      "Date",
+      "Error",
+      "EvalError",
+      "Float32Array",
+      "Float64Array",
+      ["Function", ["return 153;"]],
+      ["Function", ["'use strict'; return 153;"]],
+      ["Function", ["'use strong'; return 153;"]],
+      ["((function*(){}).constructor)", ["yield 153;"]],  // GeneratorFunction
+      ["((function*(){}).constructor)", ["'use strict'; yield 153;"]],
+      ["((function*(){}).constructor)", ["'use strong'; yield 153;"]],
+      "Int8Array",
+      "Int16Array",
+      "Int32Array",
+      "Map",
+      "Number",
+      "Object",
+      ["Promise", [(resolve, reject)=>{}]],
+      "RangeError",
+      "ReferenceError",
+      "RegExp",
+      "Set",
+      "String",
+      "SyntaxError",
+      // %TypedArray%?
+      "TypeError",
+      "Uint8Array",
+      "Uint8ClampedArray",
+      "Uint16Array",
+      "Uint32Array",
+      "URIError",
+      "WeakMap",
+      "WeakSet"
+  ];
+
+  function getname(v) {
+    return typeof v === "string" ? v : v[0];
+  }
+
+  function getargs(v) {
+    return typeof v === "string" ? [] : v[1];
+  }
+
+  function test_intrinsic_prototype(name) {
+    var own = Realm.eval(realm1, name);
+
+    // Ensure that constructor.prototype is non-writable, non-configurable.
+    var desc = Object.getOwnPropertyDescriptor(own, "prototype");
+    assertFalse(desc.configurable, name);
+    assertFalse(desc.writable, name);
+  }
+
+  for (var intrinsic of well_known_intrinsic_constructors) {
+    test_intrinsic_prototype(getname(intrinsic));
+  }
+
+  function function_with_non_instance_prototype(realm) {
+    var f = Realm.eval(realm, "(function(){})");
+    f.prototype = 1;
+    return f;
+  }
+
+  function test_intrinsic_default(realm, name, args, convert) {
+    var own = Realm.eval(realm1, name);
+    var other = Realm.eval(realm, name);
+    var o = Reflect.construct(
+        convert(own), args, function_with_non_instance_prototype(realm));
+
+    // Ensure the intrisicDefaultProto is fetched from the correct realm.
+    assertTrue(realm == realm1 || o.__proto__ !== own.prototype, [...arguments]);
+    assertTrue(o.__proto__ === other.prototype, [...arguments]);
+  }
+
+  function test_all(test, convert) {
+    for (var intrinsic of well_known_intrinsic_constructors) {
+      for (var realm of [realm1, realm2]) {
+        test(realm, getname(intrinsic), getargs(intrinsic), convert);
+      }
+    }
+  }
+
+  test_all(test_intrinsic_default, (v)=>v);
+  test_all(test_intrinsic_default,
+           (v)=>{ "use strict"; return class extends v {}});
+})();
diff --git a/test/mjsunit/es6/reflect-define-property.js b/test/mjsunit/es6/reflect-define-property.js
new file mode 100644
index 0000000..b19c5aa
--- /dev/null
+++ b/test/mjsunit/es6/reflect-define-property.js
@@ -0,0 +1,1115 @@
+// Copyright 2012-2015 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Tests the Reflect.defineProperty method - ES6 26.1.3
+// This is adapted from mjsunit/object-define-property.js.
+
+// Flags: --allow-natives-syntax
+
+
+// Check that an exception is thrown when null is passed as object.
+var exception = false;
+try {
+  Reflect.defineProperty(null, null, null);
+} catch (e) {
+  exception = true;
+  assertTrue(/called on non-object/.test(e));
+}
+assertTrue(exception);
+
+// Check that an exception is thrown when undefined is passed as object.
+exception = false;
+try {
+  Reflect.defineProperty(undefined, undefined, undefined);
+} catch (e) {
+  exception = true;
+  assertTrue(/called on non-object/.test(e));
+}
+assertTrue(exception);
+
+// Check that an exception is thrown when non-object is passed as object.
+exception = false;
+try {
+  Reflect.defineProperty(0, "foo", undefined);
+} catch (e) {
+  exception = true;
+  assertTrue(/called on non-object/.test(e));
+}
+assertTrue(exception);
+
+// Object.
+var obj1 = {};
+
+// Values.
+var val1 = 0;
+var val2 = 0;
+var val3 = 0;
+
+function setter1() {val1++; }
+function getter1() {return val1; }
+
+function setter2() {val2++; }
+function getter2() {return val2; }
+
+function setter3() {val3++; }
+function getter3() {return val3; }
+
+
+// Descriptors.
+var emptyDesc = {};
+
+var accessorConfigurable = {
+    set: setter1,
+    get: getter1,
+    configurable: true
+};
+
+var accessorNoConfigurable = {
+    set: setter2,
+    get: getter2,
+    configurable: false
+};
+
+var accessorOnlySet = {
+  set: setter3,
+  configurable: true
+};
+
+var accessorOnlyGet = {
+  get: getter3,
+  configurable: true
+};
+
+var accessorDefault = {set: function(){} };
+
+var dataConfigurable = { value: 1000, configurable: true };
+
+var dataNoConfigurable = { value: 2000, configurable: false };
+
+var dataWritable = { value: 3000, writable: true};
+
+
+// Check that we can't add property with undefined attributes.
+assertThrows(function() { Reflect.defineProperty(obj1, "foo", undefined) },
+  TypeError);
+
+// Make sure that we can add a property with an empty descriptor and
+// that it has the default descriptor values.
+assertTrue(Reflect.defineProperty(obj1, "foo", emptyDesc));
+
+// foo should be undefined as it has no get, set or value
+assertEquals(undefined, obj1.foo);
+
+// We should, however, be able to retrieve the propertydescriptor which should
+// have all default values (according to 8.6.1).
+var desc = Object.getOwnPropertyDescriptor(obj1, "foo");
+assertFalse(desc.configurable);
+assertFalse(desc.enumerable);
+assertFalse(desc.writable);
+assertEquals(desc.get, undefined);
+assertEquals(desc.set, undefined);
+assertEquals(desc.value, undefined);
+
+// Make sure that getOwnPropertyDescriptor does not return a descriptor
+// with default values if called with non existing property (otherwise
+// the test above is invalid).
+desc = Object.getOwnPropertyDescriptor(obj1, "bar");
+assertEquals(desc, undefined);
+
+// Make sure that foo can't be reset (as configurable is false).
+assertFalse(Reflect.defineProperty(obj1, "foo", accessorConfigurable));
+
+
+// Accessor properties
+
+assertTrue(Reflect.defineProperty(obj1, "bar", accessorConfigurable));
+desc = Object.getOwnPropertyDescriptor(obj1, "bar");
+assertTrue(desc.configurable);
+assertFalse(desc.enumerable);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.get, accessorConfigurable.get);
+assertEquals(desc.set, accessorConfigurable.set);
+assertEquals(desc.value, undefined);
+assertEquals(1, obj1.bar = 1);
+assertEquals(1, val1);
+assertEquals(1, obj1.bar = 1);
+assertEquals(2, val1);
+assertEquals(2, obj1.bar);
+
+// Redefine bar with non configurable test
+assertTrue(Reflect.defineProperty(obj1, "bar", accessorNoConfigurable));
+desc = Object.getOwnPropertyDescriptor(obj1, "bar");
+assertFalse(desc.configurable);
+assertFalse(desc.enumerable);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.get, accessorNoConfigurable.get);
+assertEquals(desc.set, accessorNoConfigurable.set);
+assertEquals(desc.value, undefined);
+assertEquals(1, obj1.bar = 1);
+assertEquals(2, val1);
+assertEquals(1, val2);
+assertEquals(1, obj1.bar = 1)
+assertEquals(2, val1);
+assertEquals(2, val2);
+assertEquals(2, obj1.bar);
+
+// Try to redefine bar again - should fail as configurable is false.
+assertFalse(Reflect.defineProperty(obj1, "bar", accessorConfigurable));
+
+// Try to redefine bar again using the data descriptor - should fail.
+assertFalse(Reflect.defineProperty(obj1, "bar", dataConfigurable));
+
+// Redefine using same descriptor - should succeed.
+assertTrue(Reflect.defineProperty(obj1, "bar", accessorNoConfigurable));
+desc = Object.getOwnPropertyDescriptor(obj1, "bar");
+assertFalse(desc.configurable);
+assertFalse(desc.enumerable);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.get, accessorNoConfigurable.get);
+assertEquals(desc.set, accessorNoConfigurable.set);
+assertEquals(desc.value, undefined);
+assertEquals(1, obj1.bar = 1);
+assertEquals(2, val1);
+assertEquals(3, val2);
+assertEquals(1, obj1.bar = 1)
+assertEquals(2, val1);
+assertEquals(4, val2);
+assertEquals(4, obj1.bar);
+
+// Define an accessor that has only a setter.
+assertTrue(Reflect.defineProperty(obj1, "setOnly", accessorOnlySet));
+desc = Object.getOwnPropertyDescriptor(obj1, "setOnly");
+assertTrue(desc.configurable);
+assertFalse(desc.enumerable);
+assertEquals(desc.set, accessorOnlySet.set);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.value, undefined);
+assertEquals(desc.get, undefined);
+assertEquals(1, obj1.setOnly = 1);
+assertEquals(1, val3);
+
+// Add a getter - should not touch the setter.
+assertTrue(Reflect.defineProperty(obj1, "setOnly", accessorOnlyGet));
+desc = Object.getOwnPropertyDescriptor(obj1, "setOnly");
+assertTrue(desc.configurable);
+assertFalse(desc.enumerable);
+assertEquals(desc.get, accessorOnlyGet.get);
+assertEquals(desc.set, accessorOnlySet.set);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.value, undefined);
+assertEquals(1, obj1.setOnly = 1);
+assertEquals(2, val3);
+
+// The above should also work if redefining just a getter or setter on
+// an existing property with both a getter and a setter.
+assertTrue(Reflect.defineProperty(obj1, "both", accessorConfigurable));
+
+assertTrue(Reflect.defineProperty(obj1, "both", accessorOnlySet));
+desc = Object.getOwnPropertyDescriptor(obj1, "both");
+assertTrue(desc.configurable);
+assertFalse(desc.enumerable);
+assertEquals(desc.set, accessorOnlySet.set);
+assertEquals(desc.get, accessorConfigurable.get);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.value, undefined);
+assertEquals(1, obj1.both = 1);
+assertEquals(3, val3);
+
+
+// Data properties
+
+assertTrue(Reflect.defineProperty(obj1, "foobar", dataConfigurable));
+desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
+assertEquals(obj1.foobar, 1000);
+assertEquals(desc.value, 1000);
+assertTrue(desc.configurable);
+assertFalse(desc.writable);
+assertFalse(desc.enumerable);
+assertEquals(desc.get, undefined);
+assertEquals(desc.set, undefined);
+//Try writing to non writable attribute - should remain 1000
+obj1.foobar = 1001;
+assertEquals(obj1.foobar, 1000);
+
+
+// Redefine to writable descriptor - now writing to foobar should be allowed.
+assertTrue(Reflect.defineProperty(obj1, "foobar", dataWritable));
+desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
+assertEquals(obj1.foobar, 3000);
+assertEquals(desc.value, 3000);
+// Note that since dataWritable does not define configurable the configurable
+// setting from the redefined property (in this case true) is used.
+assertTrue(desc.configurable);
+assertTrue(desc.writable);
+assertFalse(desc.enumerable);
+assertEquals(desc.get, undefined);
+assertEquals(desc.set, undefined);
+// Writing to the property should now be allowed
+obj1.foobar = 1001;
+assertEquals(obj1.foobar, 1001);
+
+
+// Redefine with non configurable data property.
+assertTrue(Reflect.defineProperty(obj1, "foobar", dataNoConfigurable));
+desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
+assertEquals(obj1.foobar, 2000);
+assertEquals(desc.value, 2000);
+assertFalse(desc.configurable);
+assertTrue(desc.writable);
+assertFalse(desc.enumerable);
+assertEquals(desc.get, undefined);
+assertEquals(desc.set, undefined);
+
+// Try redefine again - shold fail because configurable is now false.
+assertFalse(Reflect.defineProperty(obj1, "foobar", dataConfigurable));
+
+// Try redefine again with accessor property - shold also fail.
+assertFalse(Reflect.defineProperty(obj1, "foobar", dataConfigurable));
+
+
+// Redifine with the same descriptor - should succeed (step 6).
+assertTrue(Reflect.defineProperty(obj1, "foobar", dataNoConfigurable));
+desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
+assertEquals(obj1.foobar, 2000);
+assertEquals(desc.value, 2000);
+assertFalse(desc.configurable);
+assertTrue(desc.writable);
+assertFalse(desc.enumerable);
+assertEquals(desc.get, undefined);
+assertEquals(desc.set, undefined);
+
+
+// New object
+var obj2 = {};
+
+// Make accessor - redefine to data
+assertTrue(Reflect.defineProperty(obj2, "foo", accessorConfigurable));
+
+// Redefine to data property
+assertTrue(Reflect.defineProperty(obj2, "foo", dataConfigurable));
+desc = Object.getOwnPropertyDescriptor(obj2, "foo");
+assertEquals(obj2.foo, 1000);
+assertEquals(desc.value, 1000);
+assertTrue(desc.configurable);
+assertFalse(desc.writable);
+assertFalse(desc.enumerable);
+assertEquals(desc.get, undefined);
+assertEquals(desc.set, undefined);
+
+
+// Redefine back to accessor
+assertTrue(Reflect.defineProperty(obj2, "foo", accessorConfigurable));
+desc = Object.getOwnPropertyDescriptor(obj2, "foo");
+assertTrue(desc.configurable);
+assertFalse(desc.enumerable);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.get, accessorConfigurable.get);
+assertEquals(desc.set, accessorConfigurable.set);
+assertEquals(desc.value, undefined);
+assertEquals(1, obj2.foo = 1);
+assertEquals(3, val1);
+assertEquals(4, val2);
+assertEquals(3, obj2.foo);
+
+// Make data - redefine to accessor
+assertTrue(Reflect.defineProperty(obj2, "bar", dataConfigurable))
+
+// Redefine to accessor property
+assertTrue(Reflect.defineProperty(obj2, "bar", accessorConfigurable));
+desc = Object.getOwnPropertyDescriptor(obj2, "bar");
+assertTrue(desc.configurable);
+assertFalse(desc.enumerable);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.get, accessorConfigurable.get);
+assertEquals(desc.set, accessorConfigurable.set);
+assertEquals(desc.value, undefined);
+assertEquals(1, obj2.bar = 1);
+assertEquals(4, val1);
+assertEquals(4, val2);
+assertEquals(4, obj2.foo);
+
+// Redefine back to data property
+assertTrue(Reflect.defineProperty(obj2, "bar", dataConfigurable));
+desc = Object.getOwnPropertyDescriptor(obj2, "bar");
+assertEquals(obj2.bar, 1000);
+assertEquals(desc.value, 1000);
+assertTrue(desc.configurable);
+assertFalse(desc.writable);
+assertFalse(desc.enumerable);
+assertEquals(desc.get, undefined);
+assertEquals(desc.set, undefined);
+
+
+// Redefinition of an accessor defined using __defineGetter__ and
+// __defineSetter__.
+function get(){return this.x}
+function set(x){this.x=x};
+
+var obj3 = {x:1000};
+obj3.__defineGetter__("foo", get);
+obj3.__defineSetter__("foo", set);
+
+desc = Object.getOwnPropertyDescriptor(obj3, "foo");
+assertTrue(desc.configurable);
+assertTrue(desc.enumerable);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.get, get);
+assertEquals(desc.set, set);
+assertEquals(desc.value, undefined);
+assertEquals(1, obj3.foo = 1);
+assertEquals(1, obj3.x);
+assertEquals(1, obj3.foo);
+
+// Redefine to accessor property (non configurable) - note that enumerable
+// which we do not redefine should remain the same (true).
+assertTrue(Reflect.defineProperty(obj3, "foo", accessorNoConfigurable));
+desc = Object.getOwnPropertyDescriptor(obj3, "foo");
+assertFalse(desc.configurable);
+assertTrue(desc.enumerable);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.get, accessorNoConfigurable.get);
+assertEquals(desc.set, accessorNoConfigurable.set);
+assertEquals(desc.value, undefined);
+assertEquals(1, obj3.foo = 1);
+assertEquals(5, val2);
+assertEquals(5, obj3.foo);
+
+
+obj3.__defineGetter__("bar", get);
+obj3.__defineSetter__("bar", set);
+
+
+// Redefine back to data property
+assertTrue(Reflect.defineProperty(obj3, "bar", dataConfigurable));
+desc = Object.getOwnPropertyDescriptor(obj3, "bar");
+assertEquals(obj3.bar, 1000);
+assertEquals(desc.value, 1000);
+assertTrue(desc.configurable);
+assertFalse(desc.writable);
+assertTrue(desc.enumerable);
+assertEquals(desc.get, undefined);
+assertEquals(desc.set, undefined);
+
+
+var obj4 = {};
+var func = function (){return 42;};
+obj4.bar = func;
+assertEquals(42, obj4.bar());
+
+assertTrue(Reflect.defineProperty(obj4, "bar", accessorConfigurable));
+desc = Object.getOwnPropertyDescriptor(obj4, "bar");
+assertTrue(desc.configurable);
+assertTrue(desc.enumerable);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.get, accessorConfigurable.get);
+assertEquals(desc.set, accessorConfigurable.set);
+assertEquals(desc.value, undefined);
+assertEquals(1, obj4.bar = 1);
+assertEquals(5, val1);
+assertEquals(5, obj4.bar);
+
+// Make sure an error is thrown when trying to access to redefined function.
+try {
+  obj4.bar();
+  assertTrue(false);
+} catch (e) {
+  assertTrue(/is not a function/.test(e));
+}
+
+
+// Test runtime calls to DefineDataPropertyUnchecked and
+// DefineAccessorPropertyUnchecked - make sure we don't
+// crash.
+try {
+  %DefineAccessorPropertyUnchecked(0, 0, 0, 0, 0);
+} catch (e) {
+  assertTrue(/illegal access/.test(e));
+}
+
+try {
+  %DefineDataPropertyUnchecked(0, 0, 0, 0);
+} catch (e) {
+  assertTrue(/illegal access/.test(e));
+}
+
+try {
+  %DefineDataPropertyUnchecked(null, null, null, null);
+} catch (e) {
+  assertTrue(/illegal access/.test(e));
+}
+
+try {
+  %DefineAccessorPropertyUnchecked(null, null, null, null, null);
+} catch (e) {
+  assertTrue(/illegal access/.test(e));
+}
+
+try {
+  %DefineDataPropertyUnchecked({}, null, null, null);
+} catch (e) {
+  assertTrue(/illegal access/.test(e));
+}
+
+// Defining properties null should fail even when we have
+// other allowed values
+try {
+  %DefineAccessorPropertyUnchecked(null, 'foo', func, null, 0);
+} catch (e) {
+  assertTrue(/illegal access/.test(e));
+}
+
+try {
+  %DefineDataPropertyUnchecked(null, 'foo', 0, 0);
+} catch (e) {
+  assertTrue(/illegal access/.test(e));
+}
+
+// Test that all possible differences in step 6 in DefineOwnProperty are
+// exercised, i.e., any difference in the given property descriptor and the
+// existing properties should not return true, but throw an error if the
+// existing configurable property is false.
+
+var obj5 = {};
+// Enumerable will default to false.
+assertTrue(Reflect.defineProperty(obj5, 'foo', accessorNoConfigurable));
+desc = Object.getOwnPropertyDescriptor(obj5, 'foo');
+// First, test that we are actually allowed to set the accessor if all
+// values are of the descriptor are the same as the existing one.
+assertTrue(Reflect.defineProperty(obj5, 'foo', accessorNoConfigurable));
+
+// Different setter.
+var descDifferent = {
+  configurable:false,
+  enumerable:false,
+  set: setter1,
+  get: getter2
+};
+
+assertFalse(Reflect.defineProperty(obj5, 'foo', descDifferent));
+
+// Different getter.
+descDifferent = {
+  configurable:false,
+  enumerable:false,
+  set: setter2,
+  get: getter1
+};
+
+assertFalse(Reflect.defineProperty(obj5, 'foo', descDifferent));
+
+// Different enumerable.
+descDifferent = {
+  configurable:false,
+  enumerable:true,
+  set: setter2,
+  get: getter2
+};
+
+assertFalse(Reflect.defineProperty(obj5, 'foo', descDifferent));
+
+// Different configurable.
+descDifferent = {
+  configurable:false,
+  enumerable:true,
+  set: setter2,
+  get: getter2
+};
+
+assertFalse(Reflect.defineProperty(obj5, 'foo', descDifferent));
+
+// No difference.
+descDifferent = {
+  configurable:false,
+  enumerable:false,
+  set: setter2,
+  get: getter2
+};
+// Make sure we can still redefine if all properties are the same.
+assertTrue(Reflect.defineProperty(obj5, 'foo', descDifferent));
+
+// Make sure that obj5 still holds the original values.
+desc = Object.getOwnPropertyDescriptor(obj5, 'foo');
+assertEquals(desc.get, getter2);
+assertEquals(desc.set, setter2);
+assertFalse(desc.enumerable);
+assertFalse(desc.configurable);
+
+
+// Also exercise step 6 on data property, writable and enumerable
+// defaults to false.
+assertTrue(Reflect.defineProperty(obj5, 'bar', dataNoConfigurable));
+
+// Test that redefinition with the same property descriptor is possible
+assertTrue(Reflect.defineProperty(obj5, 'bar', dataNoConfigurable));
+
+// Different value.
+descDifferent = {
+  configurable:false,
+  enumerable:false,
+  writable: false,
+  value: 1999
+};
+
+assertFalse(Reflect.defineProperty(obj5, 'bar', descDifferent));
+
+// Different writable.
+descDifferent = {
+  configurable:false,
+  enumerable:false,
+  writable: true,
+  value: 2000
+};
+
+assertFalse(Reflect.defineProperty(obj5, 'bar', descDifferent));
+
+
+// Different enumerable.
+descDifferent = {
+  configurable:false,
+  enumerable:true ,
+  writable:false,
+  value: 2000
+};
+
+assertFalse(Reflect.defineProperty(obj5, 'bar', descDifferent));
+
+
+// Different configurable.
+descDifferent = {
+  configurable:true,
+  enumerable:false,
+  writable:false,
+  value: 2000
+};
+
+assertFalse(Reflect.defineProperty(obj5, 'bar', descDifferent));
+
+// No difference.
+descDifferent = {
+  configurable:false,
+  enumerable:false,
+  writable:false,
+  value:2000
+};
+// Make sure we can still redefine if all properties are the same.
+assertTrue(Reflect.defineProperty(obj5, 'bar', descDifferent));
+
+// Make sure that obj5 still holds the original values.
+desc = Object.getOwnPropertyDescriptor(obj5, 'bar');
+assertEquals(desc.value, 2000);
+assertFalse(desc.writable);
+assertFalse(desc.enumerable);
+assertFalse(desc.configurable);
+
+
+// Make sure that we can't overwrite +0 with -0 and vice versa.
+var descMinusZero = {value: -0, configurable: false};
+var descPlusZero = {value: +0, configurable: false};
+
+assertTrue(Reflect.defineProperty(obj5, 'minuszero', descMinusZero));
+
+// Make sure we can redefine with -0.
+assertTrue(Reflect.defineProperty(obj5, 'minuszero', descMinusZero));
+
+assertFalse(Reflect.defineProperty(obj5, 'minuszero', descPlusZero));
+
+
+assertTrue(Reflect.defineProperty(obj5, 'pluszero', descPlusZero));
+
+// Make sure we can redefine with +0.
+assertTrue(Reflect.defineProperty(obj5, 'pluszero', descPlusZero));
+
+assertFalse(Reflect.defineProperty(obj5, 'pluszero', descMinusZero));
+
+
+var obj6 = {};
+obj6[1] = 'foo';
+obj6[2] = 'bar';
+obj6[3] = '42';
+obj6[4] = '43';
+obj6[5] = '44';
+
+var descElement = { value: 'foobar' };
+var descElementNonConfigurable = { value: 'barfoo', configurable: false };
+var descElementNonWritable = { value: 'foofoo', writable: false };
+var descElementNonEnumerable = { value: 'barbar', enumerable: false };
+var descElementAllFalse = { value: 'foofalse',
+                            configurable: false,
+                            writable: false,
+                            enumerable: false };
+
+
+// Redefine existing property.
+assertTrue(Reflect.defineProperty(obj6, '1', descElement));
+desc = Object.getOwnPropertyDescriptor(obj6, '1');
+assertEquals(desc.value, 'foobar');
+assertTrue(desc.writable);
+assertTrue(desc.enumerable);
+assertTrue(desc.configurable);
+
+// Redefine existing property with configurable: false.
+assertTrue(Reflect.defineProperty(obj6, '2', descElementNonConfigurable));
+desc = Object.getOwnPropertyDescriptor(obj6, '2');
+assertEquals(desc.value, 'barfoo');
+assertTrue(desc.writable);
+assertTrue(desc.enumerable);
+assertFalse(desc.configurable);
+
+// Can use defineProperty to change the value of a non
+// configurable property.
+try {
+  assertTrue(Reflect.defineProperty(obj6, '2', descElement));
+  desc = Object.getOwnPropertyDescriptor(obj6, '2');
+  assertEquals(desc.value, 'foobar');
+} catch (e) {
+  assertUnreachable();
+}
+
+// Ensure that we can't change the descriptor of a
+// non configurable property.
+var descAccessor = { get: function() { return 0; } };
+assertFalse(Reflect.defineProperty(obj6, '2', descAccessor));
+
+assertTrue(Reflect.defineProperty(obj6, '2', descElementNonWritable));
+desc = Object.getOwnPropertyDescriptor(obj6, '2');
+assertEquals(desc.value, 'foofoo');
+assertFalse(desc.writable);
+assertTrue(desc.enumerable);
+assertFalse(desc.configurable);
+
+assertTrue(Reflect.defineProperty(obj6, '3', descElementNonWritable));
+desc = Object.getOwnPropertyDescriptor(obj6, '3');
+assertEquals(desc.value, 'foofoo');
+assertFalse(desc.writable);
+assertTrue(desc.enumerable);
+assertTrue(desc.configurable);
+
+// Redefine existing property with configurable: false.
+assertTrue(Reflect.defineProperty(obj6, '4', descElementNonEnumerable));
+desc = Object.getOwnPropertyDescriptor(obj6, '4');
+assertEquals(desc.value, 'barbar');
+assertTrue(desc.writable);
+assertFalse(desc.enumerable);
+assertTrue(desc.configurable);
+
+// Redefine existing property with configurable: false.
+assertTrue(Reflect.defineProperty(obj6, '5', descElementAllFalse));
+desc = Object.getOwnPropertyDescriptor(obj6, '5');
+assertEquals(desc.value, 'foofalse');
+assertFalse(desc.writable);
+assertFalse(desc.enumerable);
+assertFalse(desc.configurable);
+
+// Define non existing property - all attributes should default to false.
+assertTrue(Reflect.defineProperty(obj6, '15', descElement));
+desc = Object.getOwnPropertyDescriptor(obj6, '15');
+assertEquals(desc.value, 'foobar');
+assertFalse(desc.writable);
+assertFalse(desc.enumerable);
+assertFalse(desc.configurable);
+
+// Make sure that we can't redefine using direct access.
+obj6[15] ='overwrite';
+assertEquals(obj6[15],'foobar');
+
+
+// Repeat the above tests on an array.
+var arr = new Array();
+arr[1] = 'foo';
+arr[2] = 'bar';
+arr[3] = '42';
+arr[4] = '43';
+arr[5] = '44';
+
+var descElement = { value: 'foobar' };
+var descElementNonConfigurable = { value: 'barfoo', configurable: false };
+var descElementNonWritable = { value: 'foofoo', writable: false };
+var descElementNonEnumerable = { value: 'barbar', enumerable: false };
+var descElementAllFalse = { value: 'foofalse',
+                            configurable: false,
+                            writable: false,
+                            enumerable: false };
+
+
+// Redefine existing property.
+assertTrue(Reflect.defineProperty(arr, '1', descElement));
+desc = Object.getOwnPropertyDescriptor(arr, '1');
+assertEquals(desc.value, 'foobar');
+assertTrue(desc.writable);
+assertTrue(desc.enumerable);
+assertTrue(desc.configurable);
+
+// Redefine existing property with configurable: false.
+assertTrue(Reflect.defineProperty(arr, '2', descElementNonConfigurable));
+desc = Object.getOwnPropertyDescriptor(arr, '2');
+assertEquals(desc.value, 'barfoo');
+assertTrue(desc.writable);
+assertTrue(desc.enumerable);
+assertFalse(desc.configurable);
+
+// Can use defineProperty to change the value of a non
+// configurable property of an array.
+try {
+  assertTrue(Reflect.defineProperty(arr, '2', descElement));
+  desc = Object.getOwnPropertyDescriptor(arr, '2');
+  assertEquals(desc.value, 'foobar');
+} catch (e) {
+  assertUnreachable();
+}
+
+// Ensure that we can't change the descriptor of a
+// non configurable property.
+var descAccessor = { get: function() { return 0; } };
+assertFalse(Reflect.defineProperty(arr, '2', descAccessor));
+
+assertTrue(Reflect.defineProperty(arr, '2', descElementNonWritable));
+desc = Object.getOwnPropertyDescriptor(arr, '2');
+assertEquals(desc.value, 'foofoo');
+assertFalse(desc.writable);
+assertTrue(desc.enumerable);
+assertFalse(desc.configurable);
+
+assertTrue(Reflect.defineProperty(arr, '3', descElementNonWritable));
+desc = Object.getOwnPropertyDescriptor(arr, '3');
+assertEquals(desc.value, 'foofoo');
+assertFalse(desc.writable);
+assertTrue(desc.enumerable);
+assertTrue(desc.configurable);
+
+// Redefine existing property with configurable: false.
+assertTrue(Reflect.defineProperty(arr, '4', descElementNonEnumerable));
+desc = Object.getOwnPropertyDescriptor(arr, '4');
+assertEquals(desc.value, 'barbar');
+assertTrue(desc.writable);
+assertFalse(desc.enumerable);
+assertTrue(desc.configurable);
+
+// Redefine existing property with configurable: false.
+assertTrue(Reflect.defineProperty(arr, '5', descElementAllFalse));
+desc = Object.getOwnPropertyDescriptor(arr, '5');
+assertEquals(desc.value, 'foofalse');
+assertFalse(desc.writable);
+assertFalse(desc.enumerable);
+assertFalse(desc.configurable);
+
+// Define non existing property - all attributes should default to false.
+assertTrue(Reflect.defineProperty(arr, '15', descElement));
+desc = Object.getOwnPropertyDescriptor(arr, '15');
+assertEquals(desc.value, 'foobar');
+assertFalse(desc.writable);
+assertFalse(desc.enumerable);
+assertFalse(desc.configurable);
+
+// Define non-array property, check that .length is unaffected.
+assertEquals(16, arr.length);
+assertTrue(Reflect.defineProperty(arr, '0x20', descElement));
+assertEquals(16, arr.length);
+
+// See issue 968: http://code.google.com/p/v8/issues/detail?id=968
+var o = { x : 42 };
+assertTrue(Reflect.defineProperty(o, "x", { writable: false }));
+assertEquals(42, o.x);
+o.x = 37;
+assertEquals(42, o.x);
+
+o = { x : 42 };
+assertTrue(Reflect.defineProperty(o, "x", {}));
+assertEquals(42, o.x);
+o.x = 37;
+// Writability is preserved.
+assertEquals(37, o.x);
+
+var o = { };
+assertTrue(Reflect.defineProperty(o, "x", { writable: false }));
+assertEquals(undefined, o.x);
+o.x = 37;
+assertEquals(undefined, o.x);
+
+o = { get x() { return 87; } };
+assertTrue(Reflect.defineProperty(o, "x", { writable: false }));
+assertEquals(undefined, o.x);
+o.x = 37;
+assertEquals(undefined, o.x);
+
+// Ignore inherited properties.
+o = { __proto__ : { x : 87 } };
+assertTrue(Reflect.defineProperty(o, "x", { writable: false }));
+assertEquals(undefined, o.x);
+o.x = 37;
+assertEquals(undefined, o.x);
+
+function testDefineProperty(obj, propertyName, desc, resultDesc) {
+  assertTrue(Reflect.defineProperty(obj, propertyName, desc));
+  var actualDesc = Object.getOwnPropertyDescriptor(obj, propertyName);
+  assertEquals(resultDesc.enumerable, actualDesc.enumerable);
+  assertEquals(resultDesc.configurable, actualDesc.configurable);
+  if (resultDesc.hasOwnProperty('value')) {
+    assertEquals(resultDesc.value, actualDesc.value);
+    assertEquals(resultDesc.writable, actualDesc.writable);
+    assertFalse(resultDesc.hasOwnProperty('get'));
+    assertFalse(resultDesc.hasOwnProperty('set'));
+  } else {
+    assertEquals(resultDesc.get, actualDesc.get);
+    assertEquals(resultDesc.set, actualDesc.set);
+    assertFalse(resultDesc.hasOwnProperty('value'));
+    assertFalse(resultDesc.hasOwnProperty('writable'));
+  }
+}
+
+// tests redefining existing property with a generic descriptor
+o = { p : 42 };
+testDefineProperty(o, 'p',
+  { },
+  { value : 42, writable : true, enumerable : true, configurable : true });
+
+o = { p : 42 };
+testDefineProperty(o, 'p',
+  { enumerable : true },
+  { value : 42, writable : true, enumerable : true, configurable : true });
+
+o = { p : 42 };
+testDefineProperty(o, 'p',
+  { configurable : true },
+  { value : 42, writable : true, enumerable : true, configurable : true });
+
+o = { p : 42 };
+testDefineProperty(o, 'p',
+  { enumerable : false },
+  { value : 42, writable : true, enumerable : false, configurable : true });
+
+o = { p : 42 };
+testDefineProperty(o, 'p',
+  { configurable : false },
+  { value : 42, writable : true, enumerable : true, configurable : false });
+
+o = { p : 42 };
+testDefineProperty(o, 'p',
+  { enumerable : true, configurable : true },
+  { value : 42, writable : true, enumerable : true, configurable : true });
+
+o = { p : 42 };
+testDefineProperty(o, 'p',
+  { enumerable : false, configurable : true },
+  { value : 42, writable : true, enumerable : false, configurable : true });
+
+o = { p : 42 };
+testDefineProperty(o, 'p',
+  { enumerable : true, configurable : false },
+  { value : 42, writable : true, enumerable : true, configurable : false });
+
+o = { p : 42 };
+testDefineProperty(o, 'p',
+  { enumerable : false, configurable : false },
+  { value : 42, writable : true, enumerable : false, configurable : false });
+
+// can make a writable, non-configurable field non-writable
+o = { p : 42 };
+assertTrue(Reflect.defineProperty(o, 'p', { configurable: false }));
+testDefineProperty(o, 'p',
+  { writable: false },
+  { value : 42, writable : false, enumerable : true, configurable : false });
+
+// redefine of get only property with generic descriptor
+o = {};
+assertTrue(Reflect.defineProperty(o, 'p',
+  { get : getter1, enumerable: true, configurable: true }));
+testDefineProperty(o, 'p',
+  { enumerable : false, configurable : false },
+  { get: getter1, set: undefined, enumerable : false, configurable : false });
+
+// redefine of get/set only property with generic descriptor
+o = {};
+assertTrue(Reflect.defineProperty(o, 'p',
+  { get: getter1, set: setter1, enumerable: true, configurable: true }));
+testDefineProperty(o, 'p',
+  { enumerable : false, configurable : false },
+  { get: getter1, set: setter1, enumerable : false, configurable : false });
+
+// redefine of set only property with generic descriptor
+o = {};
+assertTrue(Reflect.defineProperty(o, 'p',
+  { set : setter1, enumerable: true, configurable: true }));
+testDefineProperty(o, 'p',
+  { enumerable : false, configurable : false },
+  { get: undefined, set: setter1, enumerable : false, configurable : false });
+
+
+// Regression test: Ensure that growing dictionaries are not ignored.
+o = {};
+for (var i = 0; i < 1000; i++) {
+  // Non-enumerable property forces dictionary mode.
+  assertTrue(Reflect.defineProperty(o, i, {value: i, enumerable: false}));
+}
+assertEquals(999, o[999]);
+
+
+// Regression test: Bizzare behavior on non-strict arguments object.
+// TODO(yangguo): Tests disabled, needs investigation!
+/*
+(function test(arg0) {
+  // Here arguments[0] is a fast alias on arg0.
+  Reflect.defineProperty(arguments, "0", {
+    value:1,
+    enumerable:false
+  });
+  // Here arguments[0] is a slow alias on arg0.
+  Reflect.defineProperty(arguments, "0", {
+    value:2,
+    writable:false
+  });
+  // Here arguments[0] is no alias at all.
+  Reflect.defineProperty(arguments, "0", {
+    value:3
+  });
+  assertEquals(2, arg0);
+  assertEquals(3, arguments[0]);
+})(0);
+*/
+
+// Regression test: We should never observe the hole value.
+var objectWithGetter = {};
+objectWithGetter.__defineGetter__('foo', function() {});
+assertEquals(undefined, objectWithGetter.__lookupSetter__('foo'));
+
+var objectWithSetter = {};
+objectWithSetter.__defineSetter__('foo', function(x) {});
+assertEquals(undefined, objectWithSetter.__lookupGetter__('foo'));
+
+// An object with a getter on the prototype chain.
+function getter() { return 111; }
+function anotherGetter() { return 222; }
+
+function testGetterOnProto(expected, o) {
+  assertEquals(expected, o.quebec);
+}
+
+obj1 = {};
+assertTrue(
+  Reflect.defineProperty(obj1, "quebec", { get: getter, configurable: true }));
+obj2 = Object.create(obj1);
+obj3 = Object.create(obj2);
+
+testGetterOnProto(111, obj3);
+testGetterOnProto(111, obj3);
+%OptimizeFunctionOnNextCall(testGetterOnProto);
+testGetterOnProto(111, obj3);
+testGetterOnProto(111, obj3);
+
+assertTrue(Reflect.defineProperty(obj1, "quebec", { get: anotherGetter }));
+
+testGetterOnProto(222, obj3);
+testGetterOnProto(222, obj3);
+%OptimizeFunctionOnNextCall(testGetterOnProto);
+testGetterOnProto(222, obj3);
+testGetterOnProto(222, obj3);
+
+// An object with a setter on the prototype chain.
+var modifyMe;
+function setter(x) { modifyMe = x+1; }
+function anotherSetter(x) { modifyMe = x+2; }
+
+function testSetterOnProto(expected, o) {
+  modifyMe = 333;
+  o.romeo = 444;
+  assertEquals(expected, modifyMe);
+}
+
+obj1 = {};
+assertTrue(
+  Reflect.defineProperty(obj1, "romeo", { set: setter, configurable: true }));
+obj2 = Object.create(obj1);
+obj3 = Object.create(obj2);
+
+testSetterOnProto(445, obj3);
+testSetterOnProto(445, obj3);
+%OptimizeFunctionOnNextCall(testSetterOnProto);
+testSetterOnProto(445, obj3);
+testSetterOnProto(445, obj3);
+
+assertTrue(Reflect.defineProperty(obj1, "romeo", { set: anotherSetter }));
+
+testSetterOnProto(446, obj3);
+testSetterOnProto(446, obj3);
+%OptimizeFunctionOnNextCall(testSetterOnProto);
+testSetterOnProto(446, obj3);
+testSetterOnProto(446, obj3);
+
+// Removing a setter on the prototype chain.
+function testSetterOnProtoStrict(o) {
+  "use strict";
+  o.sierra = 12345;
+}
+
+obj1 = {};
+assertTrue(Reflect.defineProperty(obj1, "sierra",
+                      { get: getter, set: setter, configurable: true }));
+obj2 = Object.create(obj1);
+obj3 = Object.create(obj2);
+
+testSetterOnProtoStrict(obj3);
+testSetterOnProtoStrict(obj3);
+%OptimizeFunctionOnNextCall(testSetterOnProtoStrict);
+testSetterOnProtoStrict(obj3);
+testSetterOnProtoStrict(obj3);
+
+assertTrue(Reflect.defineProperty(obj1, "sierra",
+                      { get: getter, set: undefined, configurable: true }));
+
+exception = false;
+try {
+  testSetterOnProtoStrict(obj3);
+} catch (e) {
+  exception = true;
+  assertTrue(/which has only a getter/.test(e));
+}
+assertTrue(exception);
+
+// Test assignment to a getter-only property on the prototype chain. This makes
+// sure that crankshaft re-checks its assumptions and doesn't rely only on type
+// feedback (which would be monomorphic here).
+
+function Assign(o) {
+  o.blubb = 123;
+}
+
+function C() {}
+
+Assign(new C);
+Assign(new C);
+%OptimizeFunctionOnNextCall(Assign);
+assertTrue(
+  Reflect.defineProperty(C.prototype, "blubb", {get: function() {return -42}}));
+Assign(new C);
+
+// Test that changes to the prototype of a simple constructor are not ignored,
+// even after creating initial instances.
+function C() {
+  this.x = 23;
+}
+assertEquals(23, new C().x);
+C.prototype.__defineSetter__('x', function(value) { this.y = 23; });
+assertEquals(void 0, new C().x);
diff --git a/test/mjsunit/es6/reflect-get-own-property-descriptor.js b/test/mjsunit/es6/reflect-get-own-property-descriptor.js
new file mode 100644
index 0000000..5e96899
--- /dev/null
+++ b/test/mjsunit/es6/reflect-get-own-property-descriptor.js
@@ -0,0 +1,121 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file only tests very simple descriptors that always have
+// configurable, enumerable, and writable set to true.
+
+// This is adapted from mjsunit/get-own-property-descriptor.js.
+
+function get() { return x; }
+function set(x) { this.x = x; }
+
+var obj = {x: 1};
+obj.__defineGetter__("accessor", get);
+obj.__defineSetter__("accessor", set);
+var a = new Array();
+a[1] = 42;
+obj[1] = 42;
+
+var descIsData = Reflect.getOwnPropertyDescriptor(obj, 'x');
+assertTrue(descIsData.enumerable);
+assertTrue(descIsData.writable);
+assertTrue(descIsData.configurable);
+
+var descIsAccessor = Reflect.getOwnPropertyDescriptor(obj, 'accessor');
+assertTrue(descIsAccessor.enumerable);
+assertTrue(descIsAccessor.configurable);
+assertTrue(descIsAccessor.get == get);
+assertTrue(descIsAccessor.set == set);
+
+var descIsNotData = Reflect.getOwnPropertyDescriptor(obj, 'not-x');
+assertTrue(descIsNotData == undefined);
+
+var descIsNotAccessor = Reflect.getOwnPropertyDescriptor(obj, 'not-accessor');
+assertTrue(descIsNotAccessor == undefined);
+
+var descArray = Reflect.getOwnPropertyDescriptor(a, '1');
+assertTrue(descArray.enumerable);
+assertTrue(descArray.configurable);
+assertTrue(descArray.writable);
+assertEquals(descArray.value, 42);
+
+var descObjectElement = Reflect.getOwnPropertyDescriptor(obj, '1');
+assertTrue(descObjectElement.enumerable);
+assertTrue(descObjectElement.configurable);
+assertTrue(descObjectElement.writable);
+assertEquals(descObjectElement.value, 42);
+
+// String objects.
+var a = new String('foobar');
+for (var i = 0; i < a.length; i++) {
+  var descStringObject = Reflect.getOwnPropertyDescriptor(a, i);
+  assertTrue(descStringObject.enumerable);
+  assertFalse(descStringObject.configurable);
+  assertFalse(descStringObject.writable);
+  assertEquals(descStringObject.value, a.substring(i, i+1));
+}
+
+// Support for additional attributes on string objects.
+a.x = 42;
+a[10] = 'foo';
+var descStringProperty = Reflect.getOwnPropertyDescriptor(a, 'x');
+assertTrue(descStringProperty.enumerable);
+assertTrue(descStringProperty.configurable);
+assertTrue(descStringProperty.writable);
+assertEquals(descStringProperty.value, 42);
+
+var descStringElement = Reflect.getOwnPropertyDescriptor(a, '10');
+assertTrue(descStringElement.enumerable);
+assertTrue(descStringElement.configurable);
+assertTrue(descStringElement.writable);
+assertEquals(descStringElement.value, 'foo');
+
+// Test that elements in the prototype chain is not returned.
+var proto = {};
+proto[10] = 42;
+
+var objWithProto = new Array();
+objWithProto.prototype = proto;
+objWithProto[0] = 'bar';
+var descWithProto = Reflect.getOwnPropertyDescriptor(objWithProto, '10');
+assertEquals(undefined, descWithProto);
+
+// Test elements on global proxy object.
+var global = (function() { return this; })();
+
+global[42] = 42;
+
+function el_getter() { return 239; };
+function el_setter() {};
+Object.defineProperty(global, '239', {get: el_getter, set: el_setter});
+
+var descRegularElement = Reflect.getOwnPropertyDescriptor(global, '42');
+assertEquals(42, descRegularElement.value);
+
+var descAccessorElement = Reflect.getOwnPropertyDescriptor(global, '239');
+assertEquals(el_getter, descAccessorElement.get);
+assertEquals(el_setter, descAccessorElement.set);
diff --git a/test/mjsunit/es6/reflect-get-prototype-of.js b/test/mjsunit/es6/reflect-get-prototype-of.js
new file mode 100644
index 0000000..9fd1559
--- /dev/null
+++ b/test/mjsunit/es6/reflect-get-prototype-of.js
@@ -0,0 +1,137 @@
+// Copyright 2010-2015 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Tests the Reflect.getPrototypeOf - ES6 26.1.8.
+// This is adapted from mjsunit/get-prototype-of.js.
+
+
+
+function assertPrototypeOf(func, expected) {
+  assertEquals(expected, Reflect.getPrototypeOf(func));
+}
+
+
+assertThrows(function() {
+  Reflect.getPrototypeOf(undefined);
+}, TypeError);
+
+
+assertThrows(function() {
+  Reflect.getPrototypeOf(null);
+}, TypeError);
+
+
+function F(){};
+var y = new F();
+
+assertPrototypeOf(y, F.prototype);
+assertPrototypeOf(F, Function.prototype);
+
+assertPrototypeOf({x: 5}, Object.prototype);
+assertPrototypeOf({x: 5, __proto__: null}, null);
+
+assertPrototypeOf([1, 2], Array.prototype);
+
+
+assertThrows(function () {
+  Reflect.getPrototypeOf(1);
+}, TypeError);
+assertThrows(function () {
+  Reflect.getPrototypeOf(true);
+}, TypeError);
+assertThrows(function () {
+  Reflect.getPrototypeOf(false);
+}, TypeError);
+assertThrows(function () {
+  Reflect.getPrototypeOf('str');
+}, TypeError);
+assertThrows(function () {
+  Reflect.getPrototypeOf(Symbol());
+}, TypeError);
+
+assertPrototypeOf(Object(1), Number.prototype);
+assertPrototypeOf(Object(true), Boolean.prototype);
+assertPrototypeOf(Object(false), Boolean.prototype);
+assertPrototypeOf(Object('str'), String.prototype);
+assertPrototypeOf(Object(Symbol()), Symbol.prototype);
+
+
+var errorFunctions = [
+  EvalError,
+  RangeError,
+  ReferenceError,
+  SyntaxError,
+  TypeError,
+  URIError,
+];
+
+for (var f of errorFunctions) {
+  assertPrototypeOf(f, Error);
+  assertPrototypeOf(new f(), f.prototype);
+}
+
+
+// Builtin constructors.
+var functions = [
+  Array,
+  ArrayBuffer,
+  Boolean,
+  // DataView,
+  Date,
+  Error,
+  // Float32Array, prototype is %TypedArray%
+  // Float64Array,
+  Function,
+  // Int16Array,
+  // Int32Array,
+  // Int8Array,
+  Map,
+  Number,
+  Object,
+  // Promise,
+  RegExp,
+  Set,
+  String,
+  // Symbol, not constructible
+  // Uint16Array,
+  // Uint32Array,
+  // Uint8Array,
+  // Uint8ClampedArray,
+  WeakMap,
+  WeakSet,
+];
+
+for (var f of functions) {
+  assertPrototypeOf(f, Function.prototype);
+  assertPrototypeOf(new f(), f.prototype);
+}
+
+var p = new Promise(function() {});
+assertPrototypeOf(p, Promise.prototype);
+
+var dv = new DataView(new ArrayBuffer());
+assertPrototypeOf(dv, DataView.prototype);
diff --git a/test/mjsunit/es6/reflect-own-keys.js b/test/mjsunit/es6/reflect-own-keys.js
new file mode 100644
index 0000000..5f51f40
--- /dev/null
+++ b/test/mjsunit/es6/reflect-own-keys.js
@@ -0,0 +1,91 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This is adapted from mjsunit/object-get-own-property-names.js.
+
+
+// Check simple cases.
+var obj = { a: 1, b: 2};
+var keys = Reflect.ownKeys(obj);
+assertEquals(2, keys.length);
+assertEquals("a", keys[0]);
+assertEquals("b", keys[1]);
+
+var obj = { a: function(){}, b: function(){} };
+var keys = Reflect.ownKeys(obj);
+assertEquals(2, keys.length);
+assertEquals("a", keys[0]);
+assertEquals("b", keys[1]);
+
+// Check slow case
+var obj = { a: 1, b: 2, c: 3 };
+delete obj.b;
+var keys = Reflect.ownKeys(obj)
+assertEquals(2, keys.length);
+assertEquals("a", keys[0]);
+assertEquals("c", keys[1]);
+
+// Check that non-enumerable properties are being returned.
+var keys = Reflect.ownKeys([1, 2]);
+assertEquals(3, keys.length);
+assertEquals("0", keys[0]);
+assertEquals("1", keys[1]);
+assertEquals("string", typeof keys[0]);
+assertEquals("string", typeof keys[1]);
+assertEquals("length", keys[2]);
+
+// Check that no proto properties are returned.
+var obj = { foo: "foo" };
+obj.__proto__ = { bar: "bar" };
+keys = Reflect.ownKeys(obj);
+assertEquals(1, keys.length);
+assertEquals("foo", keys[0]);
+
+// Check that getter properties are returned.
+var obj = {};
+obj.__defineGetter__("getter", function() {});
+keys = Reflect.ownKeys(obj);
+assertEquals(1, keys.length);
+assertEquals("getter", keys[0]);
+
+// Check that implementation does not access Array.prototype.
+var savedConcat = Array.prototype.concat;
+Array.prototype.concat = function() { return []; }
+keys = Reflect.ownKeys({0: 'foo', bar: 'baz'});
+assertEquals(2, keys.length);
+assertEquals('0', keys[0]);
+assertEquals('bar', keys[1]);
+assertSame(Array.prototype, keys.__proto__);
+Array.prototype.concat = savedConcat;
+
+assertThrows(function() { Reflect.ownKeys(4) }, TypeError);
+assertThrows(function() { Reflect.ownKeys("foo") }, TypeError);
+assertThrows(function() { Reflect.ownKeys(true) }, TypeError);
+
+assertEquals(Reflect.ownKeys(Object(4)), []);
+assertEquals(Reflect.ownKeys(Object("foo")), ["0", "1", "2", "length"]);
+assertEquals(Reflect.ownKeys(Object(true)), []);
diff --git a/test/mjsunit/es6/reflect-prevent-extensions.js b/test/mjsunit/es6/reflect-prevent-extensions.js
new file mode 100644
index 0000000..c6f3749
--- /dev/null
+++ b/test/mjsunit/es6/reflect-prevent-extensions.js
@@ -0,0 +1,164 @@
+// Copyright 2010-2015 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Tests the Reflect.preventExtensions method - ES6 26.1.12.
+// This is adapted from object-prevent-extensions.js.
+
+// Flags: --allow-natives-syntax
+
+
+var obj1 = {};
+// Extensible defaults to true.
+assertTrue(Object.isExtensible(obj1));
+assertTrue(Reflect.preventExtensions(obj1));
+
+// Make sure the is_extensible flag is set.
+assertFalse(Object.isExtensible(obj1));
+obj1.x = 42;
+assertEquals(undefined, obj1.x);
+
+// Try adding a new element.
+obj1[1] = 42;
+assertEquals(undefined, obj1[1]);
+
+
+// Try when the object has an existing property.
+var obj2 = {};
+assertTrue(Object.isExtensible(obj2));
+obj2.x = 42;
+assertEquals(42, obj2.x);
+assertTrue(Object.isExtensible(obj2));
+
+assertTrue(Reflect.preventExtensions(obj2));
+assertEquals(42, obj2.x);
+
+obj2.y = 42;
+// obj2.y should still be undefined.
+assertEquals(undefined, obj2.y);
+// Make sure we can still write values to obj.x.
+obj2.x = 43;
+assertEquals(43, obj2.x)
+
+obj2.y = new function() { return 42; };
+// obj2.y should still be undefined.
+assertEquals(undefined, obj2.y);
+assertEquals(43, obj2.x)
+
+try {
+  Object.defineProperty(obj2, "y", {value: 42});
+} catch (e) {
+  assertTrue(/object is not extensible/.test(e));
+}
+
+// obj2.y should still be undefined.
+assertEquals(undefined, obj2.y);
+assertEquals(43, obj2.x);
+
+obj2[1] = 42;
+assertEquals(undefined, obj2[1]);
+
+var arr = new Array();
+arr[1] = 10;
+
+assertTrue(Reflect.preventExtensions(arr));
+
+arr[2] = 42;
+assertEquals(10, arr[1]);
+
+// We should still be able to change existing elements.
+arr[1]= 42;
+assertEquals(42, arr[1]);
+
+
+// Test the the extensible flag is not inherited.
+var parent = {};
+parent.x = 42;
+assertTrue(Reflect.preventExtensions(parent));
+
+var child = Object.create(parent);
+
+// We should be able to add new properties to the child object.
+child.y = 42;
+
+// This should have no influence on the parent class.
+parent.y = 29;
+
+
+// Test that attributes on functions are also handled correctly.
+function foo() {
+  return 42;
+}
+
+assertTrue(Reflect.preventExtensions(foo));
+
+foo.x = 29;
+assertEquals(undefined, foo.x);
+
+// when Object.isExtensible(o) === false
+// assignment should return right hand side value
+var o = {};
+assertTrue(Reflect.preventExtensions(o));
+var v = o.v = 50;
+assertEquals(undefined, o.v);
+assertEquals(50, v);
+
+// test same behavior as above, but for integer properties
+var n = o[0] = 100;
+assertEquals(undefined, o[0]);
+assertEquals(100, n);
+
+// Fast properties should remain fast
+obj = { x: 42, y: 'foo' };
+assertTrue(%HasFastProperties(obj));
+assertTrue(Reflect.preventExtensions(obj));
+assertFalse(Object.isExtensible(obj));
+assertFalse(Object.isSealed(obj));
+assertTrue(%HasFastProperties(obj));
+
+// Non-extensible objects should share maps where possible
+obj = { prop1: 1, prop2: 2 };
+obj2 = { prop1: 3, prop2: 4 };
+assertTrue(%HaveSameMap(obj, obj2));
+assertTrue(Reflect.preventExtensions(obj));
+assertTrue(Reflect.preventExtensions(obj2));
+assertFalse(Object.isExtensible(obj));
+assertFalse(Object.isExtensible(obj2));
+assertFalse(Object.isSealed(obj));
+assertFalse(Object.isSealed(obj2));
+assertTrue(%HaveSameMap(obj, obj2));
+
+// Non-extensible objects should share maps even when they have elements
+obj = { prop1: 1, prop2: 2, 75: 'foo' };
+obj2 = { prop1: 3, prop2: 4, 150: 'bar' };
+assertTrue(%HaveSameMap(obj, obj2));
+assertTrue(Reflect.preventExtensions(obj));
+assertTrue(Reflect.preventExtensions(obj2));
+assertFalse(Object.isExtensible(obj));
+assertFalse(Object.isExtensible(obj2));
+assertFalse(Object.isSealed(obj));
+assertFalse(Object.isSealed(obj2));
+assertTrue(%HaveSameMap(obj, obj2));
diff --git a/test/mjsunit/es6/reflect-set-prototype-of.js b/test/mjsunit/es6/reflect-set-prototype-of.js
new file mode 100644
index 0000000..8f2a00a
--- /dev/null
+++ b/test/mjsunit/es6/reflect-set-prototype-of.js
@@ -0,0 +1,182 @@
+// Copyright 2014-2015 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This is adapted from mjsunit/harmony/set-prototype-of.js.
+
+
+
+function getObjects() {
+  function func() {}
+  return [
+    func,
+    new func(),
+    {x: 5},
+    /regexp/,
+    ['array'],
+    // new Error(),
+    new Date(),
+    new Number(1),
+    new Boolean(true),
+    new String('str'),
+    Object(Symbol())
+  ];
+}
+
+
+var coercibleValues = [
+  1,
+  true,
+  'string',
+  Symbol()
+];
+
+
+var nonCoercibleValues = [
+  undefined,
+  null
+];
+
+
+var valuesWithoutNull = coercibleValues.concat(undefined);
+
+
+function TestSetPrototypeOfCoercibleValues() {
+  for (var i = 0; i < coercibleValues.length; i++) {
+    var value = coercibleValues[i];
+    var proto = Object.getPrototypeOf(value);
+    assertThrows(function() { Reflect.setPrototypeOf(value, {}) }, TypeError);
+    assertSame(proto, Object.getPrototypeOf(value));
+  }
+}
+TestSetPrototypeOfCoercibleValues();
+
+
+function TestSetPrototypeOfNonCoercibleValues() {
+  for (var i = 0; i < nonCoercibleValues.length; i++) {
+    var value = nonCoercibleValues[i];
+    assertThrows(function() {
+      Reflect.setPrototypeOf(value, {});
+    }, TypeError);
+  }
+}
+TestSetPrototypeOfNonCoercibleValues();
+
+
+function TestSetPrototypeToNonObject(proto) {
+  var objects = getObjects();
+  for (var i = 0; i < objects.length; i++) {
+    var object = objects[i];
+    for (var j = 0; j < valuesWithoutNull.length; j++) {
+      var proto = valuesWithoutNull[j];
+      assertThrows(function() {
+        Reflect.setPrototypeOf(object, proto);
+      }, TypeError);
+    }
+  }
+}
+TestSetPrototypeToNonObject();
+
+
+function TestSetPrototypeOf(object, proto) {
+  assertTrue(Reflect.setPrototypeOf(object, proto));
+  assertEquals(Object.getPrototypeOf(object), proto);
+}
+
+
+function TestSetPrototypeOfForObjects() {
+  var objects1 = getObjects();
+  var objects2 = getObjects();
+  for (var i = 0; i < objects1.length; i++) {
+    for (var j = 0; j < objects2.length; j++) {
+      TestSetPrototypeOf(objects1[i], objects2[j]);
+    }
+  }
+}
+TestSetPrototypeOfForObjects();
+
+
+function TestSetPrototypeToNull() {
+  var objects = getObjects();
+  for (var i = 0; i < objects.length; i++) {
+    TestSetPrototypeOf(objects[i], null);
+  }
+}
+TestSetPrototypeToNull();
+
+
+function TestSetPrototypeOfNonExtensibleObject() {
+  var objects = getObjects();
+  var proto = {};
+  for (var i = 0; i < objects.length; i++) {
+    var object = objects[i];
+    Object.preventExtensions(object);
+    // Setting the current prototype must succeed.
+    assertTrue(Reflect.setPrototypeOf(object, Object.getPrototypeOf(object)));
+    // Setting any other must fail.
+    assertFalse(Reflect.setPrototypeOf(object, proto));
+  }
+}
+TestSetPrototypeOfNonExtensibleObject();
+
+
+function TestSetPrototypeCyclic() {
+  var objects = [
+    Object.prototype, {},
+    Array.prototype, [],
+    Error.prototype, new TypeError,
+    // etc ...
+  ];
+  for (var i = 0; i < objects.length; i += 2) {
+    var object = objects[i];
+    var value = objects[i + 1];
+    assertFalse(Reflect.setPrototypeOf(object, value));
+  }
+}
+TestSetPrototypeCyclic();
+
+
+function TestLookup() {
+  var object = {};
+  assertFalse('x' in object);
+  assertFalse('y' in object);
+
+  var oldProto = {
+    x: 'old x',
+    y: 'old y'
+  };
+  assertTrue(Reflect.setPrototypeOf(object, oldProto));
+  assertEquals(object.x, 'old x');
+  assertEquals(object.y, 'old y');
+
+  var newProto = {
+    x: 'new x'
+  };
+  assertTrue(Reflect.setPrototypeOf(object, newProto));
+  assertEquals(object.x, 'new x');
+  assertFalse('y' in object);
+}
+TestLookup();
diff --git a/test/mjsunit/es6/reflect.js b/test/mjsunit/es6/reflect.js
new file mode 100644
index 0000000..ee272b0
--- /dev/null
+++ b/test/mjsunit/es6/reflect.js
@@ -0,0 +1,570 @@
+// 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.
+
+// TODO(neis): Test with proxies.
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// (Auxiliaries)
+
+
+"use strict";
+
+var global = this;
+
+var sym = Symbol("gaga");
+
+var objects = [
+  {},
+  [],
+  function() {},
+  function() {
+    return arguments;
+  }(),
+  function() {
+    'use strict';
+    return arguments;
+  }(),
+  Object(1),
+  Object(true),
+  Object('bla'),
+  new Date,
+  new RegExp,
+  new Set,
+  new Map,
+  new WeakMap,
+  new WeakSet,
+  new ArrayBuffer(10),
+  new Int32Array(5),
+  Object,
+  Function,
+  Date,
+  RegExp,
+  global
+];
+
+function prepare(target) {
+  target["bla"] = true;
+  target[4] = 42;
+  target[sym] = "foo";
+  target["noconf"] = 43;
+  Object.defineProperty(target, "noconf",
+      { configurable: false });
+  Object.defineProperty(target, "nowrite",
+      { writable: false, configurable: true, value: 44 });
+  Object.defineProperty(target, "getter",
+      { get: function () {return this.bla}, configurable: true });
+  Object.defineProperty(target, "setter",
+      { set: function (x) {this.gaga = x}, configurable: true });
+  Object.defineProperty(target, "setter2",
+      { set: function (x) {}, configurable: true });
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Reflect.get
+
+
+(function testReflectGetArity() {
+  assertEquals(2, Reflect.get.length);
+})();
+
+
+(function testReflectGetOnNonObject() {
+  assertThrows(function() { Reflect.get(); }, TypeError);
+  assertThrows(function() { Reflect.get(42, "bla"); }, TypeError);
+  assertThrows(function() { Reflect.get(null, "bla"); }, TypeError);
+})();
+
+
+(function testReflectGetKeyConversion() {
+  var target = {bla: 42};
+  var a = { [Symbol.toPrimitive]: function() { return "bla" } };
+  var b = { [Symbol.toPrimitive]: function() { throw "gaga" } };
+  assertEquals(42, Reflect.get(target, a));
+  assertThrowsEquals(function() { Reflect.get(target, b); }, "gaga");
+})();
+
+
+(function testReflectGetOnObject() {
+  var receiver = {bla: false};
+  for (let target of objects) {
+    prepare(target);
+    assertEquals(true, Reflect.get(target, "bla"));
+    assertEquals(true, Reflect.get(target, "bla", target));
+    assertEquals(true, Reflect.get(target, "bla", receiver));
+    assertEquals(42, Reflect.get(target, 4));
+    assertEquals(42, Reflect.get(target, 4, target));
+    assertEquals(42, Reflect.get(target, 4, receiver));
+    assertEquals(42, Reflect.get(target, "4"));
+    assertEquals(42, Reflect.get(target, "4", target));
+    assertEquals(42, Reflect.get(target, "4", receiver));
+    assertEquals("foo", Reflect.get(target, sym));
+    assertEquals("foo", Reflect.get(target, sym, target));
+    assertEquals("foo", Reflect.get(target, sym, receiver));
+    assertEquals(43, Reflect.get(target, "noconf"));
+    assertEquals(43, Reflect.get(target, "noconf", target));
+    assertEquals(43, Reflect.get(target, "noconf", receiver));
+    assertEquals(true, Reflect.get(target, "getter"));
+    assertEquals(true, Reflect.get(target, "getter", target));
+    assertEquals(false, Reflect.get(target, "getter", receiver));
+    assertEquals(undefined, Reflect.get(target, "setter"));
+    assertEquals(undefined, Reflect.get(target, "setter", target));
+    assertEquals(undefined, Reflect.get(target, "setter", receiver));
+    assertEquals(undefined, Reflect.get(target, "foo"));
+    assertEquals(undefined, Reflect.get(target, "foo", target));
+    assertEquals(undefined, Reflect.get(target, "foo", receiver));
+    assertEquals(undefined, Reflect.get(target, 666));
+    assertEquals(undefined, Reflect.get(target, 666, target));
+    assertEquals(undefined, Reflect.get(target, 666, receiver));
+
+    let proto = target.__proto__;
+    target.__proto__ = { get foo() {return this.bla} };
+    assertEquals(true, Reflect.get(target, "foo"));
+    assertEquals(true, Reflect.get(target, "foo", target));
+    assertEquals(false, Reflect.get(target, "foo", receiver));
+    target.__proto__ = proto;
+  }
+})();
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Reflect.set
+
+
+(function testReflectSetArity() {
+  assertEquals(3, Reflect.set.length);
+})();
+
+
+(function testReflectSetOnNonObject() {
+  assertThrows(function() { Reflect.set(); }, TypeError);
+  assertThrows(function() { Reflect.set(42, "bla"); }, TypeError);
+  assertThrows(function() { Reflect.set(null, "bla"); }, TypeError);
+})();
+
+
+(function testReflectSetKeyConversion() {
+  var target = {};
+  var a = { [Symbol.toPrimitive]: function() { return "bla" } };
+  var b = { [Symbol.toPrimitive]: function() { throw "gaga" } };
+  assertTrue(Reflect.set(target, a, 42));
+  assertEquals(42, target.bla);
+  assertThrowsEquals(function() { Reflect.set(target, b, 42); }, "gaga");
+})();
+
+
+(function testReflectSetOnObject() {
+  var receiver = {bla: false};
+  var value = 34234;
+  for (let target of objects) {
+    prepare(target);
+    assertTrue(Reflect.set(target, "bla", value));
+    assertEquals(value, target.bla);
+
+    prepare(target);
+    assertTrue(Reflect.set(target, "bla", value, target));
+    assertEquals(value, target.bla);
+
+    prepare(target);
+    assertTrue(Reflect.set(target, "bla", value, receiver));
+    assertEquals(true, target.bla);
+    assertEquals(value, receiver.bla);
+    receiver.bla = false;
+
+    prepare(target);
+    assertTrue(Reflect.set(target, 4, value));
+    assertEquals(value, target[4]);
+
+    prepare(target);
+    assertTrue(Reflect.set(target, 4, value, target));
+    assertEquals(value, target[4]);
+
+    prepare(target);
+    assertTrue(Reflect.set(target, 4, value, receiver));
+    assertEquals(42, target[4]);
+    assertEquals(value, receiver[4]);
+    delete receiver[4];
+
+    prepare(target);
+    assertTrue(Reflect.set(target, sym, value));
+    assertEquals(value, target[sym]);
+
+    prepare(target);
+    assertTrue(Reflect.set(target, sym, value, target));
+    assertEquals(value, target[sym]);
+
+    prepare(target);
+    assertTrue(Reflect.set(target, sym, value, receiver));
+    assertEquals("foo", target[sym]);
+    assertEquals(value, receiver[sym]);
+    delete receiver[sym];
+
+    prepare(target);
+    assertTrue(Reflect.set(target, "noconf", value));
+    assertEquals(value, target.noconf);
+
+    prepare(target);
+    assertTrue(Reflect.set(target, "noconf", value, target));
+    assertEquals(value, target.noconf);
+
+    prepare(target);
+    assertTrue(Reflect.set(target, "noconf", value, receiver));
+    assertEquals(43, target.noconf);
+    assertEquals(value, receiver.noconf);
+    delete receiver.noconf;
+
+    assertTrue(Reflect.set(target, "setter", value));
+    assertEquals(value, target.gaga)
+    delete target.gaga;
+
+    assertTrue(Reflect.set(target, "setter", value, target));
+    assertEquals(value, target.gaga)
+    delete target.gaga;
+
+    assertTrue(Reflect.set(target, "setter", value, receiver));
+    assertFalse("gaga" in target);
+    assertEquals(value, receiver.gaga);
+    delete receiver.gaga;
+
+    assertFalse(Reflect.set(target, "nowrite", value));
+    assertEquals(44, target.nowrite);
+
+    assertFalse(Reflect.set(target, "nowrite", value, target));
+    assertEquals(44, target.nowrite);
+
+    assertFalse(Reflect.set(target, "nowrite", value, receiver));
+    assertEquals(44, target.nowrite);
+    assertFalse("nowrite" in receiver);
+
+    // Data vs Non-Writable
+    assertFalse(Reflect.set({}, "nowrite", value, target));
+
+    // Data vs Accessor
+    assertFalse(Reflect.set({}, "unknown", 0, {set unknown(x) {}}));
+    assertFalse(Reflect.set(target, "unknown", value, {set unknown(x) {}}));
+    assertFalse(Reflect.set(target, "bla", value, {set bla(x) {}}));
+    assertFalse(Reflect.set(target, "bla", value, {get bla() {}}));
+
+    // Accessor vs Data
+    assertTrue(Reflect.set({set bla(x) {}}), "bla", value, target);
+    assertFalse(Reflect.set({get bla() {}}, "bla", value, target));
+
+    // Data vs Non-Object
+    assertFalse(Reflect.set({}, "bla", value, null));
+    assertFalse(Reflect.set({bla: 42}, "bla", value, null));
+
+    // Accessor vs Non-Object
+    assertTrue(Reflect.set(target, "setter2", value, null));
+    assertFalse(Reflect.set(target, "getter", value, null));
+
+    let receiver2 = {};
+    Object.defineProperty(receiver2, "bla",
+        {configurable: false, writable: true, value: true});
+    Object.defineProperty(receiver2, "not_in_target",
+        {configurable: false, writable: true, value: true});
+    assertTrue(Reflect.set(target, "bla", value, receiver2));
+    assertTrue(Reflect.set(target, "not_in_target", value, receiver2));
+  }
+})();
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Reflect.has
+
+
+(function testReflectHasArity() {
+  assertEquals(2, Reflect.has.length);
+})();
+
+
+(function testReflectHasOnNonObject() {
+  assertThrows(function() { Reflect.has(); }, TypeError);
+  assertThrows(function() { Reflect.has(42, "bla"); }, TypeError);
+  assertThrows(function() { Reflect.has(null, "bla"); }, TypeError);
+})();
+
+
+(function testReflectHasKeyConversion() {
+  var target = {bla: 42};
+  var a = { [Symbol.toPrimitive]: function() { return "bla" } };
+  var b = { [Symbol.toPrimitive]: function() { throw "gaga" } };
+  assertTrue(Reflect.has(target, a));
+  assertThrowsEquals(function() { Reflect.has(target, b); }, "gaga");
+})();
+
+
+(function testReflectHasOnObject() {
+  for (let target of objects) {
+    prepare(target);
+    assertTrue(Reflect.has(target, "bla"));
+    assertTrue(Reflect.has(target, 4));
+    assertTrue(Reflect.has(target, "4"));
+    assertTrue(Reflect.has(target, sym));
+    assertTrue(Reflect.has(target, "noconf"));
+    assertTrue(Reflect.has(target, "getter"));
+    assertTrue(Reflect.has(target, "setter"));
+    assertFalse(Reflect.has(target, "foo"));
+    assertFalse(Reflect.has(target, 666));
+
+    let proto = target.__proto__;
+    target.__proto__ = { get foo() {return this.bla} };
+    assertEquals(true, Reflect.has(target, "foo"));
+    target.__proto__ = proto;
+  }
+})();
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Reflect.defineProperty
+
+
+(function testReflectDefinePropertyArity() {
+  assertEquals(3, Reflect.defineProperty.length);
+})();
+
+
+(function testReflectDefinePropertyOnNonObject() {
+  assertThrows(function() { Reflect.defineProperty(); }, TypeError);
+  assertThrows(function() { Reflect.defineProperty(42, "bla"); }, TypeError);
+  assertThrows(function() { Reflect.defineProperty(null, "bla"); }, TypeError);
+  assertThrows(function() { Reflect.defineProperty({}, "bla"); }, TypeError);
+  assertThrows(function() { Reflect.defineProperty({}, "bla", 42); },
+      TypeError);
+  assertThrows(function() { Reflect.defineProperty({}, "bla", null); },
+      TypeError);
+})();
+
+
+(function testReflectDefinePropertyKeyConversion() {
+  var target = {};
+  var a = { [Symbol.toPrimitive]: function() { return "bla" } };
+  var b = { [Symbol.toPrimitive]: function() { throw "gaga" } };
+  assertTrue(Reflect.defineProperty(target, a, {value: 42}));
+  assertEquals(target.bla, 42);
+  assertThrowsEquals(function() { Reflect.defineProperty(target, b); }, "gaga");
+})();
+
+
+// See reflect-define-property.js for further tests.
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Reflect.deleteProperty
+
+
+(function testReflectDeletePropertyArity() {
+  assertEquals(2, Reflect.deleteProperty.length);
+})();
+
+
+(function testReflectDeletePropertyOnNonObject() {
+  assertThrows(function() { Reflect.deleteProperty(); }, TypeError);
+  assertThrows(function() { Reflect.deleteProperty(42, "bla"); }, TypeError);
+  assertThrows(function() { Reflect.deleteProperty(null, "bla"); }, TypeError);
+})();
+
+
+(function testReflectDeletePropertyKeyConversion() {
+  var target = {bla: 42};
+  var a = { [Symbol.toPrimitive]: function() { return "bla" } };
+  var b = { [Symbol.toPrimitive]: function() { throw "gaga" } };
+  assertTrue(Reflect.deleteProperty(target, a));
+  assertThrowsEquals(function() { Reflect.deleteProperty(target, b); }, "gaga");
+})();
+
+
+(function testReflectDeletePropertyOnObject() {
+  for (let target of objects) {
+    prepare(target);
+    assertTrue(Reflect.deleteProperty(target, "bla"));
+    assertEquals(undefined, Object.getOwnPropertyDescriptor(target, "bla"));
+    if (target instanceof Int32Array) {
+      assertFalse(Reflect.deleteProperty(target, 4));
+    } else {
+      assertTrue(Reflect.deleteProperty(target, 4));
+      assertEquals(undefined, Object.getOwnPropertyDescriptor(target, 4));
+    }
+    assertTrue(Reflect.deleteProperty(target, sym));
+    assertEquals(undefined, Object.getOwnPropertyDescriptor(target, sym));
+    assertFalse(Reflect.deleteProperty(target, "noconf"));
+    assertEquals(43, target.noconf);
+    assertTrue(Reflect.deleteProperty(target, "getter"));
+    assertTrue(Reflect.deleteProperty(target, "setter"));
+    assertTrue(Reflect.deleteProperty(target, "foo"));
+    assertTrue(Reflect.deleteProperty(target, 666));
+
+    let proto = target.__proto__;
+    target.__proto__ = { get foo() {return this.bla} };
+    assertEquals(true, Reflect.deleteProperty(target, "foo"));
+    target.__proto__ = proto;
+  }
+})();
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Reflect.getPrototypeOf
+
+
+(function testReflectGetPrototypeOfArity() {
+  assertEquals(1, Reflect.getPrototypeOf.length);
+})();
+
+
+(function testReflectGetPrototypeOnNonObject() {
+  assertThrows(function() { Reflect.getPrototypeOf(); }, TypeError);
+  assertThrows(function() { Reflect.getPrototypeOf(42); }, TypeError);
+  assertThrows(function() { Reflect.getPrototypeOf(null); }, TypeError);
+})();
+
+
+// See reflect-get-prototype-of.js for further tests.
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Reflect.setPrototypeOf
+
+
+(function testReflectSetPrototypeOfArity() {
+  assertEquals(2, Reflect.setPrototypeOf.length);
+})();
+
+
+(function testReflectSetPrototypeOfOnNonObject() {
+  assertThrows(function() { Reflect.setPrototypeOf(undefined, {}); },
+      TypeError);
+  assertThrows(function() { Reflect.setPrototypeOf(42, {}); }, TypeError);
+  assertThrows(function() { Reflect.setPrototypeOf(null, {}); }, TypeError);
+
+  assertThrows(function() { Reflect.setPrototypeOf({}, undefined); },
+      TypeError);
+  assertThrows(function() { Reflect.setPrototypeOf({}, 42); }, TypeError);
+  assertTrue(Reflect.setPrototypeOf({}, null));
+})();
+
+
+// See reflect-set-prototype-of.js for further tests.
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Reflect.isExtensible
+
+
+(function testReflectIsExtensibleArity() {
+  assertEquals(1, Reflect.isExtensible.length);
+})();
+
+
+(function testReflectIsExtensibleOnNonObject() {
+  assertThrows(function() { Reflect.isExtensible(); }, TypeError);
+  assertThrows(function() { Reflect.isExtensible(42); }, TypeError);
+  assertThrows(function() { Reflect.isExtensible(null); }, TypeError);
+})();
+
+
+(function testReflectIsExtensibleOnObject() {
+  // This should be the last test on [objects] as it modifies them irreversibly.
+  for (let target of objects) {
+    prepare(target);
+    if (target instanceof Int32Array) continue;  // issue v8:4460
+    assertTrue(Reflect.isExtensible(target));
+    Object.preventExtensions(target);
+    assertFalse(Reflect.isExtensible(target));
+  }
+})();
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Reflect.getOwnPropertyDescriptor
+
+
+(function testReflectGetOwnPropertyDescriptorArity() {
+  assertEquals(2, Reflect.getOwnPropertyDescriptor.length);
+})();
+
+
+(function testReflectGetOwnPropertyDescriptorOnNonObject() {
+  assertThrows(function() { Reflect.getOwnPropertyDescriptor(); }, TypeError);
+  assertThrows(function() { Reflect.getOwnPropertyDescriptor(42); },
+      TypeError);
+  assertThrows(function() { Reflect.getOwnPropertyDescriptor(null); },
+      TypeError);
+})();
+
+
+(function testReflectGetOwnPropertyDescriptorKeyConversion() {
+  var target = {bla: 42};
+  var a = { [Symbol.toPrimitive]: function() { return "bla" } };
+  var b = { [Symbol.toPrimitive]: function() { throw "gaga" } };
+  assertEquals(42, Reflect.getOwnPropertyDescriptor(target, a).value);
+  assertThrowsEquals(() => Reflect.getOwnPropertyDescriptor(target, b), "gaga");
+})();
+
+
+// See reflect-get-own-property-descriptor.js for further tests.
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Reflect.ownKeys
+
+
+(function testReflectOwnKeysArity() {
+  assertEquals(1, Reflect.ownKeys.length);
+})();
+
+
+(function testReflectOwnKeysOnNonObject() {
+  assertThrows(function() { Reflect.ownKeys(); }, TypeError);
+  assertThrows(function() { Reflect.ownKeys(42); }, TypeError);
+  assertThrows(function() { Reflect.ownKeys(null); }, TypeError);
+})();
+
+
+(function testReflectOwnKeysOnObject(){
+  assertEquals(["z", "y", "x"], Reflect.ownKeys({z: 3, y: 2, x: 1}));
+  assertEquals(["length"], Reflect.ownKeys([]));
+
+  var s1 = Symbol("foo");
+  var s2 = Symbol("bar");
+  var obj = { [s1]: 0, "bla": 0, 42: 0, "0": 0,
+      [s2]: 0, "-1": 0, "88": 0, "aaa": 0 };
+  assertEquals(["0", "42", "88", "bla", "-1", "aaa", s1, s2],
+      Reflect.ownKeys(obj));
+})();
+
+
+// See reflect-own-keys.js for further tests.
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Reflect.preventExtensions
+
+
+(function testReflectPreventExtensionsArity() {
+  assertEquals(1, Reflect.preventExtensions.length);
+})();
+
+
+(function testReflectPreventExtensionsOnNonObject() {
+  assertThrows(function() { Reflect.preventExtensions(); }, TypeError);
+  assertThrows(function() { Reflect.preventExtensions(42); }, TypeError);
+  assertThrows(function() { Reflect.preventExtensions(null); }, TypeError);
+})();
+
+
+// See reflect-prevent-extensions.js for further tests.
+
+// TODO(neis): Need proxies to test the situation where
+// [[preventExtensions]] returns false.
diff --git a/test/mjsunit/es6/regexp-constructor.js b/test/mjsunit/es6/regexp-constructor.js
index e3b7efa..559ac00 100644
--- a/test/mjsunit/es6/regexp-constructor.js
+++ b/test/mjsunit/es6/regexp-constructor.js
@@ -21,32 +21,47 @@
 })();
 
 (function() {
+  let allow = false;
   class A extends RegExp {
-    get source() { throw new Error("should not be called") }
-    get flags() { throw new Error("should not be called") }
+    get source() {
+      if (!allow) throw new Error("should not be called");
+      return super.source;
+    }
+    get flags() {
+      if (!allow) throw new Error("should not be called");
+      return super.flags
+    }
   }
 
   var r = new A("biep");
   var r2 = RegExp(r);
 
   assertFalse(r === r2);
+  allow = true;
   assertEquals(r, r2);
+  allow = false;
   assertTrue(A.prototype === r.__proto__);
   assertTrue(RegExp.prototype === r2.__proto__);
 
   var r3 = RegExp(r);
   assertFalse(r3 === r);
+  allow = true;
   assertEquals(r3, r);
+  allow = false;
 
   var r4 = new A(r2);
   assertFalse(r4 === r2);
+  allow = true;
   assertEquals(r4, r2);
+  allow = false;
   assertTrue(A.prototype === r4.__proto__);
 
   r[Symbol.match] = false;
   var r5 = new A(r);
   assertFalse(r5 === r);
+  allow = true;
   assertEquals(r5, r);
+  allow = false;
   assertTrue(A.prototype === r5.__proto__);
 })();
 
diff --git a/test/mjsunit/es6/regexp-flags.js b/test/mjsunit/es6/regexp-flags.js
index 79b0197..480222d 100644
--- a/test/mjsunit/es6/regexp-flags.js
+++ b/test/mjsunit/es6/regexp-flags.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: --harmony-regexps --harmony-unicode-regexps
+// Flags: --harmony-unicode-regexps
 
 var r1 = /abc/gi;
 assertEquals("abc", r1.source);
@@ -44,15 +44,18 @@
 // Overridden flag getters affects the flags getter.
 assertEquals("gi", r3.flags);
 assertEquals(4, get_count);
-// Overridden flag getters do not affect the internal flags.
+// Overridden flag getters affect string.replace
+// TODO(adamk): Add more tests here once we've switched
+// to use [[OriginalFlags]] in more cases.
 assertEquals(expected, string.replace(r3, "X"));
-assertEquals(4, get_count);
+assertEquals(5, get_count);
 
 
 function testName(name) {
-  // TODO(littledan): For web compatibility, we don't throw an exception,
-  // but ES2015 expects an exception to be thrown from this getter.
-  assertEquals(undefined, RegExp.prototype[name]);
+  // Test for ES2017 RegExp web compatibility semantics
+  // https://github.com/tc39/ecma262/pull/511
+  assertEquals(name === "source" ? "(?:)" : undefined,
+               RegExp.prototype[name]);
   assertEquals(
       "get " + name,
       Object.getOwnPropertyDescriptor(RegExp.prototype, name).get.name);
@@ -64,3 +67,55 @@
 testName("source");
 testName("sticky");
 testName("unicode");
+
+
+RegExp.prototype.flags = 'setter should be undefined';
+
+assertEquals('', RegExp('').flags);
+assertEquals('', /./.flags);
+assertEquals('gimuy', RegExp('', 'yugmi').flags);
+assertEquals('gimuy', /foo/yumig.flags);
+
+var descriptor = Object.getOwnPropertyDescriptor(RegExp.prototype, 'flags');
+assertTrue(descriptor.configurable);
+assertFalse(descriptor.enumerable);
+assertInstanceof(descriptor.get, Function);
+assertEquals(undefined, descriptor.set);
+
+function testGenericFlags(object) {
+  return descriptor.get.call(object);
+}
+
+assertEquals('', testGenericFlags({}));
+assertEquals('i', testGenericFlags({ ignoreCase: true }));
+assertEquals('uy', testGenericFlags({ global: 0, sticky: 1, unicode: 1 }));
+assertEquals('m', testGenericFlags({ __proto__: { multiline: true } }));
+assertThrows(function() { testGenericFlags(); }, TypeError);
+assertThrows(function() { testGenericFlags(undefined); }, TypeError);
+assertThrows(function() { testGenericFlags(null); }, TypeError);
+assertThrows(function() { testGenericFlags(true); }, TypeError);
+assertThrows(function() { testGenericFlags(false); }, TypeError);
+assertThrows(function() { testGenericFlags(''); }, TypeError);
+assertThrows(function() { testGenericFlags(42); }, TypeError);
+
+var counter = 0;
+var map = {};
+var object = {
+  get global() {
+    map.g = counter++;
+  },
+  get ignoreCase() {
+    map.i = counter++;
+  },
+  get multiline() {
+    map.m = counter++;
+  },
+  get unicode() {
+    map.u = counter++;
+  },
+  get sticky() {
+    map.y = counter++;
+  }
+};
+testGenericFlags(object);
+assertEquals({ g: 0, i: 1, m: 2, u: 3, y: 4 }, map);
diff --git a/test/mjsunit/es6/regexp-sticky.js b/test/mjsunit/es6/regexp-sticky.js
new file mode 100644
index 0000000..c0633f9
--- /dev/null
+++ b/test/mjsunit/es6/regexp-sticky.js
@@ -0,0 +1,130 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var re = /foo.bar/;
+
+assertTrue(!!"foo*bar".match(re));
+assertTrue(!!"..foo*bar".match(re));
+
+var plain = /foobar/;
+
+assertTrue(!!"foobar".match(plain));
+assertTrue(!!"..foobar".match(plain));
+
+var sticky = /foo.bar/y;
+
+assertTrue(!!"foo*bar".match(sticky));
+assertEquals(7, sticky.lastIndex);
+assertFalse(!!"..foo*bar".match(sticky));
+
+var stickyplain = /foobar/y;
+
+assertTrue(!!"foobar".match(stickyplain));
+assertEquals(6, stickyplain.lastIndex);
+assertFalse(!!"..foobar".match(stickyplain));
+
+var global = /foo.bar/g;
+
+assertTrue(global.test("foo*bar"));
+assertFalse(global.test("..foo*bar"));
+global.lastIndex = 0;
+assertTrue(global.test("..foo*bar"));
+
+var plainglobal = /foobar/g;
+
+assertTrue(plainglobal.test("foobar"));
+assertFalse(plainglobal.test("foobar"));
+plainglobal.lastIndex = 0;
+assertTrue(plainglobal.test("foobar"));
+
+var stickyglobal = /foo.bar/gy;
+
+assertTrue(stickyglobal.test("foo*bar"));
+assertEquals(7, stickyglobal.lastIndex);
+assertFalse(stickyglobal.test("..foo*bar"));
+stickyglobal.lastIndex = 0;
+assertFalse(stickyglobal.test("..foo*bar"));
+stickyglobal.lastIndex = 2;
+assertTrue(stickyglobal.test("..foo*bar"));
+assertEquals(9, stickyglobal.lastIndex);
+
+var stickyplainglobal = /foobar/yg;
+assertTrue(stickyplainglobal.sticky);
+stickyplainglobal.sticky = false;
+
+assertTrue(stickyplainglobal.test("foobar"));
+assertEquals(6, stickyplainglobal.lastIndex);
+assertFalse(stickyplainglobal.test("..foobar"));
+stickyplainglobal.lastIndex = 0;
+assertFalse(stickyplainglobal.test("..foobar"));
+stickyplainglobal.lastIndex = 2;
+assertTrue(stickyplainglobal.test("..foobar"));
+assertEquals(8, stickyplainglobal.lastIndex);
+
+assertEquals("/foo.bar/gy", "" + stickyglobal);
+assertEquals("/foo.bar/g", "" + global);
+
+assertTrue(stickyglobal.sticky);
+stickyglobal.sticky = false;
+assertTrue(stickyglobal.sticky);
+
+var stickyglobal2 = new RegExp("foo.bar", "gy");
+assertTrue(stickyglobal2.test("foo*bar"));
+assertEquals(7, stickyglobal2.lastIndex);
+assertFalse(stickyglobal2.test("..foo*bar"));
+stickyglobal2.lastIndex = 0;
+assertFalse(stickyglobal2.test("..foo*bar"));
+stickyglobal2.lastIndex = 2;
+assertTrue(stickyglobal2.test("..foo*bar"));
+assertEquals(9, stickyglobal2.lastIndex);
+
+assertEquals("/foo.bar/gy", "" + stickyglobal2);
+
+assertTrue(stickyglobal2.sticky);
+stickyglobal2.sticky = false;
+assertTrue(stickyglobal2.sticky);
+
+sticky.lastIndex = -1; // Causes sticky regexp to fail fast
+assertFalse(sticky.test("..foo.bar"));
+assertEquals(0, sticky.lastIndex);
+
+sticky.lastIndex = -1; // Causes sticky regexp to fail fast
+assertFalse(!!sticky.exec("..foo.bar"));
+assertEquals(0, sticky.lastIndex);
+
+// ES6 draft says: Even when the y flag is used with a pattern, ^ always
+// matches only at the beginning of Input, or (if Multiline is true) at the
+// beginning of a line.
+var hat = /^foo/y;
+hat.lastIndex = 2;
+assertFalse(hat.test("..foo"));
+
+var mhat = /^foo/my;
+mhat.lastIndex = 2;
+assertFalse(mhat.test("..foo"));
+mhat.lastIndex = 2;
+assertTrue(mhat.test(".\nfoo"));
diff --git a/test/mjsunit/es6/regexp-tostring.js b/test/mjsunit/es6/regexp-tostring.js
index 3deeeb7..23e137c 100644
--- a/test/mjsunit/es6/regexp-tostring.js
+++ b/test/mjsunit/es6/regexp-tostring.js
@@ -44,3 +44,14 @@
 
 assertEquals("/pattern/flags", RegExp.prototype.toString.call(fake));
 assertEquals(["p", "ps", "f", "fs"], log);
+
+// Monkey-patching is also possible on RegExp instances
+
+let weird = /foo/;
+Object.defineProperty(weird, 'flags', {value: 'bar'});
+Object.defineProperty(weird, 'source', {value: 'baz'});
+assertEquals('/baz/bar', weird.toString());
+
+assertEquals('/(?:)/', RegExp.prototype.toString());
+assertEquals('(?:)', RegExp.prototype.source);
+assertEquals('', RegExp.prototype.flags);
diff --git a/test/mjsunit/es6/regress/regress-2219.js b/test/mjsunit/es6/regress/regress-2219.js
new file mode 100644
index 0000000..79f5bfb
--- /dev/null
+++ b/test/mjsunit/es6/regress/regress-2219.js
@@ -0,0 +1,32 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-gc
+
+var p = new Proxy({}, {getOwnPropertyDescriptor: function() { gc() }});
+var o = Object.create(p);
+assertSame(23, o.x = 23);
diff --git a/test/mjsunit/es6/regress/regress-2225.js b/test/mjsunit/es6/regress/regress-2225.js
new file mode 100644
index 0000000..cb5cd8c
--- /dev/null
+++ b/test/mjsunit/es6/regress/regress-2225.js
@@ -0,0 +1,74 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var proxy_has_x = false;
+var proxy = new Proxy({}, {
+  get(t, key, receiver) {
+    assertSame('x', key);
+    if (proxy_has_x) { return 19 }
+    return 8;
+  }
+});
+
+// Test __lookupGetter__/__lookupSetter__ with proxy.
+assertSame(undefined, Object.prototype.__lookupGetter__.call(proxy, 'foo'));
+assertSame(undefined, Object.prototype.__lookupSetter__.call(proxy, 'bar'));
+assertSame(undefined, Object.prototype.__lookupGetter__.call(proxy, '123'));
+assertSame(undefined, Object.prototype.__lookupSetter__.call(proxy, '456'));
+
+// Test __lookupGetter__/__lookupSetter__ with proxy in prototype chain.
+var object = Object.create(proxy);
+assertSame(undefined, Object.prototype.__lookupGetter__.call(object, 'foo'));
+assertSame(undefined, Object.prototype.__lookupSetter__.call(object, 'bar'));
+assertSame(undefined, Object.prototype.__lookupGetter__.call(object, '123'));
+assertSame(undefined, Object.prototype.__lookupSetter__.call(object, '456'));
+
+// Test inline constructors with proxy as prototype.
+function F() { this.x = 42 }
+F.prototype = proxy;
+var instance = new F();
+
+proxy_has_x = false;
+assertSame(42, instance.x);
+delete instance.x;
+assertSame(8, instance.x);
+
+proxy_has_x = true;
+assertSame(19, instance.x);
+
+// Test inline constructors with proxy in prototype chain.
+function G() { this.x = 42; }
+G.prototype.__proto__ = proxy;
+instance = new G();
+
+proxy_has_x = false;
+assertSame(42, instance.x);
+delete instance.x;
+assertSame(8, instance.x);
+
+proxy_has_x = true;
+assertSame(19, instance.x);
diff --git a/test/mjsunit/es6/regress/regress-4395-global-eval.js b/test/mjsunit/es6/regress/regress-4395-global-eval.js
new file mode 100644
index 0000000..72a0ece
--- /dev/null
+++ b/test/mjsunit/es6/regress/regress-4395-global-eval.js
@@ -0,0 +1,6 @@
+// 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.
+
+((x, y = eval('x')) => assertEquals(42, y))(42);
+((x, {y = eval('x')}) => assertEquals(42, y))(42, {});
diff --git a/test/mjsunit/es6/regress/regress-4395.js b/test/mjsunit/es6/regress/regress-4395.js
new file mode 100644
index 0000000..bdf8443
--- /dev/null
+++ b/test/mjsunit/es6/regress/regress-4395.js
@@ -0,0 +1,102 @@
+// 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 testExpressionTypes() {
+  "use strict";
+  ((x, y = x) => assertEquals(42, y))(42);
+
+  ((x, y = (x)) => assertEquals(42, y))(42);
+  ((x, y = `${x}`) => assertEquals("42", y))(42);
+  ((x, y = x = x + 1) => assertEquals(43, y))(42);
+  ((x, y = x()) => assertEquals(42, y))(() => 42);
+  ((x, y = new x()) => assertEquals(42, y.z))(function() { this.z = 42 });
+  ((x, y = -x) => assertEquals(-42, y))(42);
+  ((x, y = ++x) => assertEquals(43, y))(42);
+  ((x, y = x === 42) => assertTrue(y))(42);
+  ((x, y = (x == 42 ? x : 0)) => assertEquals(42, y))(42);
+
+  ((x, y = function() { return x }) => assertEquals(42, y()))(42);
+  ((x, y = () => x) => assertEquals(42, y()))(42);
+
+  // Literals
+  ((x, y = {z: x}) => assertEquals(42, y.z))(42);
+  ((x, y = {[x]: x}) => assertEquals(42, y[42]))(42);
+  ((x, y = [x]) => assertEquals(42, y[0]))(42);
+  ((x, y = [...x]) => assertEquals(42, y[0]))([42]);
+
+  ((x, y = class {
+    static [x]() { return x }
+  }) => assertEquals(42, y[42]()))(42);
+  ((x, y = (new class {
+    z() { return x }
+  })) => assertEquals(42, y.z()))(42);
+
+  ((x, y = (new class Y {
+    static [x]() { return x }
+    z() { return Y[42]() }
+  })) => assertEquals(42, y.z()))(42);
+
+  ((x, y = (new class {
+    constructor() { this.z = x }
+  })) => assertEquals(42, y.z))(42);
+  ((x, y = (new class Y {
+    constructor() { this.z = x }
+  })) => assertEquals(42, y.z))(42);
+
+  ((x, y = (new class extends x {
+  })) => assertEquals(42, y.z()))(class { z() { return 42 } });
+
+  // Defaults inside destructuring
+  ((x, {y = x}) => assertEquals(42, y))(42, {});
+  ((x, [y = x]) => assertEquals(42, y))(42, []);
+})();
+
+
+(function testMultiScopeCapture() {
+  "use strict";
+  var x = 1;
+  {
+    let y = 2;
+    ((x, y, a = x, b = y) => {
+      assertEquals(3, x);
+      assertEquals(3, a);
+      assertEquals(4, y);
+      assertEquals(4, b);
+    })(3, 4);
+  }
+})();
+
+
+(function testSuper() {
+  "use strict";
+  class A {
+    x() { return 42; }
+  }
+
+  class B extends A {
+    y() {
+      ((q = super.x()) => assertEquals(42, q))();
+    }
+  }
+
+  new B().y();
+
+  class C {
+    constructor() { return { prop: 42 } }
+  }
+
+  class D extends C{
+    constructor() {
+      ((q = super()) => assertEquals(42, q.prop))();
+    }
+  }
+
+  new D();
+})();
+
+
+(function testScopeFlags() {
+  ((x, y = eval('x')) => assertEquals(42, y))(42);
+  ((x, {y = eval('x')}) => assertEquals(42, y))(42, {});
+})();
diff --git a/test/mjsunit/es6/regress/regress-4400.js b/test/mjsunit/es6/regress/regress-4400.js
new file mode 100644
index 0000000..98ad269
--- /dev/null
+++ b/test/mjsunit/es6/regress/regress-4400.js
@@ -0,0 +1,8 @@
+// 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: --min-preparse-length=0
+
+function borked(a = [], b = {}, c) {}
+borked();
diff --git a/test/mjsunit/es6/regress/regress-4585.js b/test/mjsunit/es6/regress/regress-4585.js
new file mode 100644
index 0000000..8ded646
--- /dev/null
+++ b/test/mjsunit/es6/regress/regress-4585.js
@@ -0,0 +1,14 @@
+// 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.
+
+assertThrows(`for(const { method() {} } = this) {}`, SyntaxError);
+assertThrows(`var { method() {} } = this;`, SyntaxError);
+assertThrows(`for(const { *method() {} } = this) {}`, SyntaxError);
+assertThrows(`var { *method() {} } = this;`, SyntaxError);
+assertThrows(`for(var { get foo() {} } = this) {}`, SyntaxError);
+assertThrows(`for(var { set foo() {} } = this) {}`, SyntaxError);
+
+// Still OK in other objects
+for (var { name = "" + { toString() { return "test" } } } in { a: 1}) break;
+assertEquals(name, "test");
diff --git a/test/mjsunit/es6/regress/regress-4759.js b/test/mjsunit/es6/regress/regress-4759.js
new file mode 100644
index 0000000..5f8ee68
--- /dev/null
+++ b/test/mjsunit/es6/regress/regress-4759.js
@@ -0,0 +1,23 @@
+// 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 iterable(done) {
+  return {
+    [Symbol.iterator]: function() {
+      return {
+        next: function() {
+          if (done) return { done: true };
+          done = true;
+          return { value: 42, done: false };
+        }
+      }
+    }
+  }
+}
+
+var [...result] = iterable(true);
+assertEquals([], result);
+
+var [...result] = iterable(false);
+assertEquals([42], result);
diff --git a/test/mjsunit/es6/regress/regress-517455.js b/test/mjsunit/es6/regress/regress-517455.js
new file mode 100644
index 0000000..9c1dfd7
--- /dev/null
+++ b/test/mjsunit/es6/regress/regress-517455.js
@@ -0,0 +1,6 @@
+// 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 f({x = ""}) { eval(x) }
+f({})
diff --git a/test/mjsunit/es6/regress/regress-576662.js b/test/mjsunit/es6/regress/regress-576662.js
new file mode 100644
index 0000000..ad582d6
--- /dev/null
+++ b/test/mjsunit/es6/regress/regress-576662.js
@@ -0,0 +1,9 @@
+// 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.
+
+// https://code.google.com/p/chromium/issues/detail?id=576662 (simplified)
+
+Realm.create();
+this.__proto__ = new Proxy({},{});
+assertThrows(() => Realm.eval(1, "Realm.global(0).bla = 1"));
diff --git a/test/mjsunit/es6/regress/regress-cr493566.js b/test/mjsunit/es6/regress/regress-cr493566.js
index 2b0b7ea..7fbbd7d 100644
--- a/test/mjsunit/es6/regress/regress-cr493566.js
+++ b/test/mjsunit/es6/regress/regress-cr493566.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-proxies --harmony-reflect
-
 "use strict";
 var global = this;
 
diff --git a/test/mjsunit/es6/regress/regress-cr512574.js b/test/mjsunit/es6/regress/regress-cr512574.js
index 8d843ee..2bff763 100644
--- a/test/mjsunit/es6/regress/regress-cr512574.js
+++ b/test/mjsunit/es6/regress/regress-cr512574.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-destructuring-bind
-
 function f({}) {
   for (var v in []);
 };
diff --git a/test/mjsunit/es6/regress/regress-crbug-448730.js b/test/mjsunit/es6/regress/regress-crbug-448730.js
new file mode 100644
index 0000000..a3c70ac
--- /dev/null
+++ b/test/mjsunit/es6/regress/regress-crbug-448730.js
@@ -0,0 +1,14 @@
+// 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
+
+function bar() {}
+bar({ a: new Proxy({}, {}) });
+function foo(x) { x.a.b == ""; }
+var x = {a: {b: "" }};
+foo(x);
+foo(x);
+%OptimizeFunctionOnNextCall(foo);
+foo(x);
diff --git a/test/mjsunit/es6/regress/regress-crbug-461520.js b/test/mjsunit/es6/regress/regress-crbug-461520.js
new file mode 100644
index 0000000..d12ec53
--- /dev/null
+++ b/test/mjsunit/es6/regress/regress-crbug-461520.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 fuse = 1;
+
+var handler = {
+  get: function() { return function() {} },
+  has() { return true },
+  getOwnPropertyDescriptor: function() {
+    if (fuse-- == 0) throw "please die";
+    return {value: function() {}, configurable: true};
+  }
+};
+
+var p = new Proxy({}, handler);
+var o = Object.create(p);
+with (o) { f() }
diff --git a/test/mjsunit/es6/regress/regress-lookup-transition.js b/test/mjsunit/es6/regress/regress-lookup-transition.js
new file mode 100644
index 0000000..c6da9bd
--- /dev/null
+++ b/test/mjsunit/es6/regress/regress-lookup-transition.js
@@ -0,0 +1,14 @@
+// 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-gc
+
+var proxy = new Proxy({}, { getOwnPropertyDescriptor:function() {
+  gc();
+}});
+
+function f() { this.x = 23; }
+f.prototype = proxy;
+new f();
+new f();
diff --git a/test/mjsunit/es6/string-endswith.js b/test/mjsunit/es6/string-endswith.js
index cbf2ed8..4246f16 100644
--- a/test/mjsunit/es6/string-endswith.js
+++ b/test/mjsunit/es6/string-endswith.js
@@ -408,3 +408,11 @@
     "toString": function() { return "abc"; }
   }, [/./]);
 }, TypeError);
+
+// endsWith does its brand checks with Symbol.match
+var re = /./;
+assertThrows(function() {
+  "".startsWith(re);
+}, TypeError);
+re[Symbol.match] = false;
+assertEquals(false, "".startsWith(re));
diff --git a/test/mjsunit/es6/string-includes.js b/test/mjsunit/es6/string-includes.js
index 61bf779..c825ffd 100644
--- a/test/mjsunit/es6/string-includes.js
+++ b/test/mjsunit/es6/string-includes.js
@@ -162,3 +162,11 @@
   "throw RangeError(); } }, [/./])", RangeError);
 assertThrows("String.prototype.includes.apply({ 'toString': function() { " +
   "return 'abc'; } }, [/./])", TypeError);
+
+// includes does its brand checks with Symbol.match
+var re = /./;
+assertThrows(function() {
+  "".includes(re);
+}, TypeError);
+re[Symbol.match] = false;
+assertEquals(false, "".includes(re));
diff --git a/test/mjsunit/es6/string-iterator.js b/test/mjsunit/es6/string-iterator.js
index 769f549..8eb27b1 100644
--- a/test/mjsunit/es6/string-iterator.js
+++ b/test/mjsunit/es6/string-iterator.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-tostring
-
 function TestStringPrototypeIterator() {
   assertTrue(String.prototype.hasOwnProperty(Symbol.iterator));
   assertFalse("".hasOwnProperty(Symbol.iterator));
diff --git a/test/mjsunit/es6/string-startswith.js b/test/mjsunit/es6/string-startswith.js
index 887db99..f38f7b9 100644
--- a/test/mjsunit/es6/string-startswith.js
+++ b/test/mjsunit/es6/string-startswith.js
@@ -399,3 +399,11 @@
     "toString": function() { return "abc"; }
   }, [/./]);
 }, TypeError);
+
+// startsWith does its brand checks with Symbol.match
+var re = /./;
+assertThrows(function() {
+  "".startsWith(re);
+}, TypeError);
+re[Symbol.match] = false;
+assertEquals(false, "".startsWith(re));
diff --git a/test/mjsunit/es6/super.js b/test/mjsunit/es6/super.js
index 67cb45f..a2ba1e8 100644
--- a/test/mjsunit/es6/super.js
+++ b/test/mjsunit/es6/super.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // Flags: --allow-natives-syntax
-// Flags: --harmony-destructuring-bind --harmony-sloppy
+// Flags: --harmony-sloppy
 
 (function TestSuperNamedLoads() {
   function Base() { }
diff --git a/test/mjsunit/es6/symbols.js b/test/mjsunit/es6/symbols.js
index 3833857..9bac41f 100644
--- a/test/mjsunit/es6/symbols.js
+++ b/test/mjsunit/es6/symbols.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 --allow-natives-syntax --harmony-tostring
+// Flags: --expose-gc --allow-natives-syntax
 
 var symbols = []
 
@@ -86,6 +86,7 @@
 
 
 function TestConstructor() {
+  assertEquals(0, Symbol.length);
   assertSame(Function.prototype, Symbol.__proto__)
   assertFalse(Object === Symbol.prototype.constructor)
   assertFalse(Symbol === Object.prototype.constructor)
diff --git a/test/mjsunit/es6/tail-call-megatest-shard0.js b/test/mjsunit/es6/tail-call-megatest-shard0.js
new file mode 100644
index 0000000..87fe29e
--- /dev/null
+++ b/test/mjsunit/es6/tail-call-megatest-shard0.js
@@ -0,0 +1,13 @@
+// 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 --harmony-tailcalls
+
+try {
+  load("mjsunit/es6/tail-call-megatest.js");
+} catch(e) {
+  load("test/mjsunit/es6/tail-call-megatest.js");
+}
+
+run_tests(0);
diff --git a/test/mjsunit/es6/tail-call-megatest-shard1.js b/test/mjsunit/es6/tail-call-megatest-shard1.js
new file mode 100644
index 0000000..10deb28
--- /dev/null
+++ b/test/mjsunit/es6/tail-call-megatest-shard1.js
@@ -0,0 +1,13 @@
+// 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 --harmony-tailcalls
+
+try {
+  load("mjsunit/es6/tail-call-megatest.js");
+} catch(e) {
+  load("test/mjsunit/es6/tail-call-megatest.js");
+}
+
+run_tests(1);
diff --git a/test/mjsunit/es6/tail-call-megatest-shard2.js b/test/mjsunit/es6/tail-call-megatest-shard2.js
new file mode 100644
index 0000000..7d2bd97
--- /dev/null
+++ b/test/mjsunit/es6/tail-call-megatest-shard2.js
@@ -0,0 +1,13 @@
+// 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 --harmony-tailcalls
+
+try {
+  load("mjsunit/es6/tail-call-megatest.js");
+} catch(e) {
+  load("test/mjsunit/es6/tail-call-megatest.js");
+}
+
+run_tests(2);
diff --git a/test/mjsunit/es6/tail-call-megatest-shard3.js b/test/mjsunit/es6/tail-call-megatest-shard3.js
new file mode 100644
index 0000000..7bce6c4
--- /dev/null
+++ b/test/mjsunit/es6/tail-call-megatest-shard3.js
@@ -0,0 +1,13 @@
+// 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 --harmony-tailcalls
+
+try {
+  load("mjsunit/es6/tail-call-megatest.js");
+} catch(e) {
+  load("test/mjsunit/es6/tail-call-megatest.js");
+}
+
+run_tests(3);
diff --git a/test/mjsunit/es6/tail-call-megatest-shard4.js b/test/mjsunit/es6/tail-call-megatest-shard4.js
new file mode 100644
index 0000000..6c43d3e
--- /dev/null
+++ b/test/mjsunit/es6/tail-call-megatest-shard4.js
@@ -0,0 +1,13 @@
+// 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 --harmony-tailcalls
+
+try {
+  load("mjsunit/es6/tail-call-megatest.js");
+} catch(e) {
+  load("test/mjsunit/es6/tail-call-megatest.js");
+}
+
+run_tests(4);
diff --git a/test/mjsunit/es6/tail-call-megatest-shard5.js b/test/mjsunit/es6/tail-call-megatest-shard5.js
new file mode 100644
index 0000000..a91bd3f
--- /dev/null
+++ b/test/mjsunit/es6/tail-call-megatest-shard5.js
@@ -0,0 +1,13 @@
+// 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 --harmony-tailcalls
+
+try {
+  load("mjsunit/es6/tail-call-megatest.js");
+} catch(e) {
+  load("test/mjsunit/es6/tail-call-megatest.js");
+}
+
+run_tests(5);
diff --git a/test/mjsunit/es6/tail-call-megatest-shard6.js b/test/mjsunit/es6/tail-call-megatest-shard6.js
new file mode 100644
index 0000000..0d70a42
--- /dev/null
+++ b/test/mjsunit/es6/tail-call-megatest-shard6.js
@@ -0,0 +1,13 @@
+// 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 --harmony-tailcalls
+
+try {
+  load("mjsunit/es6/tail-call-megatest.js");
+} catch(e) {
+  load("test/mjsunit/es6/tail-call-megatest.js");
+}
+
+run_tests(6);
diff --git a/test/mjsunit/es6/tail-call-megatest-shard7.js b/test/mjsunit/es6/tail-call-megatest-shard7.js
new file mode 100644
index 0000000..63477af
--- /dev/null
+++ b/test/mjsunit/es6/tail-call-megatest-shard7.js
@@ -0,0 +1,13 @@
+// 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 --harmony-tailcalls
+
+try {
+  load("mjsunit/es6/tail-call-megatest.js");
+} catch(e) {
+  load("test/mjsunit/es6/tail-call-megatest.js");
+}
+
+run_tests(7);
diff --git a/test/mjsunit/es6/tail-call-megatest-shard8.js b/test/mjsunit/es6/tail-call-megatest-shard8.js
new file mode 100644
index 0000000..0c68827
--- /dev/null
+++ b/test/mjsunit/es6/tail-call-megatest-shard8.js
@@ -0,0 +1,13 @@
+// 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 --harmony-tailcalls
+
+try {
+  load("mjsunit/es6/tail-call-megatest.js");
+} catch(e) {
+  load("test/mjsunit/es6/tail-call-megatest.js");
+}
+
+run_tests(8);
diff --git a/test/mjsunit/es6/tail-call-megatest-shard9.js b/test/mjsunit/es6/tail-call-megatest-shard9.js
new file mode 100644
index 0000000..82f991a
--- /dev/null
+++ b/test/mjsunit/es6/tail-call-megatest-shard9.js
@@ -0,0 +1,13 @@
+// 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 --harmony-tailcalls
+
+try {
+  load("mjsunit/es6/tail-call-megatest.js");
+} catch(e) {
+  load("test/mjsunit/es6/tail-call-megatest.js");
+}
+
+run_tests(9);
diff --git a/test/mjsunit/es6/tail-call-megatest.js b/test/mjsunit/es6/tail-call-megatest.js
index 0057961..1de8ec6 100644
--- a/test/mjsunit/es6/tail-call-megatest.js
+++ b/test/mjsunit/es6/tail-call-megatest.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: --allow-natives-syntax --harmony-tailcalls --no-turbo-inlining
+// Flags: --allow-natives-syntax --harmony-tailcalls
 
 
 Error.prepareStackTrace = (error,stack) => {
@@ -11,23 +11,15 @@
 }
 
 
-function CheckStackTrace(expected) {
+function checkStackTrace(expected) {
   var e = new Error();
   e.stack;  // prepare stack trace
   var stack = e.strace;
-  assertEquals("CheckStackTrace", stack[0].getFunctionName());
+  assertEquals("checkStackTrace", stack[0].getFunctionName());
   for (var i = 0; i < expected.length; i++) {
     assertEquals(expected[i].name, stack[i + 1].getFunctionName());
   }
 }
-%NeverOptimizeFunction(CheckStackTrace);
-
-
-function CheckArguments(expected, args) {
-  args = Array.prototype.slice.call(args);
-  assertEquals(expected, args);
-}
-%NeverOptimizeFunction(CheckArguments);
 
 
 var CAN_INLINE_COMMENT  = "// Let it be inlined.";
@@ -45,28 +37,59 @@
   return ident + source.replace(/\n/gi, "\n" + ident);
 }
 
-var global = Function('return this')();
-var the_receiver = {receiver: 1};
+var SHARDS_COUNT = 10;
 
-function run_tests() {
+function run_tests(shard) {
   function inlinable_comment(inlinable) {
     return inlinable ? CAN_INLINE_COMMENT : DONT_INLINE_COMMENT;
   }
 
+  // Check arguments manually to avoid bailing out with reason "bad value
+  // context for arguments value".
+  function check_arguments_template(expected_name) {
+    var lines = [
+      `  assertEquals_(${expected_name}.length, arguments.length);`,
+      `  for (var i = 0; i < ${expected_name}.length; i++) {`,
+      `    assertEquals_(${expected_name}[i], arguments[i]);`,
+      `  }`,
+    ];
+    return lines.join("\n");
+  }
+  var check_arguments = check_arguments_template("expected_args");
+
+  function deopt_template(deopt_mode) {
+    switch(deopt_mode) {
+      case "none":
+        return "  // Don't deoptimize";
+      case "f":
+      case "g":
+      case "test":
+        return `  %DeoptimizeFunction(${deopt_mode});`;
+      default:
+        assertUnreachable();
+    }
+  }
+
   var f_cfg_sloppy = {
     func_name: 'f',
     source_template: function(cfg) {
       var receiver = cfg.f_receiver != undefined ? cfg.f_receiver
                                                  : "global";
+      var do_checks = [
+        `  assertEquals_(${receiver}, this);`,
+        `  ${!cfg.check_new_target ? "// " : ""}assertEquals_(undefined, new.target);`,
+        check_arguments,
+        `  checkStackTrace_([f, test]);`,
+      ].join("\n");
+
       var lines = [
         `function f(a) {`,
         `  ${inlinable_comment(cfg.f_inlinable)}`,
-        `  assertEquals(${receiver}, this);`,
-        `  CheckArguments([${cfg.f_args}], arguments);`,
-        `  CheckStackTrace([f, test]);`,
-        `  %DeoptimizeNow();`,
-        `  CheckArguments([${cfg.f_args}], arguments);`,
-        `  CheckStackTrace([f, test]);`,
+        `  counter++;`,
+        `  var expected_args = [${cfg.f_args}];`,
+        do_checks,
+        deopt_template(cfg.deopt_mode),
+        do_checks,
         `  return 42;`,
         `}`,
       ];
@@ -79,16 +102,22 @@
     source_template: function(cfg) {
       var receiver = cfg.f_receiver != undefined ? cfg.f_receiver
                                                  : "undefined";
+      var do_checks = [
+        `  assertEquals_(${receiver}, this);`,
+        `  ${!cfg.check_new_target ? "// " : ""}assertEquals_(undefined, new.target);`,
+        check_arguments,
+        `  checkStackTrace_([f, test]);`,
+      ].join("\n");
+
       var lines = [
         `function f(a) {`,
         `  "use strict";`,
         `  ${inlinable_comment(cfg.f_inlinable)}`,
-        `  assertEquals(${receiver}, this);`,
-        `  CheckArguments([${cfg.f_args}], arguments);`,
-        `  CheckStackTrace([f, test]);`,
-        `  %DeoptimizeNow();`,
-        `  CheckArguments([${cfg.f_args}], arguments);`,
-        `  CheckStackTrace([f, test]);`,
+        `  counter++;`,
+        `  var expected_args = [${cfg.f_args}];`,
+        do_checks,
+        deopt_template(cfg.deopt_mode),
+        do_checks,
         `  return 42;`,
         `}`,
       ];
@@ -101,15 +130,21 @@
     source_template: function(cfg) {
       var receiver = cfg.f_receiver != undefined ? cfg.f_receiver
                                                  : "global";
+      var do_checks = [
+        `  assertEquals_(${receiver}, this);`,
+        `  ${!cfg.check_new_target ? "// " : ""}assertEquals_(undefined, new.target);`,
+        check_arguments,
+        `  checkStackTrace_([f, test]);`,
+      ].join("\n");
+
       var lines = [
         `function f(a) {`,
         `  ${inlinable_comment(cfg.f_inlinable)}`,
-        `  assertEquals(${receiver}, this);`,
-        `  CheckArguments([${cfg.f_args}], arguments);`,
-        `  CheckStackTrace([f, test]);`,
-        `  %DeoptimizeNow();`,
-        `  CheckArguments([${cfg.f_args}], arguments);`,
-        `  CheckStackTrace([f, test]);`,
+        `  counter++;`,
+        `  var expected_args = [${cfg.f_args}];`,
+        do_checks,
+        deopt_template(cfg.deopt_mode),
+        do_checks,
         `  return 42;`,
         `}`,
         `var eval = f;`,
@@ -121,16 +156,22 @@
   var f_cfg_bound = {
     func_name: 'bound',
     source_template: function(cfg) {
+      var do_checks = [
+        `  assertEquals_(receiver, this);`,
+        `  ${!cfg.check_new_target ? "// " : ""}assertEquals_(undefined, new.target);`,
+        check_arguments,
+        `  checkStackTrace_([f, test]);`,
+      ].join("\n");
+
       var lines = [
         `function f(a) {`,
         `  "use strict";`,
         `  ${inlinable_comment(cfg.f_inlinable)}`,
-        `  assertEquals(receiver, this);`,
-        `  CheckArguments([${cfg.f_args}], arguments);`,
-        `  CheckStackTrace([f, test]);`,
-        `  %DeoptimizeNow();`,
-        `  CheckArguments([${cfg.f_args}], arguments);`,
-        `  CheckStackTrace([f, test]);`,
+        `  counter++;`,
+        `  var expected_args = [${cfg.f_args}];`,
+        do_checks,
+        deopt_template(cfg.deopt_mode),
+        do_checks,
         `  return 42;`,
         `}`,
         `var receiver = {a: 153};`,
@@ -145,15 +186,21 @@
     source_template: function(cfg) {
       var receiver = cfg.f_receiver != undefined ? cfg.f_receiver
                                                  : "global";
+      var do_checks = [
+        `  assertEquals_(${receiver}, this);`,
+        `  ${!cfg.check_new_target ? "// " : ""}assertEquals_(undefined, new.target);`,
+        check_arguments,
+        `  checkStackTrace_([f, test]);`,
+      ].join("\n");
+
       var lines = [
         `function f(a) {`,
         `  ${inlinable_comment(cfg.f_inlinable)}`,
-        `  assertEquals(${receiver}, this);`,
-        `  CheckArguments([${cfg.f_args}], arguments);`,
-        `  CheckStackTrace([f, test]);`,
-        `  %DeoptimizeNow();`,
-        `  CheckArguments([${cfg.f_args}], arguments);`,
-        `  CheckStackTrace([f, test]);`,
+        `  counter++;`,
+        `  var expected_args = [${cfg.f_args}];`,
+        do_checks,
+        deopt_template(cfg.deopt_mode),
+        do_checks,
         `  return 42;`,
         `}`,
         `var p = new Proxy(f, {});`,
@@ -169,7 +216,8 @@
         `function g(a) {`,
         `  "use strict";`,
         `  ${inlinable_comment(cfg.g_inlinable)}`,
-        `  CheckArguments([${cfg.g_args}], arguments);`,
+        `  var expected_args = [${cfg.g_args}];`,
+        check_arguments,
         `  return ${cfg.f_name}(${cfg.f_args});`,
         `}`,
       ];
@@ -178,6 +226,23 @@
   };
 
 
+  var g_cfg_reflect_apply = {
+    receiver: "the_receiver",
+    source_template: function(cfg) {
+      var lines = [
+        `function g(a) {`,
+        `  "use strict";`,
+        `  ${inlinable_comment(cfg.g_inlinable)}`,
+        `  var expected_args = [${cfg.g_args}];`,
+        check_arguments,
+        `  return Reflect.apply(${cfg.f_name}, the_receiver, [${cfg.f_args}]);`,
+        `}`,
+      ];
+      return lines.join("\n");
+    },
+  };
+
+
   var g_cfg_function_apply = {
     receiver: "the_receiver",
     source_template: function(cfg) {
@@ -185,7 +250,8 @@
         `function g(a) {`,
         `  "use strict";`,
         `  ${inlinable_comment(cfg.g_inlinable)}`,
-        `  CheckArguments([${cfg.g_args}], arguments);`,
+        `  var expected_args = [${cfg.g_args}];`,
+        check_arguments,
         `  return ${cfg.f_name}.apply(the_receiver, [${cfg.f_args}]);`,
         `}`,
       ];
@@ -194,6 +260,24 @@
   };
 
 
+  var g_cfg_function_apply_arguments_object = {
+    receiver: "the_receiver",
+    source_template: function(cfg) {
+      cfg.f_args = cfg.g_args;
+      var lines = [
+        `function g(a) {`,
+        `  "use strict";`,
+        `  ${inlinable_comment(cfg.g_inlinable)}`,
+        `  var expected_args = [${cfg.g_args}];`,
+        check_arguments,
+        `  return ${cfg.f_name}.apply(the_receiver, arguments);`,
+        `}`,
+      ];
+      return lines.join("\n");
+    },
+  };
+
+
   var g_cfg_function_call = {
     receiver: "the_receiver",
     source_template: function(cfg) {
@@ -205,7 +289,8 @@
         `function g(a) {`,
         `  "use strict";`,
         `  ${inlinable_comment(cfg.g_inlinable)}`,
-        `  CheckArguments([${cfg.g_args}], arguments);`,
+        `  var expected_args = [${cfg.g_args}];`,
+        check_arguments,
         `  return ${cfg.f_name}.call(${f_args});`,
         `}`,
       ];
@@ -215,27 +300,39 @@
 
 
   function test_template(cfg) {
-    var f_source = cfg.f_source_template(cfg);
+    // Note: g_source_template modifies cfg.f_args in some cases.
     var g_source = cfg.g_source_template(cfg);
-    f_source = ident_source(f_source, 2);
     g_source = ident_source(g_source, 2);
 
+    var f_source = cfg.f_source_template(cfg);
+    f_source = ident_source(f_source, 2);
+
     var lines = [
       `(function() {`,
+      `  // Avoid bailing out because of "Reference to a variable which requires dynamic lookup".`,
+      `  var assertEquals_ = assertEquals;`,
+      `  var checkStackTrace_ = checkStackTrace;`,
+      `  var undefined = void 0;`,
+      `  var global = Function('return this')();`,
+      `  var the_receiver = {receiver: 1};`,
+      `  var counter = 0;`,
+      ``,
+      `  // Don't inline helper functions`,
+      `  %NeverOptimizeFunction(assertEquals);`,
+      `  %NeverOptimizeFunction(checkStackTrace);`,
+      ``,
       f_source,
       g_source,
       `  function test() {`,
       `    "use strict";`,
-      `    assertEquals(42, g(${cfg.g_args}));`,
+      `    assertEquals_(42, g(${cfg.g_args}));`,
       `  }`,
-      `  ${cfg.f_inlinable ? "%SetForceInlineFlag(f)" : ""};`,
-      `  ${cfg.g_inlinable ? "%SetForceInlineFlag(g)" : ""};`,
-      ``,
-      `  test();`,
+      `  ${"test();".repeat(cfg.test_warmup_count)}`,
+      `  ${cfg.f_inlinable ? "%SetForceInlineFlag(f)" : "%OptimizeFunctionOnNextCall(f)"};`,
+      `  ${cfg.g_inlinable ? "%SetForceInlineFlag(g)" : "%OptimizeFunctionOnNextCall(g)"};`,
       `  %OptimizeFunctionOnNextCall(test);`,
-      `  %OptimizeFunctionOnNextCall(f);`,
-      `  %OptimizeFunctionOnNextCall(g);`,
       `  test();`,
+      `  assertEquals(${1 + cfg.test_warmup_count}, counter);`,
       `})();`,
       ``,
     ];
@@ -243,11 +340,13 @@
     return source;
   }
 
-  // TODO(v8:4698), TODO(ishell): support all commented cases.
   var f_args_variants = ["", "1", "1, 2"];
-  var g_args_variants = [/*"",*/ "10", /*"10, 20"*/];
-  var f_inlinable_variants = [/*true,*/ false];
+  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 deopt_mode_variants = ["none", "f", "g", "test"];
   var f_variants = [
       f_cfg_sloppy,
       f_cfg_strict,
@@ -257,36 +356,60 @@
   ];
   var g_variants = [
       g_cfg_normal,
-      g_cfg_function_call,
+      g_cfg_reflect_apply,
       g_cfg_function_apply,
+      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) {
+    print("Running shard #" + shard);
+  }
   f_variants.forEach((f_cfg) => {
-    g_variants.forEach((g_cfg) => {
-      f_args_variants.forEach((f_args) => {
-        g_args_variants.forEach((g_args) => {
-          f_inlinable_variants.forEach((f_inlinable) => {
-            g_inlinable_variants.forEach((g_inlinable) => {
-              var cfg = {
-                f_source_template: f_cfg.source_template,
-                f_inlinable,
-                f_args,
-                f_name: f_cfg.func_name,
-                f_receiver: g_cfg.receiver,
-                g_source_template: g_cfg.source_template,
-                g_inlinable,
-                g_args,
-              };
-              var source = test_template(cfg);
-              print("====================");
-              print(source);
-              eval(source);
+    check_new_target_variants.forEach((check_new_target) => {
+      deopt_mode_variants.forEach((deopt_mode) => {
+        g_variants.forEach((g_cfg) => {
+          f_args_variants.forEach((f_args) => {
+            g_args_variants.forEach((g_args) => {
+              f_inlinable_variants.forEach((f_inlinable) => {
+                g_inlinable_variants.forEach((g_inlinable) => {
+                  test_warmup_counts.forEach((test_warmup_count) => {
+                    if (shard !== undefined && (iter++) % SHARDS_COUNT != shard) {
+                      print("skipping...");
+                      return;
+                    }
+                    tests_executed++;
+                    var cfg = {
+                      f_source_template: f_cfg.source_template,
+                      f_inlinable,
+                      f_args,
+                      f_name: f_cfg.func_name,
+                      f_receiver: g_cfg.receiver,
+                      g_source_template: g_cfg.source_template,
+                      g_inlinable,
+                      g_args,
+                      test_warmup_count,
+                      check_new_target,
+                      deopt_mode,
+                    };
+                    var source = test_template(cfg);
+                    print("====================");
+                    print(source);
+                    eval(source);
+                  });
+                });
+              });
             });
           });
         });
       });
     });
   });
+  print("Number of tests executed: " + tests_executed);
 }
 
-run_tests();
+// Uncomment to run all the tests at once or use shard runners.
+//run_tests();
diff --git a/test/mjsunit/es6/tail-call-proxies.js b/test/mjsunit/es6/tail-call-proxies.js
index 25f9fcf..251ac0c 100644
--- a/test/mjsunit/es6/tail-call-proxies.js
+++ b/test/mjsunit/es6/tail-call-proxies.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: --allow-natives-syntax --harmony-tailcalls --harmony-proxies
+// Flags: --allow-natives-syntax --harmony-tailcalls
 "use strict";
 
 Error.prepareStackTrace = (e,s) => s;
diff --git a/test/mjsunit/es6/tail-call-simple.js b/test/mjsunit/es6/tail-call-simple.js
index d2890b0..cc63808 100644
--- a/test/mjsunit/es6/tail-call-simple.js
+++ b/test/mjsunit/es6/tail-call-simple.js
@@ -10,7 +10,7 @@
 (function() {
   function f(n) {
     if (n <= 0) {
-      return  "foo";
+      return "foo";
     }
     return f(n - 1);
   }
@@ -27,7 +27,7 @@
   "use strict";
   function f(n) {
     if (n <= 0) {
-      return  "foo";
+      return "foo";
     }
     return f(n - 1);
   }
@@ -39,6 +39,20 @@
 
 (function() {
   "use strict";
+  function f(n) {
+    if (n <= 0) {
+      return  "foo";
+    }
+    return f(n - 1, 42);  // Call with arguments adaptor.
+  }
+  assertEquals("foo", f(1e5));
+  %OptimizeFunctionOnNextCall(f);
+  assertEquals("foo", f(1e5));
+})();
+
+
+(function() {
+  "use strict";
   function f(n){
     if (n <= 0) {
       return "foo";
@@ -59,6 +73,28 @@
 })();
 
 
+(function() {
+  "use strict";
+  function f(n){
+    if (n <= 0) {
+      return "foo";
+    }
+    return g(n - 1, 42);  // Call with arguments adaptor.
+  }
+  function g(n){
+    if (n <= 0) {
+      return "bar";
+    }
+    return f(n - 1, 42);  // Call with arguments adaptor.
+  }
+  assertEquals("foo", f(1e5));
+  assertEquals("bar", f(1e5 + 1));
+  %OptimizeFunctionOnNextCall(f);
+  assertEquals("foo", f(1e5));
+  assertEquals("bar", f(1e5 + 1));
+})();
+
+
 //
 // Tail call bound functions.
 //
diff --git a/test/mjsunit/es6/tail-call.js b/test/mjsunit/es6/tail-call.js
index e9539c3..d0d00f4 100644
--- a/test/mjsunit/es6/tail-call.js
+++ b/test/mjsunit/es6/tail-call.js
@@ -20,6 +20,8 @@
     assertEquals(expected[i].name, stack[i + 1].getFunctionName());
   }
 }
+%NeverOptimizeFunction(CheckStackTrace);
+
 
 function f(expected_call_stack, a, b) {
   CheckStackTrace(expected_call_stack);
@@ -69,6 +71,7 @@
     assertEquals(12, g4(1));
   }
   test();
+  test();
   %OptimizeFunctionOnNextCall(test);
   test();
 })();
@@ -111,6 +114,7 @@
     assertEquals(12, g4());
   }
   test();
+  test();
   %OptimizeFunctionOnNextCall(test);
   test();
 })();
@@ -162,6 +166,7 @@
     assertEquals(12, g4(1));
   }
   test();
+  test();
   %OptimizeFunctionOnNextCall(test);
   test();
 })();
@@ -212,6 +217,89 @@
     assertEquals(12, g4());
   }
   test();
+  test();
+  %OptimizeFunctionOnNextCall(test);
+  test();
+})();
+
+
+// Tail calling from getter.
+(function() {
+  function g(v) {
+    CheckStackTrace([g, test]);
+    %DeoptimizeFunction(test);
+    return 153;
+  }
+  %NeverOptimizeFunction(g);
+
+  function f(v) {
+    return g();
+  }
+  %SetForceInlineFlag(f);
+
+  function test() {
+    var o = {};
+    o.__defineGetter__('p', f);
+    assertEquals(153, o.p);
+  }
+
+  test();
+  test();
+  %OptimizeFunctionOnNextCall(test);
+  test();
+})();
+
+
+// Tail calling from setter.
+(function() {
+  function g() {
+    CheckStackTrace([g, test]);
+    %DeoptimizeFunction(test);
+    return 153;
+  }
+  %NeverOptimizeFunction(g);
+
+  var context = 10;
+  function f(v) {
+    return g(context);
+  }
+  %SetForceInlineFlag(f);
+
+  function test() {
+    var o = {};
+    o.__defineSetter__('q', f);
+    assertEquals(1, o.q = 1);
+  }
+
+  test();
+  test();
+  %OptimizeFunctionOnNextCall(test);
+  test();
+})();
+
+
+// Tail calling from constructor.
+(function() {
+  function g(context) {
+    CheckStackTrace([g, test]);
+    %DeoptimizeFunction(test);
+    return {x: 153};
+  }
+  %NeverOptimizeFunction(g);
+
+  function A() {
+    this.x = 42;
+    return g();
+  }
+
+  function test() {
+    var o = new A();
+    %DebugPrint(o);
+    assertEquals(153, o.x);
+  }
+
+  test();
+  test();
   %OptimizeFunctionOnNextCall(test);
   test();
 })();
@@ -237,6 +325,53 @@
     assertEquals(153, g3());
   }
   test();
+  test();
+  %OptimizeFunctionOnNextCall(test);
+  test();
+})();
+
+
+// Tail calling from various statements.
+(function() {
+  function g1() {
+    for (var v in {a:0}) {
+      return f_153([f_153, g1, test]);
+    }
+  }
+
+  function g2() {
+    for (var v of [1, 2, 3]) {
+      return f_153([f_153, g2, test]);
+    }
+  }
+
+  function g3() {
+    for (var i = 0; i < 10; i++) {
+      return f_153([f_153, test]);
+    }
+  }
+
+  function g4() {
+    while (true) {
+      return f_153([f_153, test]);
+    }
+  }
+
+  function g5() {
+    do {
+      return f_153([f_153, test]);
+    } while (true);
+  }
+
+  function test() {
+    assertEquals(153, g1());
+    assertEquals(153, g2());
+    assertEquals(153, g3());
+    assertEquals(153, g4());
+    assertEquals(153, g5());
+  }
+  test();
+  test();
   %OptimizeFunctionOnNextCall(test);
   test();
 })();
@@ -280,6 +415,7 @@
     assertEquals(153, tc3());
   }
   test();
+  test();
   %OptimizeFunctionOnNextCall(test);
   test();
 })();
@@ -321,6 +457,7 @@
     assertEquals(153, tf3());
   }
   test();
+  test();
   %OptimizeFunctionOnNextCall(test);
   test();
 })();
@@ -381,6 +518,28 @@
     assertEquals(153, tcf4());
   }
   test();
+  test();
+  %OptimizeFunctionOnNextCall(test);
+  test();
+})();
+
+
+// Test tail calls from arrow functions.
+(function () {
+  function g1(a) {
+    return (() => { return f_153([f_153, test]); })();
+  }
+
+  function g2(a) {
+    return (() => f_153([f_153, test]))();
+  }
+
+  function test() {
+    assertEquals(153, g1());
+    assertEquals(153, g2());
+  }
+  test();
+  test();
   %OptimizeFunctionOnNextCall(test);
   test();
 })();
diff --git a/test/mjsunit/es6/typed-array-iterator.js b/test/mjsunit/es6/typed-array-iterator.js
index 0b27625..7970bba 100644
--- a/test/mjsunit/es6/typed-array-iterator.js
+++ b/test/mjsunit/es6/typed-array-iterator.js
@@ -21,10 +21,10 @@
 assertFalse(TypedArrayPrototype.propertyIsEnumerable('keys'));
 assertFalse(TypedArrayPrototype.propertyIsEnumerable(Symbol.iterator));
 
-assertEquals(Array.prototype.entries, TypedArrayPrototype.entries);
-assertEquals(Array.prototype[Symbol.iterator], TypedArrayPrototype.values);
-assertEquals(Array.prototype.keys, TypedArrayPrototype.keys);
-assertEquals(Array.prototype[Symbol.iterator], TypedArrayPrototype[Symbol.iterator]);
+assertFalse(Array.prototype.entries === TypedArrayPrototype.entries);
+assertFalse(Array.prototype[Symbol.iterator] === TypedArrayPrototype.values);
+assertFalse(Array.prototype.keys === TypedArrayPrototype.keys);
+assertFalse(Array.prototype[Symbol.iterator] === TypedArrayPrototype[Symbol.iterator]);
 
 
 function TestTypedArrayValues(constructor) {
diff --git a/test/mjsunit/es6/typedarray-of.js b/test/mjsunit/es6/typedarray-of.js
index a6df29a..eaa7bde 100644
--- a/test/mjsunit/es6/typedarray-of.js
+++ b/test/mjsunit/es6/typedarray-of.js
@@ -115,9 +115,9 @@
   // Check superficial features of %TypedArray%.of.
   var desc = Object.getOwnPropertyDescriptor(constructor.__proto__, "of");
 
-  assertEquals(desc.configurable, false);
+  assertEquals(desc.configurable, true);
   assertEquals(desc.enumerable, false);
-  assertEquals(desc.writable, false);
+  assertEquals(desc.writable, true);
   assertEquals(constructor.of.length, 0);
 
   // %TypedArray%.of is not a constructor.
diff --git a/test/mjsunit/es6/typedarray-proto.js b/test/mjsunit/es6/typedarray-proto.js
index 346b2ea..0bd90d1 100644
--- a/test/mjsunit/es6/typedarray-proto.js
+++ b/test/mjsunit/es6/typedarray-proto.js
@@ -28,17 +28,13 @@
 let classProperties = new Set([
   "length", "name", "arguments", "caller", "prototype", "BYTES_PER_ELEMENT"
 ]);
-let instanceProperties = new Set([
-  "BYTES_PER_ELEMENT", "constructor", "prototype",
-  // length is also an instance property as a temporary workaround to
-  // BUG(chromium:579905). TODO(littledan): remove the workaround
-  "length"
-]);
+let instanceProperties = new Set(["BYTES_PER_ELEMENT", "constructor", "prototype"]);
 
 function functionProperties(object) {
   return Object.getOwnPropertyNames(object).filter(function(name) {
     return typeof Object.getOwnPropertyDescriptor(object, name).value
-        == "function" && name != 'constructor';
+        == "function"
+      && name != 'constructor' && name != 'subarray';
   });
 }
 
diff --git a/test/mjsunit/es6/typedarray.js b/test/mjsunit/es6/typedarray.js
index e6a949c..4bdf822 100644
--- a/test/mjsunit/es6/typedarray.js
+++ b/test/mjsunit/es6/typedarray.js
@@ -25,8 +25,6 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Flags: --harmony-tostring
-
 // ArrayBuffer
 
 function TestByteLength(param, expectedByteLength) {