Merge V8 at 3.7.12.28

Bug: 5688872

Change-Id: Iddb40cae44d51a2b449f2858951e0472771f5981
diff --git a/src/proxy.js b/src/proxy.js
index 4e44cd4..3cd467f 100644
--- a/src/proxy.js
+++ b/src/proxy.js
@@ -32,7 +32,10 @@
 $Proxy.create = function(handler, proto) {
   if (!IS_SPEC_OBJECT(handler))
     throw MakeTypeError("handler_non_object", ["create"])
-  if (!IS_SPEC_OBJECT(proto)) proto = null  // Mozilla does this...
+  if (IS_UNDEFINED(proto))
+    proto = null
+  else if (!(IS_SPEC_OBJECT(proto) || proto === null))
+    throw MakeTypeError("proto_non_object", ["create"])
   return %CreateJSProxy(handler, proto)
 }
 
@@ -42,8 +45,14 @@
   if (!IS_SPEC_FUNCTION(callTrap))
     throw MakeTypeError("trap_function_expected", ["createFunction", "call"])
   if (IS_UNDEFINED(constructTrap)) {
-    constructTrap = callTrap
-  } else if (!IS_SPEC_FUNCTION(constructTrap)) {
+    constructTrap = DerivedConstructTrap(callTrap)
+  } else if (IS_SPEC_FUNCTION(constructTrap)) {
+    // Make sure the trap receives 'undefined' as this.
+    var construct = constructTrap
+    constructTrap = function() {
+      return %Apply(construct, void 0, arguments, 0, %_ArgumentsLength());
+    }
+  } else {
     throw MakeTypeError("trap_function_expected",
                         ["createFunction", "construct"])
   }
@@ -57,6 +66,17 @@
 // Builtins
 ////////////////////////////////////////////////////////////////////////////////
 
+function DerivedConstructTrap(callTrap) {
+  return function() {
+    var proto = this.prototype
+    if (!IS_SPEC_OBJECT(proto)) proto = $Object.prototype
+    var obj = new $Object()
+    obj.__proto__ = proto
+    var result = %Apply(callTrap, obj, arguments, 0, %_ArgumentsLength());
+    return IS_SPEC_OBJECT(result) ? result : obj
+  }
+}
+
 function DelegateCallAndConstruct(callTrap, constructTrap) {
   return function() {
     return %Apply(%_IsConstructCall() ? constructTrap : callTrap,
@@ -136,9 +156,32 @@
   var enumerableNames = []
   for (var i = 0, count = 0; i < names.length; ++i) {
     var name = names[i]
-    if (this.getOwnPropertyDescriptor(TO_STRING_INLINE(name)).enumerable) {
+    var desc = this.getOwnPropertyDescriptor(TO_STRING_INLINE(name))
+    if (!IS_UNDEFINED(desc) && desc.enumerable) {
       enumerableNames[count++] = names[i]
     }
   }
   return enumerableNames
 }
+
+function DerivedEnumerateTrap() {
+  var names = this.getPropertyNames()
+  var enumerableNames = []
+  for (var i = 0, count = 0; i < names.length; ++i) {
+    var name = names[i]
+    var desc = this.getPropertyDescriptor(TO_STRING_INLINE(name))
+    if (!IS_UNDEFINED(desc) && desc.enumerable) {
+      enumerableNames[count++] = names[i]
+    }
+  }
+  return enumerableNames
+}
+
+function ProxyEnumerate(proxy) {
+  var handler = %GetHandler(proxy)
+  if (IS_UNDEFINED(handler.enumerate)) {
+    return %Apply(DerivedEnumerateTrap, handler, [], 0, 0)
+  } else {
+    return ToStringArray(handler.enumerate(), "enumerate")
+  }
+}