Revision: 23163
Author:   [email protected]
Date:     Mon Aug 18 14:26:30 2014 UTC
Log:      Rewriting SetOwnPropertyIgnoreAttributes using the LookupIterator

BUG=
[email protected]

Review URL: https://codereview.chromium.org/468493002
http://code.google.com/p/v8/source/detail?r=23163

Modified:
 /branches/bleeding_edge/src/lookup.cc
 /branches/bleeding_edge/src/lookup.h
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/runtime.cc

=======================================
--- /branches/bleeding_edge/src/lookup.cc       Wed Aug  6 08:02:21 2014 UTC
+++ /branches/bleeding_edge/src/lookup.cc       Mon Aug 18 14:26:30 2014 UTC
@@ -124,6 +124,31 @@
   }
   CHECK(HasProperty());
 }
+
+
+void LookupIterator::ReconfigureDataProperty(Handle<Object> value,
+ PropertyAttributes attributes) {
+  DCHECK(has_property_);
+  DCHECK(HolderIsReceiverOrHiddenPrototype());
+  Handle<JSObject> holder = GetHolder<JSObject>();
+  if (property_encoding_ != DICTIONARY) {
+ holder_map_ = Map::ReconfigureDataProperty(holder_map_, descriptor_number(),
+                                               attributes);
+    JSObject::MigrateToMap(holder, holder_map_);
+  }
+
+  // Reload property information and update the descriptor if in dictionary
+  // mode.
+  if (holder_map_->is_dictionary_map()) {
+    property_encoding_ = DICTIONARY;
+    PropertyDetails details(attributes, NORMAL, 0);
+    JSObject::SetNormalizedProperty(holder, name(), value, details);
+  } else {
+    property_encoding_ = DESCRIPTOR;
+  }
+
+  CHECK(HasProperty());
+}


 void LookupIterator::TransitionToDataProperty(
@@ -136,10 +161,6 @@
   // observable.
   Handle<JSObject> receiver = Handle<JSObject>::cast(GetReceiver());

-  // Properties have to be added to context extension objects through
-  // SetOwnPropertyIgnoreAttributes.
-  DCHECK(!receiver->IsJSContextExtensionObject());
-
   if (receiver->IsJSGlobalProxy()) {
     PrototypeIterator iter(isolate(), receiver);
     receiver =
@@ -162,6 +183,8 @@

 bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const {
   DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
+  // Optimization that only works if configuration_ is not mutable.
+  if (!check_derived()) return true;
   DisallowHeapAllocation no_gc;
   Handle<Object> receiver = GetReceiver();
   if (!receiver->IsJSReceiver()) return false;
@@ -180,6 +203,16 @@
   } while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN));
   return false;
 }
