Reland "Use C++ implementation of Object.definePropert{y,ies}"

This reverts commit 581ead5c8ceeb0e4ee2049d78972418236f5d3ba.

Review URL: https://codereview.chromium.org/1413123004

Cr-Commit-Position: refs/heads/master@{#31473}
diff --git a/src/js/v8natives.js b/src/js/v8natives.js
index 7c2ea48..3c1e175 100644
--- a/src/js/v8natives.js
+++ b/src/js/v8natives.js
@@ -1038,42 +1038,47 @@
 
 // ES5 section 15.2.3.6.
 function ObjectDefineProperty(obj, p, attributes) {
-  if (!IS_SPEC_OBJECT(obj)) {
-    throw MakeTypeError(kCalledOnNonObject, "Object.defineProperty");
-  }
-  var name = TO_NAME(p);
-  if (%_IsJSProxy(obj)) {
-    // Clone the attributes object for protection.
-    // TODO(rossberg): not spec'ed yet, so not sure if this should involve
-    // non-own properties as it does (or non-enumerable ones, as it doesn't?).
-    var attributesClone = { __proto__: null };
-    for (var a in attributes) {
-      attributesClone[a] = attributes[a];
+  // The new pure-C++ implementation doesn't support Proxies yet, nor O.o.
+  // TODO(jkummerow): Implement missing features and remove fallback path.
+  if (%_IsJSProxy(obj) || %IsObserved(obj)) {
+    if (!IS_SPEC_OBJECT(obj)) {
+      throw MakeTypeError(kCalledOnNonObject, "Object.defineProperty");
     }
-    DefineProxyProperty(obj, name, attributesClone, true);
-    // The following would implement the spec as in the current proposal,
-    // but after recent comments on es-discuss, is most likely obsolete.
-    /*
-    var defineObj = FromGenericPropertyDescriptor(desc);
-    var names = ObjectGetOwnPropertyNames(attributes);
-    var standardNames =
-      {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
-    for (var i = 0; i < names.length; i++) {
-      var N = names[i];
-      if (!(%HasOwnProperty(standardNames, N))) {
-        var attr = GetOwnPropertyJS(attributes, N);
-        DefineOwnProperty(descObj, N, attr, true);
+    var name = TO_NAME(p);
+    if (%_IsJSProxy(obj)) {
+      // Clone the attributes object for protection.
+      // TODO(rossberg): not spec'ed yet, so not sure if this should involve
+      // non-own properties as it does (or non-enumerable ones, as it doesn't?).
+      var attributesClone = { __proto__: null };
+      for (var a in attributes) {
+        attributesClone[a] = attributes[a];
       }
+      DefineProxyProperty(obj, name, attributesClone, true);
+      // The following would implement the spec as in the current proposal,
+      // but after recent comments on es-discuss, is most likely obsolete.
+      /*
+      var defineObj = FromGenericPropertyDescriptor(desc);
+      var names = ObjectGetOwnPropertyNames(attributes);
+      var standardNames =
+        {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
+      for (var i = 0; i < names.length; i++) {
+        var N = names[i];
+        if (!(%HasOwnProperty(standardNames, N))) {
+          var attr = GetOwnPropertyJS(attributes, N);
+          DefineOwnProperty(descObj, N, attr, true);
+        }
+      }
+      // This is really confusing the types, but it is what the proxies spec
+      // currently requires:
+      desc = descObj;
+      */
+    } else {
+      var desc = ToPropertyDescriptor(attributes);
+      DefineOwnProperty(obj, name, desc, true);
     }
-    // This is really confusing the types, but it is what the proxies spec
-    // currently requires:
-    desc = descObj;
-    */
-  } else {
-    var desc = ToPropertyDescriptor(attributes);
-    DefineOwnProperty(obj, name, desc, true);
+    return obj;
   }
-  return obj;
+  return %ObjectDefineProperty(obj, p, attributes);
 }
 
 
@@ -1101,19 +1106,24 @@
 
 // ES5 section 15.2.3.7.
 function ObjectDefineProperties(obj, properties) {
-  if (!IS_SPEC_OBJECT(obj)) {
-    throw MakeTypeError(kCalledOnNonObject, "Object.defineProperties");
+  // The new pure-C++ implementation doesn't support Proxies yet, nor O.o.
+  // TODO(jkummerow): Implement missing features and remove fallback path.
+  if (%_IsJSProxy(obj) || %_IsJSProxy(properties) || %IsObserved(obj)) {
+    if (!IS_SPEC_OBJECT(obj)) {
+      throw MakeTypeError(kCalledOnNonObject, "Object.defineProperties");
+    }
+    var props = TO_OBJECT(properties);
+    var names = GetOwnEnumerablePropertyNames(props);
+    var descriptors = new InternalArray();
+    for (var i = 0; i < names.length; i++) {
+      descriptors.push(ToPropertyDescriptor(props[names[i]]));
+    }
+    for (var i = 0; i < names.length; i++) {
+      DefineOwnProperty(obj, names[i], descriptors[i], true);
+    }
+    return obj;
   }
-  var props = TO_OBJECT(properties);
-  var names = GetOwnEnumerablePropertyNames(props);
-  var descriptors = new InternalArray();
-  for (var i = 0; i < names.length; i++) {
-    descriptors.push(ToPropertyDescriptor(props[names[i]]));
-  }
-  for (var i = 0; i < names.length; i++) {
-    DefineOwnProperty(obj, names[i], descriptors[i], true);
-  }
-  return obj;
+  return %ObjectDefineProperties(obj, properties);
 }
 
 
diff --git a/src/objects.cc b/src/objects.cc
index 5382b41..49e8b52 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -6024,6 +6024,17 @@
   LookupIterator it = LookupIterator::PropertyOrElement(
       isolate, object, key, &success, LookupIterator::HIDDEN);
   DCHECK(success);  // ...so creating a LookupIterator can't fail.
+
+  // Deal with access checks first.
+  if (it.state() == LookupIterator::ACCESS_CHECK) {
+    if (!it.HasAccess()) {
+      isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
+      RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, false);
+      return false;
+    }
+    it.Next();
+  }
+
   return OrdinaryDefineOwnProperty(&it, desc, should_throw);
 }
 
@@ -6063,6 +6074,13 @@
       }
       return false;
     }