+
+
+bool LookupIterator::HolderIsNonGlobalHiddenPrototype() const {
+  if (!HolderIsReceiverOrHiddenPrototype()) return false;
+  Handle<Object> receiver = GetReceiver();
+  Handle<JSReceiver> holder = GetHolder<JSReceiver>();
+  if (receiver.is_identical_to(holder)) return false;
+  if (receiver->IsJSGlobalProxy()) return !holder->IsJSGlobalObject();
+  return true;
+}


 Handle<Object> LookupIterator::FetchValue() const {
=======================================
--- /branches/bleeding_edge/src/lookup.h        Tue Aug 12 15:28:20 2014 UTC
+++ /branches/bleeding_edge/src/lookup.h        Mon Aug 18 14:26:30 2014 UTC
@@ -15,15 +15,15 @@
 class LookupIterator V8_FINAL BASE_EMBEDDED {
  public:
   enum Configuration {
-    CHECK_OWN_REAL     = 0,
-    CHECK_HIDDEN       = 1 << 0,
-    CHECK_DERIVED      = 1 << 1,
-    CHECK_INTERCEPTOR  = 1 << 2,
+    CHECK_OWN_REAL = 0,
+    CHECK_HIDDEN = 1 << 0,
+    CHECK_DERIVED = 1 << 1,
+    CHECK_INTERCEPTOR = 1 << 2,
     CHECK_ACCESS_CHECK = 1 << 3,
-    CHECK_ALL          = CHECK_HIDDEN | CHECK_DERIVED |
-                         CHECK_INTERCEPTOR | CHECK_ACCESS_CHECK,
-    SKIP_INTERCEPTOR   = CHECK_ALL ^ CHECK_INTERCEPTOR,
-    CHECK_OWN          = CHECK_ALL ^ CHECK_DERIVED
+    CHECK_HIDDEN_ACCESS = CHECK_HIDDEN | CHECK_ACCESS_CHECK,
+    SKIP_INTERCEPTOR = CHECK_HIDDEN_ACCESS | CHECK_DERIVED,
+    CHECK_ALL = SKIP_INTERCEPTOR | CHECK_INTERCEPTOR,
+    CHECK_OWN = CHECK_HIDDEN_ACCESS | CHECK_INTERCEPTOR
   };

   enum State {
@@ -90,7 +90,7 @@
   Heap* heap() const { return isolate_->heap(); }
   Factory* factory() const { return isolate_->factory(); }
   Handle<Object> GetReceiver() const {
-    return Handle<Object>::cast(maybe_receiver_.ToHandleChecked());
+    return maybe_receiver_.ToHandleChecked();
   }
   Handle<Map> holder_map() const { return holder_map_; }
   template <class T>
@@ -100,16 +100,7 @@
   }
   Handle<JSReceiver> GetRoot() const;
   bool HolderIsReceiverOrHiddenPrototype() const;
-
-  /* Dynamically reduce the trapped types. */
-  void skip_interceptor() {
-    configuration_ = static_cast<Configuration>(
-        configuration_ & ~CHECK_INTERCEPTOR);
-  }
-  void skip_access_check() {
-    configuration_ = static_cast<Configuration>(
-        configuration_ & ~CHECK_ACCESS_CHECK);
-  }
+  bool HolderIsNonGlobalHiddenPrototype() const;

   /* ACCESS_CHECK */
   bool HasAccess(v8::AccessType access_type) const;
@@ -123,6 +114,8 @@
   void TransitionToDataProperty(Handle<Object> value,
                                 PropertyAttributes attributes,
                                 Object::StoreFromKeyed store_mode);
+  void ReconfigureDataProperty(Handle<Object> value,
+                               PropertyAttributes attributes);
   PropertyKind property_kind() const {
     DCHECK(has_property_);
     return property_kind_;
@@ -196,6 +189,8 @@
     }
   }

+  // If configuration_ becomes mutable, update
+  // HolderIsReceiverOrHiddenPrototype.
   Configuration configuration_;
   State state_;
   bool has_property_;
=======================================
--- /branches/bleeding_edge/src/objects.cc      Mon Aug 18 07:54:19 2014 UTC
+++ /branches/bleeding_edge/src/objects.cc      Mon Aug 18 14:26:30 2014 UTC
@@ -575,8 +575,6 @@


 static bool FindAllCanReadHolder(LookupIterator* it) {
-  it->skip_interceptor();
-  it->skip_access_check();
   for (; it->IsFound(); it->Next()) {
     if (it->state() == LookupIterator::PROPERTY &&
         it->HasProperty() &&
@@ -618,8 +616,6 @@


 static bool FindAllCanWriteHolder(LookupIterator* it) {
-  it->skip_interceptor();
-  it->skip_access_check();
   for (; it->IsFound(); it->Next()) {
     if (it->state() == LookupIterator::PROPERTY && it->HasProperty() &&
         it->property_kind() == LookupIterator::ACCESSOR) {
@@ -672,21 +668,6 @@
   DCHECK(!value->IsPropertyCell() && !value->IsCell());
   return value;
 }
-
-
-void JSObject::SetNormalizedProperty(Handle<JSObject> object,
-                                     const LookupResult* result,
-                                     Handle<Object> value) {
-  DCHECK(!object->HasFastProperties());
-  NameDictionary* property_dictionary = object->property_dictionary();
-  if (object->IsGlobalObject()) {
-    Handle<PropertyCell> cell(PropertyCell::cast(
-        property_dictionary->ValueAt(result->GetDictionaryEntry())));
-    PropertyCell::SetValueInferType(cell, value);
-  } else {
-    property_dictionary->ValueAtPut(result->GetDictionaryEntry(), *value);
-  }
-}


 void JSObject::SetNormalizedProperty(Handle<JSObject> object,
@@ -1821,37 +1802,6 @@
   ConstantDescriptor new_constant_desc(name, constant, attributes);
   return Map::CopyAddDescriptor(map, &new_constant_desc, flag);
 }
-
-
-void JSObject::AddFastProperty(Handle<JSObject> object,
-                               Handle<Name> name,
-                               Handle<Object> value,
-                               PropertyAttributes attributes,
-                               StoreFromKeyed store_mode,
-                               TransitionFlag flag) {
-  DCHECK(!object->IsJSGlobalProxy());
-
-  MaybeHandle<Map> maybe_map;
-  if (value->IsJSFunction()) {
-    maybe_map = Map::CopyWithConstant(
-        handle(object->map()), name, value, attributes, flag);
-  } else if (!object->map()->TooManyFastProperties(store_mode)) {
-    Isolate* isolate = object->GetIsolate();
-    Representation representation = value->OptimalRepresentation();
-    maybe_map = Map::CopyWithField(
-        handle(object->map(), isolate), name,
-        value->OptimalType(isolate, representation),
-        attributes, representation, flag);
-  }
-
-  Handle<Map> new_map;
-  if (!maybe_map.ToHandle(&new_map)) {
-    NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
-    return;
-  }
-
-  JSObject::MigrateToNewProperty(object, new_map, value);
-}


 void JSObject::AddSlowProperty(Handle<JSObject> object,
@@ -1886,45 +1836,6 @@
 }


-MaybeHandle<Object> JSObject::AddPropertyInternal(
-    Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
-    PropertyAttributes attributes, JSReceiver::StoreFromKeyed store_mode,
- ExtensibilityCheck extensibility_check, TransitionFlag transition_flag) {
-  DCHECK(!object->IsJSGlobalProxy());
-  Isolate* isolate = object->GetIsolate();
-
-  if (!name->IsUniqueName()) {
-    name = isolate->factory()->InternalizeString(
-        Handle<String>::cast(name));
-  }
-
-  if (extensibility_check == PERFORM_EXTENSIBILITY_CHECK &&
-      !object->map()->is_extensible()) {
-    Handle<Object> args[1] = {name};
-    Handle<Object> error = isolate->factory()->NewTypeError(
-        "object_not_extensible", HandleVector(args, ARRAY_SIZE(args)));
-    return isolate->Throw<Object>(error);
-  }
-
-  if (object->HasFastProperties()) {
-    AddFastProperty(object, name, value, attributes, store_mode,
-                    transition_flag);
-  }
-
-  if (!object->HasFastProperties()) {
-    AddSlowProperty(object, name, value, attributes);
-  }
-
-  if (object->map()->is_observed() &&
-      *name != isolate->heap()->hidden_string()) {
-    Handle<Object> old_value = isolate->factory()->the_hole_value();
-    EnqueueChangeRecord(object, "add", name, old_value);
-  }
-
-  return value;
-}
-
-
 Context* JSObject::GetCreationContext() {
   Object* constructor = this->map()->constructor();
   JSFunction* function;
@@ -1957,23 +1868,6 @@
                   isolate->factory()->undefined_value(),
                   argc, args).Assert();
 }
-
-
-static void ReplaceSlowProperty(Handle<JSObject> object,
-                                Handle<Name> name,
-                                Handle<Object> value,
-                                PropertyAttributes attributes) {
-  NameDictionary* dictionary = object->property_dictionary();
-  int old_index = dictionary->FindEntry(name);
- int new_enumeration_index = 0; // 0 means "Use the next available index."
-  if (old_index != -1) {
-    // All calls to ReplaceSlowProperty have had all transitions removed.
- new_enumeration_index = dictionary->DetailsAt(old_index).dictionary_index();
-  }
-
-  PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
-  JSObject::SetNormalizedProperty(object, name, value, new_details);
-}


 const char* Representation::Mnemonic() const {
@@ -3029,7 +2923,8 @@
     if (done) break;
   }

-  return AddDataProperty(it, value, NONE, strict_mode, store_mode);
+  return AddDataProperty(it, value, NONE, strict_mode, store_mode,
+                         PERFORM_EXTENSIBILITY_CHECK);
 }


@@ -3084,7 +2979,8 @@
                                             Handle<Object> value,
                                             PropertyAttributes attributes,
                                             StrictMode strict_mode,
-                                            StoreFromKeyed store_mode) {
+                                            StoreFromKeyed store_mode,
+                                            ExtensibilityCheck check) {
   DCHECK(!it->GetReceiver()->IsJSProxy());
   if (!it->GetReceiver()->IsJSObject()) {
     // TODO(verwaest): Throw a TypeError with a more specific message.
@@ -3102,7 +2998,8 @@
         Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter));
   }

-  if (!receiver->map()->is_extensible()) {
+  if (check == PERFORM_EXTENSIBILITY_CHECK &&
+      !receiver->map()->is_extensible()) {
     if (strict_mode == SLOPPY) return value;

     Handle<Object> args[1] = {it->name()};
@@ -3941,45 +3838,6 @@
   }
   return true;
 }
-
-
-MaybeHandle<Object> JSObject::SetPropertyUsingTransition(
-    Handle<JSObject> object,
-    LookupResult* lookup,
-    Handle<Name> name,
-    Handle<Object> value,
-    PropertyAttributes attributes) {
-  Handle<Map> transition_map(lookup->GetTransitionTarget());
-  int descriptor = transition_map->LastAdded();
-
- Handle<DescriptorArray> descriptors(transition_map->instance_descriptors());
-  PropertyDetails details = descriptors->GetDetails(descriptor);
-
-  if (details.type() == CALLBACKS || attributes != details.attributes()) {
- // AddPropertyInternal will either normalize the object, or create a new
-    // fast copy of the map. If we get a fast copy of the map, all field
-    // representations will be tagged since the transition is omitted.
-    return JSObject::AddPropertyInternal(
-        object, name, value, attributes,
-        JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED,
-        JSReceiver::OMIT_EXTENSIBILITY_CHECK, OMIT_TRANSITION);
-  }
-
-  // Keep the target CONSTANT if the same value is stored.
-  // TODO(verwaest): Also support keeping the placeholder
-  // (value->IsUninitialized) as constant.
-  if (!lookup->CanHoldValue(value)) {
-    Representation field_representation = value->OptimalRepresentation();
-    Handle<HeapType> field_type = value->OptimalType(
-        lookup->isolate(), field_representation);
-    transition_map = Map::GeneralizeRepresentation(
-        transition_map, descriptor,
-        field_representation, field_type, FORCE_FIELD);
-  }
-
-  JSObject::MigrateToNewProperty(object, transition_map, value);
-  return value;
-}


 void JSObject::MigrateToNewProperty(Handle<JSObject> object,
@@ -4010,65 +3868,6 @@
     FastPropertyAtPut(index, value);
   }
 }
-
-
-void JSObject::SetPropertyToField(LookupResult* lookup, Handle<Object> value) {
-  if (lookup->type() == CONSTANT || !lookup->CanHoldValue(value)) {
-    Representation field_representation = value->OptimalRepresentation();
-    Handle<HeapType> field_type = value->OptimalType(
-        lookup->isolate(), field_representation);
-    JSObject::GeneralizeFieldRepresentation(handle(lookup->holder()),
-                                            lookup->GetDescriptorIndex(),
- field_representation, field_type);
-  }
-  lookup->holder()->WriteToField(lookup->GetDescriptorIndex(), *value);
-}
-
-
-void JSObject::ConvertAndSetOwnProperty(LookupResult* lookup,
-                                        Handle<Name> name,
-                                        Handle<Object> value,
-                                        PropertyAttributes attributes) {
-  Handle<JSObject> object(lookup->holder());
- if (object->map()->TooManyFastProperties(Object::MAY_BE_STORE_FROM_KEYED)) {
-    JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
-  } else if (object->map()->is_prototype_map()) {
-    JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0);
-  }
-
-  if (!object->HasFastProperties()) {
-    ReplaceSlowProperty(object, name, value, attributes);
-    ReoptimizeIfPrototype(object);
-    return;
-  }
-
-  int descriptor_index = lookup->GetDescriptorIndex();
-  if (lookup->GetAttributes() == attributes) {
-    JSObject::GeneralizeFieldRepresentation(object, descriptor_index,
-                                            Representation::Tagged(),
- HeapType::Any(lookup->isolate()));
-  } else {
-    Handle<Map> old_map(object->map());
-    Handle<Map> new_map = Map::CopyGeneralizeAllRepresentations(old_map,
-        descriptor_index, FORCE_FIELD, attributes, "attributes mismatch");
-    JSObject::MigrateToMap(object, new_map);
-  }
-
-  object->WriteToField(descriptor_index, *value);
-}
-
-
-void JSObject::SetPropertyToFieldWithAttributes(LookupResult* lookup,
-                                                Handle<Name> name,
-                                                Handle<Object> value,
- PropertyAttributes attributes) {
-  if (lookup->GetAttributes() == attributes) {
-    if (value->IsUninitialized()) return;
-    SetPropertyToField(lookup, value);
-  } else {
-    ConvertAndSetOwnProperty(lookup, name, value, attributes);
-  }
-}


 void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name,