+    // We have to use a fresh LookupIterator to handle interceptors properly.
+    LookupIterator lookup_for_store =
+        it->IsElement() ? LookupIterator(isolate, it->GetReceiver(),
+                                         it->index(), LookupIterator::HIDDEN)
+                        : LookupIterator(it->GetReceiver(), it->name(),
+                                         LookupIterator::HIDDEN);
+
     // 2c. If IsGenericDescriptor(Desc) or IsDataDescriptor(Desc) is true, then:
     // (This is equivalent to !IsAccessorDescriptor(desc).)
     DCHECK((desc_is_generic_descriptor || desc_is_data_descriptor) ==
@@ -6082,8 +6100,9 @@
                 ? desc->value()
                 : Handle<Object>::cast(isolate->factory()->undefined_value()));
         MaybeHandle<Object> result =
-            JSObject::DefineOwnPropertyIgnoreAttributes(it, value,
-                                                        desc->ToAttributes());
+            JSObject::DefineOwnPropertyIgnoreAttributes(
+                &lookup_for_store, value, desc->ToAttributes(),
+                JSObject::DONT_FORCE_FIELD);
         if (result.is_null()) return false;
       }
     } else {
@@ -6105,8 +6124,8 @@
             desc->has_set()
                 ? desc->set()
                 : Handle<Object>::cast(isolate->factory()->undefined_value()));
-        MaybeHandle<Object> result =
-            JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
+        MaybeHandle<Object> result = JSObject::DefineAccessor(
+            &lookup_for_store, getter, setter, desc->ToAttributes());
         if (result.is_null()) return false;
       }
     }
@@ -6515,7 +6534,7 @@
   if (!success && should_throw == THROW_ON_ERROR) {
     isolate->Throw(*isolate->factory()->NewTypeError(
         MessageTemplate::kStrictDeleteProperty,
-        isolate->factory()->NewNumberFromUint(actual_new_len - 1)));
+        isolate->factory()->NewNumberFromUint(actual_new_len - 1), a));
   }
   return success;
 }
@@ -7784,7 +7803,10 @@
       DCHECK(filter == INCLUDE_SYMBOLS);
       PropertyAttributes attr_filter =
           static_cast<PropertyAttributes>(DONT_ENUM | PRIVATE_SYMBOL);
-      JSObject::CollectOwnElementKeys(current, &accumulator, attr_filter);
+      Handle<FixedArray> property_keys = isolate->factory()->NewFixedArray(
+          current->NumberOfOwnProperties(attr_filter));
+      current->GetOwnPropertyNames(*property_keys, 0, attr_filter);
+      accumulator.AddKeys(property_keys);
     }
 
     // Add the property keys from the interceptor.
diff --git a/src/property-descriptor.cc b/src/property-descriptor.cc
index 442d056..2ecf75a 100644
--- a/src/property-descriptor.cc
+++ b/src/property-descriptor.cc
@@ -4,6 +4,7 @@
 
 #include "src/property-descriptor.h"
 
+#include "src/bootstrapper.h"
 #include "src/factory.h"
 #include "src/isolate-inl.h"
 #include "src/lookup.h"
@@ -43,6 +44,9 @@
   if (map->instance_type() != JS_OBJECT_TYPE) return false;
   if (map->is_access_check_needed()) return false;
   if (map->prototype() != *isolate->initial_object_prototype()) return false;
+  // During bootstrapping, the object_function_prototype_map hasn't been
+  // set up yet.
+  if (isolate->bootstrapper()->IsActive()) return false;
   if (JSObject::cast(map->prototype())->map() !=
       isolate->native_context()->object_function_prototype_map()) {
     return false;
@@ -210,7 +214,11 @@
     }
   } else {
     DCHECK(obj->IsJSProxy());
-    UNIMPLEMENTED();
+    // Having an UNIMPLEMENTED() here would upset ClusterFuzz, because
+    // --harmony-proxies makes it possible to reach this branch.
+    isolate->Throw(
+        *isolate->factory()->NewTypeError(MessageTemplate::kUnsupported));
+    return false;
   }
   // 23. Return desc.
   return true;
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index e4fcf4a..8ad8a77 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -8727,10 +8727,12 @@
   CompileRun("other.accessible_prop = 42");
   CHECK_EQ(42, g_echo_value);
 
-  v8::Handle<Value> value;
-  CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
-  value = CompileRun("other.accessible_prop == 42");
-  CHECK(value->IsTrue());
+  // [[DefineOwnProperty]] always throws for access-checked objects.
+  CHECK(
+      CompileRun("Object.defineProperty(other, 'accessible_prop', {value: 43})")
+          .IsEmpty());
+  CHECK(CompileRun("other.accessible_prop == 42")->IsTrue());
+  CHECK_EQ(42, g_echo_value);  // Make sure we didn't call the setter.
 }
 
 
diff --git a/test/test262/test262.status b/test/test262/test262.status
index 1093327..01def65 100644
--- a/test/test262/test262.status
+++ b/test/test262/test262.status
@@ -33,30 +33,6 @@
   'intl402/11.2.3_b': [FAIL],
   'intl402/12.2.3_b': [FAIL],
 
-  # BUG(v8:4267)
-  'built-ins/Object/defineProperties/15.2.3.7-6-a-112': [FAIL],
-  'built-ins/Object/defineProperties/15.2.3.7-6-a-113': [FAIL],
-  'built-ins/Object/defineProperties/15.2.3.7-6-a-164': [FAIL],
-  'built-ins/Object/defineProperties/15.2.3.7-6-a-165': [FAIL],
-  'built-ins/Object/defineProperties/15.2.3.7-6-a-166': [FAIL],
-  'built-ins/Object/defineProperties/15.2.3.7-6-a-168': [FAIL],
-  'built-ins/Object/defineProperties/15.2.3.7-6-a-169': [FAIL],
-  'built-ins/Object/defineProperties/15.2.3.7-6-a-170': [FAIL],
-  'built-ins/Object/defineProperties/15.2.3.7-6-a-172': [FAIL],
-  'built-ins/Object/defineProperties/15.2.3.7-6-a-173': [FAIL],
-  'built-ins/Object/defineProperties/15.2.3.7-6-a-175': [FAIL],
-  'built-ins/Object/defineProperties/15.2.3.7-6-a-176': [FAIL],
-  'built-ins/Object/defineProperty/15.2.3.6-4-116': [FAIL],
-  'built-ins/Object/defineProperty/15.2.3.6-4-117': [FAIL],
-  'built-ins/Object/defineProperty/15.2.3.6-4-168': [FAIL],
-  'built-ins/Object/defineProperty/15.2.3.6-4-169': [FAIL],
-  'built-ins/Object/defineProperty/15.2.3.6-4-170': [FAIL],
-  'built-ins/Object/defineProperty/15.2.3.6-4-172': [FAIL],
-  'built-ins/Object/defineProperty/15.2.3.6-4-173': [FAIL],
-  'built-ins/Object/defineProperty/15.2.3.6-4-174': [FAIL],
-  'built-ins/Object/defineProperty/15.2.3.6-4-176': [FAIL],
-  'built-ins/Object/defineProperty/15.2.3.6-4-177': [FAIL],
-
   # Unicode canonicalization is not available with i18n turned off.
   'built-ins/String/prototype/localeCompare/15.5.4.9_CE': [['no_i18n', SKIP]],