@@ -4100,156 +3899,123 @@
     StoreFromKeyed store_from_keyed,
     ExecutableAccessorInfoHandling handling) {
   DCHECK(!value->IsTheHole());
-  Isolate* isolate = object->GetIsolate();
+  LookupIterator it(object, name, LookupIterator::CHECK_HIDDEN_ACCESS);
+  bool is_observed = object->map()->is_observed() &&
+                     *name != it.isolate()->heap()->hidden_string();
+  for (; it.IsFound(); it.Next()) {
+    switch (it.state()) {
+      case LookupIterator::NOT_FOUND:
+      case LookupIterator::JSPROXY:
+      case LookupIterator::INTERCEPTOR:
+        UNREACHABLE();

-  // Make sure that the top context does not change when doing callbacks or
-  // interceptor calls.
-  AssertNoContextChange ncc(isolate);
+      case LookupIterator::ACCESS_CHECK:
+        if (!it.isolate()->MayNamedAccess(object, name, v8::ACCESS_SET)) {
+          return SetPropertyWithFailedAccessCheck(&it, value, SLOPPY);
+        }
+        break;

-  LookupResult lookup(isolate);
-  object->LookupOwn(name, &lookup, true);
-  if (!lookup.IsFound()) {
-    object->map()->LookupTransition(*object, *name, &lookup);
-  }
+      case LookupIterator::PROPERTY: {
+        if (!it.HasProperty()) break;
+        if (it.HolderIsNonGlobalHiddenPrototype()) break;
+        PropertyDetails details = it.property_details();
+ Handle<Object> old_value = it.isolate()->factory()->the_hole_value();
+        switch (it.property_kind()) {
+          case LookupIterator::ACCESSOR: {
+ // Ensure the context isn't changed after calling into accessors.
+            AssertNoContextChange ncc(it.isolate());

-  // Check access rights if needed.
-  if (object->IsAccessCheckNeeded()) {
-    if (!isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) {
-      LookupIterator it(object, name, LookupIterator::CHECK_OWN);
-      return SetPropertyWithFailedAccessCheck(&it, value, SLOPPY);
-    }
-  }
+            Handle<Object> accessors = it.GetAccessors();

-  if (object->IsJSGlobalProxy()) {
-    PrototypeIterator iter(isolate, object);
-    if (iter.IsAtEnd()) return value;
-    DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
-    return SetOwnPropertyIgnoreAttributes(
-        Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), name,
-        value, attributes, extensibility_check);
-  }
+            if (is_observed && accessors->IsAccessorInfo()) {
+              ASSIGN_RETURN_ON_EXCEPTION(
+                  it.isolate(), old_value,
+                  GetPropertyWithAccessor(it.GetReceiver(), it.name(),
+ it.GetHolder<JSObject>(), accessors),
+                  Object);
+            }

-  if (lookup.IsInterceptor() ||
-      (lookup.IsDescriptorOrDictionary() && lookup.type() == CALLBACKS)) {
-    object->LookupOwnRealNamedProperty(name, &lookup);
-  }
+ // Special handling for ExecutableAccessorInfo, which behaves like a
+            // data property.
+            if (handling == DONT_FORCE_FIELD &&
+                accessors->IsExecutableAccessorInfo()) {
+              Handle<Object> result;
+              ASSIGN_RETURN_ON_EXCEPTION(
+                  it.isolate(), result,
+                  JSObject::SetPropertyWithAccessor(
+                      it.GetReceiver(), it.name(), value,
+                      it.GetHolder<JSObject>(), accessors, STRICT),
+                  Object);
+              DCHECK(result->SameValue(*value));

-  // Check for accessor in prototype chain removed here in clone.
-  if (!lookup.IsFound()) {
-    object->map()->LookupTransition(*object, *name, &lookup);
-    TransitionFlag flag = lookup.IsFound()
-        ? OMIT_TRANSITION : INSERT_TRANSITION;
-    // Neither properties nor transitions found.
-    return AddPropertyInternal(object, name, value, attributes,
- store_from_keyed, extensibility_check, flag);
-  }
+              if (details.attributes() == attributes) {
+                // Regular property update if the attributes match.
+                if (is_observed && !old_value->SameValue(*value)) {
+                  // If we are setting the prototype of a function and are
+ // observed, don't send change records because the prototype
+                  // handles that itself.
+                  if (!object->IsJSFunction() ||
+                      
!Name::Equals(it.isolate()->factory()->prototype_string(),
+                                    name) ||
+                      !Handle<JSFunction>::cast(object)
+                           ->should_have_prototype()) {
+                    EnqueueChangeRecord(object, "update", name, old_value);
+                  }
+                }
+                return value;
+              }

-  Handle<Object> old_value = isolate->factory()->the_hole_value();
-  PropertyAttributes old_attributes = ABSENT;
-  bool is_observed = object->map()->is_observed() &&
-                     *name != isolate->heap()->hidden_string();
-  if (is_observed && lookup.IsProperty()) {
-    if (lookup.IsDataProperty()) {
- old_value = Object::GetPropertyOrElement(object, name).ToHandleChecked();
-    }
-    old_attributes = lookup.GetAttributes();
-  }
+              // Reconfigure the accessor if attributes mismatch.
+              Handle<ExecutableAccessorInfo> new_data =
+                  Accessors::CloneAccessor(
+                      it.isolate(),
+                      Handle<ExecutableAccessorInfo>::cast(accessors));
+              new_data->set_property_attributes(attributes);
+ // By clearing the setter we don't have to introduce a lookup to
+              // the setter, simply make it unavailable to reflect the
+              // attributes.
+              if (attributes & READ_ONLY) new_data->clear_setter();
+              SetPropertyCallback(object, name, new_data, attributes);
+              if (is_observed) {
+                if (old_value->SameValue(*value)) {
+                  old_value = it.isolate()->factory()->the_hole_value();
+                }
+ EnqueueChangeRecord(object, "reconfigure", name, old_value);
+              }
+              return value;
+            }

-  bool executed_set_prototype = false;
+            // Regular accessor. Reconfigure to data property.
+            break;
+          }

-  // Check of IsReadOnly removed from here in clone.
-  if (lookup.IsTransition()) {
-    Handle<Object> result;
-    ASSIGN_RETURN_ON_EXCEPTION(
-        isolate, result,
-        SetPropertyUsingTransition(
-            handle(lookup.holder()), &lookup, name, value, attributes),
-        Object);
-  } else {
-    switch (lookup.type()) {
-      case NORMAL:
-        ReplaceSlowProperty(object, name, value, attributes);
-        break;
-      case FIELD:
-        SetPropertyToFieldWithAttributes(&lookup, name, value, attributes);
-        break;
-      case CONSTANT:
-        // Only replace the constant if necessary.
-        if (lookup.GetAttributes() != attributes ||
-            *value != lookup.GetConstant()) {
- SetPropertyToFieldWithAttributes(&lookup, name, value, attributes);
+          case LookupIterator::DATA:
+            // Regular property update if the attributes match.
+            if (details.attributes() == attributes) {
+              return SetDataProperty(&it, value);
+            }
+            // Reconfigure the data property if the attributes mismatch.
+            if (is_observed) old_value = it.GetDataValue();
         }
-        break;
-      case CALLBACKS:
-      {
-        Handle<Object> callback(lookup.GetCallbackObject(), isolate);
-        if (callback->IsExecutableAccessorInfo() &&
-            handling == DONT_FORCE_FIELD) {
-          Handle<Object> result;
-          ASSIGN_RETURN_ON_EXCEPTION(
-              isolate, result, JSObject::SetPropertyWithAccessor(
- object, name, value, handle(lookup.holder()),
-                                   callback, STRICT),
-              Object);

-          if (attributes != lookup.GetAttributes()) {
-            Handle<ExecutableAccessorInfo> new_data =
-                Accessors::CloneAccessor(
- isolate, Handle<ExecutableAccessorInfo>::cast(callback));
-            new_data->set_property_attributes(attributes);
-            if (attributes & READ_ONLY) {
- // This way we don't have to introduce a lookup to the setter,
-              // simply make it unavailable to reflect the attributes.
-              new_data->clear_setter();
-            }
+        it.ReconfigureDataProperty(value, attributes);
+        it.PrepareForDataProperty(value);
+        it.WriteDataValue(value);

-            SetPropertyCallback(object, name, new_data, attributes);
+        if (is_observed) {
+          if (old_value->SameValue(*value)) {
+            old_value = it.isolate()->factory()->the_hole_value();
           }
-          if (is_observed) {
- // If we are setting the prototype of a function and are observed,
-            // don't send change records because the prototype handles that
-            // itself.
-            executed_set_prototype = object->IsJSFunction() &&
-                String::Equals(isolate->factory()->prototype_string(),
-                               Handle<String>::cast(name)) &&
-                Handle<JSFunction>::cast(object)->should_have_prototype();
-          }
-        } else {
-          ConvertAndSetOwnProperty(&lookup, name, value, attributes);
+          EnqueueChangeRecord(object, "reconfigure", name, old_value);
         }
-        break;
-      }
-      case NONEXISTENT:
-      case HANDLER:
-      case INTERCEPTOR:
-        UNREACHABLE();
-    }
-  }

-  if (is_observed && !executed_set_prototype) {
-    if (lookup.IsTransition()) {
-      EnqueueChangeRecord(object, "add", name, old_value);
-    } else if (old_value->IsTheHole()) {
-      EnqueueChangeRecord(object, "reconfigure", name, old_value);
-    } else {
-      LookupResult new_lookup(isolate);
-      object->LookupOwn(name, &new_lookup, true);
-      bool value_changed = false;
-      if (new_lookup.IsDataProperty()) {
-        Handle<Object> new_value =
-            Object::GetPropertyOrElement(object, name).ToHandleChecked();
-        value_changed = !old_value->SameValue(*new_value);
-      }
-      if (new_lookup.GetAttributes() != old_attributes) {
- if (!value_changed) old_value = isolate->factory()->the_hole_value();
-        EnqueueChangeRecord(object, "reconfigure", name, old_value);
-      } else if (value_changed) {
-        EnqueueChangeRecord(object, "update", name, old_value);
+        return value;
       }
     }
   }

-  return value;
+  return AddDataProperty(&it, value, attributes, STRICT, store_from_keyed,
+                         extensibility_check);
 }


@@ -7409,6 +7175,18 @@

   return result;
 }
+
+
+Handle<Map> Map::ReconfigureDataProperty(Handle<Map> map, int descriptor,
+                                         PropertyAttributes attributes) {
+  // Dictionaries have to be reconfigured in-place.
+  DCHECK(!map->is_dictionary_map());
+
+  // For now, give up on transitioning and just create a unique map.
+  // TODO(verwaest/ishell): Cache transitions with different attributes.
+  return CopyGeneralizeAllRepresentations(map, descriptor, FORCE_FIELD,
+ attributes, "attributes mismatch");
+}


 Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
=======================================
--- /branches/bleeding_edge/src/objects.h       Mon Aug 18 12:35:34 2014 UTC
+++ /branches/bleeding_edge/src/objects.h       Mon Aug 18 14:26:30 2014 UTC
@@ -247,6 +247,14 @@
 };


+// Internal properties (e.g. the hidden properties dictionary) might
+// be added even though the receiver is non-extensible.
+enum ExtensibilityCheck {
+  PERFORM_EXTENSIBILITY_CHECK,
+  OMIT_EXTENSIBILITY_CHECK
+};
+
+
// Indicates how aggressively the prototype should be optimized. FAST_PROTOTYPE // will give the fastest result by tailoring the map to the prototype, but that // will cause polymorphism with other objects. REGULAR_PROTOTYPE is to be used
@@ -1492,7 +1500,8 @@
       LookupIterator* it, Handle<Object> value);
   MUST_USE_RESULT static MaybeHandle<Object> AddDataProperty(
LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
-      StrictMode strict_mode, StoreFromKeyed store_mode);
+      StrictMode strict_mode, StoreFromKeyed store_mode,
+      ExtensibilityCheck check);
   MUST_USE_RESULT static inline MaybeHandle<Object> GetPropertyOrElement(
       Handle<Object> object,
       Handle<Name> key);
@@ -1936,13 +1945,6 @@
     FORCE_DELETION
   };

-  // Internal properties (e.g. the hidden properties dictionary) might
-  // be added even though the receiver is non-extensible.
-  enum ExtensibilityCheck {
-    PERFORM_EXTENSIBILITY_CHECK,
-    OMIT_EXTENSIBILITY_CHECK
-  };
-
   DECLARE_CAST(JSReceiver)

   MUST_USE_RESULT static MaybeHandle<Object> SetElement(
@@ -2172,12 +2174,6 @@
   static Handle<Object> GetNormalizedProperty(Handle<JSObject> object,
                                               const LookupResult* result);

-  // Sets the property value in a normalized object given a lookup result.
-  // Handles the special representation of JS global objects.
-  static void SetNormalizedProperty(Handle<JSObject> object,
-                                    const LookupResult* result,
-                                    Handle<Object> value);
-
// Sets the property value in a normalized object given (key, value, details).
   // Handles the special representation of JS global objects.
   static void SetNormalizedProperty(Handle<JSObject> object,
@@ -2621,17 +2617,6 @@
                                 Handle<Map> new_map,
                                 int expected_additional_properties);

- static void SetPropertyToField(LookupResult* lookup, Handle<Object> value);
-
-  static void ConvertAndSetOwnProperty(LookupResult* lookup,
-                                       Handle<Name> name,
-                                       Handle<Object> value,
-                                       PropertyAttributes attributes);
-
-  static void SetPropertyToFieldWithAttributes(LookupResult* lookup,
-                                               Handle<Name> name,
-                                               Handle<Object> value,
- PropertyAttributes attributes);
   static void GeneralizeFieldRepresentation(Handle<JSObject> object,
                                             int modify_index,
Representation new_representation,
@@ -2705,29 +2690,9 @@
       StrictMode strict_mode,
       bool check_prototype = true);

-  MUST_USE_RESULT static MaybeHandle<Object> SetPropertyUsingTransition(
-      Handle<JSObject> object,
-      LookupResult* lookup,
-      Handle<Name> name,
-      Handle<Object> value,
-      PropertyAttributes attributes);
MUST_USE_RESULT static MaybeHandle<Object> SetPropertyWithFailedAccessCheck(
       LookupIterator* it, Handle<Object> value, StrictMode strict_mode);

-  // Add a property to an object.
-  MUST_USE_RESULT static MaybeHandle<Object> AddPropertyInternal(
-      Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
-      PropertyAttributes attributes, StoreFromKeyed store_mode,
-      ExtensibilityCheck extensibility_check, TransitionFlag flag);
-
-  // Add a property to a fast-case object.
-  static void AddFastProperty(Handle<JSObject> object,
-                              Handle<Name> name,
-                              Handle<Object> value,
-                              PropertyAttributes attributes,
-                              StoreFromKeyed store_mode,
-                              TransitionFlag flag);
-
   // Add a property to a slow-case object.
   static void AddSlowProperty(Handle<JSObject> object,
                               Handle<Name> name,
@@ -6517,6 +6482,8 @@
                                               Handle<Object> value,
PropertyAttributes attributes,
                                               StoreFromKeyed store_mode);
+ static Handle<Map> ReconfigureDataProperty(Handle<Map> map, int descriptor, + PropertyAttributes attributes);

   inline void AppendDescriptor(Descriptor* desc);

=======================================
--- /branches/bleeding_edge/src/runtime.cc      Mon Aug 18 08:51:35 2014 UTC
+++ /branches/bleeding_edge/src/runtime.cc      Mon Aug 18 14:26:30 2014 UTC
@@ -5041,10 +5041,8 @@
     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
         isolate, result,
         JSObject::SetOwnPropertyIgnoreAttributes(
-            js_object, name, obj_value, attr,
-            JSReceiver::PERFORM_EXTENSIBILITY_CHECK,
-            JSReceiver::MAY_BE_STORE_FROM_KEYED,
-            JSObject::DONT_FORCE_FIELD));
+            js_object, name, obj_value, attr, PERFORM_EXTENSIBILITY_CHECK,
+ JSReceiver::MAY_BE_STORE_FROM_KEYED, JSObject::DONT_FORCE_FIELD));
     return *result;
   }

@@ -5198,7 +5196,7 @@
     } else {
if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
       return JSObject::SetOwnPropertyIgnoreAttributes(
- js_object, name, value, attr, JSReceiver::PERFORM_EXTENSIBILITY_CHECK,
+          js_object, name, value, attr, PERFORM_EXTENSIBILITY_CHECK,
           store_from_keyed);
     }
   }
@@ -5214,7 +5212,7 @@
                                 SLOPPY, false, DEFINE_PROPERTY);
   } else {
     return JSObject::SetOwnPropertyIgnoreAttributes(
- js_object, name, value, attr, JSReceiver::PERFORM_EXTENSIBILITY_CHECK,
+        js_object, name, value, attr, PERFORM_EXTENSIBILITY_CHECK,
         store_from_keyed);
   }
 }

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to