Revision: 22802
Author:   [email protected]
Date:     Mon Aug  4 08:34:56 2014 UTC
Log:      Avoid one repeated property lookup when computing load ICs.

[email protected]

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

Modified:
 /branches/bleeding_edge/src/arm/stub-cache-arm.cc
 /branches/bleeding_edge/src/arm64/stub-cache-arm64.cc
 /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
 /branches/bleeding_edge/src/ic.cc
 /branches/bleeding_edge/src/ic.h
 /branches/bleeding_edge/src/lookup.cc
 /branches/bleeding_edge/src/lookup.h
 /branches/bleeding_edge/src/mips/stub-cache-mips.cc
 /branches/bleeding_edge/src/mips64/stub-cache-mips64.cc
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/stub-cache.h
 /branches/bleeding_edge/src/x64/stub-cache-x64.cc
 /branches/bleeding_edge/src/x87/stub-cache-x87.cc

=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Wed Jul 30 12:21:41 2014 UTC +++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Mon Aug 4 08:34:56 2014 UTC
@@ -1221,7 +1221,7 @@


 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
-    Handle<PropertyCell> cell, Handle<Name> name, bool is_dont_delete) {
+    Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
   Label miss;
   FrontendHeader(receiver(), name, &miss);

@@ -1231,7 +1231,7 @@
   __ ldr(result, FieldMemOperand(result, Cell::kValueOffset));

   // Check for deleted property if property can actually be deleted.
-  if (!is_dont_delete) {
+  if (is_configurable) {
     __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
     __ cmp(result, ip);
     __ b(eq, &miss);
=======================================
--- /branches/bleeding_edge/src/arm64/stub-cache-arm64.cc Wed Jul 30 12:44:50 2014 UTC +++ /branches/bleeding_edge/src/arm64/stub-cache-arm64.cc Mon Aug 4 08:34:56 2014 UTC
@@ -1195,7 +1195,7 @@


 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
-    Handle<PropertyCell> cell, Handle<Name> name, bool is_dont_delete) {
+    Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
   Label miss;
   FrontendHeader(receiver(), name, &miss);

@@ -1205,7 +1205,7 @@
   __ Ldr(result, FieldMemOperand(result, Cell::kValueOffset));

   // Check for deleted property if property can actually be deleted.
-  if (!is_dont_delete) {
+  if (is_configurable) {
     __ JumpIfRoot(result, Heap::kTheHoleValueRootIndex, &miss);
   }

=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Wed Jul 30 12:21:41 2014 UTC +++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Mon Aug 4 08:34:56 2014 UTC
@@ -1245,7 +1245,7 @@


 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
-    Handle<PropertyCell> cell, Handle<Name> name, bool is_dont_delete) {
+    Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
   Label miss;

   FrontendHeader(receiver(), name, &miss);
@@ -1259,7 +1259,7 @@
   }

   // Check for deleted property if property can actually be deleted.
-  if (!is_dont_delete) {
+  if (is_configurable) {
     __ cmp(result, factory()->the_hole_value());
     __ j(equal, &miss);
   } else if (FLAG_debug_code) {
=======================================
--- /branches/bleeding_edge/src/ic.cc   Wed Jul 30 12:01:48 2014 UTC
+++ /branches/bleeding_edge/src/ic.cc   Mon Aug  4 08:34:56 2014 UTC
@@ -188,11 +188,6 @@
   ASSERT(original_code->IsCode());
   return original_code;
 }
-
-
-static bool HasInterceptorGetter(JSObject* object) {
-  return !object->GetNamedInterceptor()->getter()->IsUndefined();
-}


 static bool HasInterceptorSetter(JSObject* object) {
@@ -200,38 +195,27 @@
 }


-static void LookupForRead(Handle<Object> object,
-                          Handle<String> name,
-                          LookupResult* lookup) {
-  // Skip all the objects with named interceptors, but
-  // without actual getter.
-  while (true) {
-    object->Lookup(name, lookup);
-    // Besides normal conditions (property not found or it's not
-    // an interceptor), bail out if lookup is not cacheable: we won't
-    // be able to IC it anyway and regular lookup should work fine.
-    if (!lookup->IsInterceptor() || !lookup->IsCacheable()) {
-      return;
-    }
-
-    Handle<JSObject> holder(lookup->holder(), lookup->isolate());
-    if (HasInterceptorGetter(*holder)) {
-      return;
-    }
-
-    holder->LookupOwnRealNamedProperty(name, lookup);
-    if (lookup->IsFound()) {
-      ASSERT(!lookup->IsInterceptor());
-      return;
-    }
-
-    PrototypeIterator iter(lookup->isolate(), holder);
-    if (iter.IsAtEnd()) {
-      ASSERT(!lookup->IsFound());
-      return;
+static void LookupForRead(LookupIterator* it) {
+  for (; it->IsFound(); it->Next()) {
+    switch (it->state()) {
+      case LookupIterator::NOT_FOUND:
+        UNREACHABLE();
+      case LookupIterator::JSPROXY:
+        return;
+      case LookupIterator::INTERCEPTOR: {
+ // If there is a getter, return; otherwise loop to perform the lookup.
+        Handle<JSObject> holder = it->GetHolder<JSObject>();
+        if (!holder->GetNamedInterceptor()->getter()->IsUndefined()) {
+          return;
+        }
+        break;
+      }
+      case LookupIterator::ACCESS_CHECK:
+        return;
+      case LookupIterator::PROPERTY:
+        if (it->HasProperty()) return;  // Yay!
+        break;
     }
-
-    object = PrototypeIterator::GetCurrent(iter);
   }
 }

@@ -574,11 +558,11 @@
   bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;

   // Named lookup in the object.
-  LookupResult lookup(isolate());
-  LookupForRead(object, name, &lookup);
+  LookupIterator it(object, name);
+  LookupForRead(&it);

   // If we did not find a property, check if we need to throw an exception.
-  if (!lookup.IsFound()) {
+  if (!it.IsFound()) {
     if (IsUndeclaredGlobal(object)) {
       return ReferenceError("not_defined", name);
     }
@@ -586,16 +570,14 @@
   }

   // Update inline cache and stub cache.
-  if (use_ic) UpdateCaches(&lookup, object, name);
+  if (use_ic) UpdateCaches(&it, object, name);

   // Get the property.
-  LookupIterator it(object, name);
   Handle<Object> result;
   ASSIGN_RETURN_ON_EXCEPTION(
       isolate(), result, Object::GetProperty(&it), Object);
// If the property is not present, check if we need to throw an exception.
-  if ((lookup.IsInterceptor() || lookup.IsHandler()) &&
-      !it.IsFound() && IsUndeclaredGlobal(object)) {
+  if (!it.IsFound() && IsUndeclaredGlobal(object)) {
     return ReferenceError("not_defined", name);
   }

@@ -828,8 +810,7 @@
 }


-void LoadIC::UpdateCaches(LookupResult* lookup,
-                          Handle<Object> object,
+void LoadIC::UpdateCaches(LookupIterator* lookup, Handle<Object> object,
                           Handle<String> name) {
   if (state() == UNINITIALIZED) {
     // This is the first time we execute this inline cache.
@@ -841,10 +822,10 @@
   }

   Handle<Code> code;
-  if (!lookup->IsCacheable()) {
-    // Bail out if the result is not cacheable.
+  if (lookup->state() == LookupIterator::JSPROXY ||
+      lookup->state() == LookupIterator::ACCESS_CHECK) {
     code = slow_stub();
-  } else if (!lookup->IsProperty()) {
+  } else if (!lookup->IsFound()) {
     if (kind() == Code::LOAD_IC) {
       code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(name,
receiver_type());
@@ -869,10 +850,53 @@
 }


-Handle<Code> IC::ComputeHandler(LookupResult* lookup,
-                                Handle<Object> object,
-                                Handle<String> name,
-                                Handle<Object> value) {
+Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> object, + Handle<String> name, Handle<Object> value) {
+  bool receiver_is_holder =
+      object.is_identical_to(lookup->GetHolder<JSObject>());
+  CacheHolderFlag flag;
+  Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder(
+      *receiver_type(), receiver_is_holder, isolate(), &flag);
+
+  Handle<Code> code = PropertyHandlerCompiler::Find(
+      name, stub_holder_map, kind(), flag,
+ lookup->holder_map()->is_dictionary_map() ? Code::NORMAL : Code::FAST);
+  // Use the cached value if it exists, and if it is different from the
+  // handler that just missed.
+  if (!code.is_null()) {
+    if (!maybe_handler_.is_null() &&
+        !maybe_handler_.ToHandleChecked().is_identical_to(code)) {
+      return code;
+    }
+    if (maybe_handler_.is_null()) {
+ // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs.
+      // In MEGAMORPHIC case, check if the handler in the megamorphic stub
+      // cache (which just missed) is different from the cached handler.
+      if (state() == MEGAMORPHIC && object->IsHeapObject()) {
+        Map* map = Handle<HeapObject>::cast(object)->map();
+        Code* megamorphic_cached_code =
+            isolate()->stub_cache()->Get(*name, map, code->flags());
+        if (megamorphic_cached_code != *code) return code;
+      } else {
+        return code;
+      }
+    }
+  }
+
+  code = CompileHandler(lookup, object, name, value, flag);
+  ASSERT(code->is_handler());
+
+  if (code->type() != Code::NORMAL) {
+    Map::UpdateCodeCache(stub_holder_map, name, code);
+  }
+
+  return code;
+}
+
+
+Handle<Code> IC::ComputeStoreHandler(LookupResult* lookup,
+ Handle<Object> object, Handle<String> name,
+                                     Handle<Object> value) {
   bool receiver_is_holder = lookup->ReceiverIsHolder(object);
   CacheHolderFlag flag;
   Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder(
@@ -903,7 +927,7 @@
     }
   }

-  code = CompileHandler(lookup, object, name, value, flag);
+  code = CompileStoreHandler(lookup, object, name, value, flag);
   ASSERT(code->is_handler());

   if (code->type() != Code::NORMAL) {
@@ -914,8 +938,9 @@
 }


-Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, Handle<Object> object, - Handle<String> name, Handle<Object> unused,
+Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
+ Handle<Object> object, Handle<String> name,
+                                    Handle<Object> unused,
                                     CacheHolderFlag cache_holder) {
   if (object->IsString() &&
       String::Equals(isolate()->factory()->length_string(), name)) {
@@ -940,102 +965,107 @@
   }

   Handle<HeapType> type = receiver_type();
-  Handle<JSObject> holder(lookup->holder());
+  Handle<JSObject> holder = lookup->GetHolder<JSObject>();
   bool receiver_is_holder = object.is_identical_to(holder);
   NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
                                     cache_holder);

-  switch (lookup->type()) {
-    case FIELD: {
-      FieldIndex field = lookup->GetFieldIndex();
-      if (receiver_is_holder) {
-        return SimpleFieldLoad(field);
+  // -------------- Interceptors --------------
+  if (lookup->state() == LookupIterator::INTERCEPTOR) {
+    ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
+    return compiler.CompileLoadInterceptor(name);
+  }
+  ASSERT(lookup->state() == LookupIterator::PROPERTY);
+
+  // -------------- Accessors --------------
+  if (lookup->property_kind() == LookupIterator::ACCESSOR) {
+    // Use simple field loads for some well-known callback properties.
+    if (receiver_is_holder) {
+      ASSERT(object->IsJSObject());
+      Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+      int object_offset;
+      if (Accessors::IsJSObjectFieldAccessor<HeapType>(type, name,
+                                                       &object_offset)) {
+        FieldIndex index =
+            FieldIndex::ForInObjectOffset(object_offset, receiver->map());
+        return SimpleFieldLoad(index);
       }
- return compiler.CompileLoadField(name, field, lookup->representation());
     }
-    case CONSTANT: {
-      Handle<Object> constant(lookup->GetConstant(), isolate());
-      return compiler.CompileLoadConstant(name, constant);
+
+    Handle<Object> accessors = lookup->GetAccessors();
+    if (accessors->IsExecutableAccessorInfo()) {
+      Handle<ExecutableAccessorInfo> info =
+          Handle<ExecutableAccessorInfo>::cast(accessors);
+      if (v8::ToCData<Address>(info->getter()) == 0) return slow_stub();
+ if (!ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), info,
+                                                            type)) {
+        return slow_stub();
+      }
+      if (holder->IsGlobalObject()) return slow_stub();
+      return compiler.CompileLoadCallback(name, info);
     }
-    case NORMAL:
-      if (kind() != Code::LOAD_IC) break;
-      if (holder->IsGlobalObject()) {
-        Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
-        Handle<PropertyCell> cell(
-            global->GetPropertyCell(lookup), isolate());
-        Handle<Code> code =
-            compiler.CompileLoadGlobal(cell, name, lookup->IsDontDelete());
- // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
-        CacheHolderFlag flag;
-        Handle<Map> stub_holder_map =
- GetHandlerCacheHolder(*type, receiver_is_holder, isolate(), &flag);
-        Map::UpdateCodeCache(stub_holder_map, name, code);
-        return code;
+    if (accessors->IsAccessorPair()) {
+ Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
+                            isolate());
+      if (!getter->IsJSFunction()) return slow_stub();
+      if (holder->IsGlobalObject()) return slow_stub();
+      if (!holder->HasFastProperties()) return slow_stub();
+      Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
+      if (!object->IsJSObject() && !function->IsBuiltin() &&
+          function->shared()->strict_mode() == SLOPPY) {
+        // Calling sloppy non-builtins with a value as the receiver
+        // requires boxing.
+        return slow_stub();
       }
-      // There is only one shared stub for loading normalized
-      // properties. It does not traverse the prototype chain, so the
-      // property must be found in the object for the stub to be
-      // applicable.
-      if (!receiver_is_holder) break;
-      return isolate()->builtins()->LoadIC_Normal();
-    case CALLBACKS: {
-      // Use simple field loads for some well-known callback properties.
-      if (receiver_is_holder) {
-        ASSERT(object->IsJSObject());
-        Handle<JSObject> receiver = Handle<JSObject>::cast(object);
-        int object_offset;
-        if (Accessors::IsJSObjectFieldAccessor<HeapType>(
-                type, name, &object_offset)) {
-          FieldIndex index = FieldIndex::ForInObjectOffset(
-              object_offset, receiver->map());
-          return SimpleFieldLoad(index);
-        }
+      CallOptimization call_optimization(function);
+      if (call_optimization.is_simple_api_call() &&
+          call_optimization.IsCompatibleReceiver(object, holder)) {
+        return compiler.CompileLoadCallback(name, call_optimization);
       }
+      return compiler.CompileLoadViaGetter(name, function);
+    }
+    // TODO(dcarney): Handle correctly.
+    ASSERT(accessors->IsDeclaredAccessorInfo());
+    return slow_stub();
+  }

-      Handle<Object> callback(lookup->GetCallbackObject(), isolate());
-      if (callback->IsExecutableAccessorInfo()) {
-        Handle<ExecutableAccessorInfo> info =
-            Handle<ExecutableAccessorInfo>::cast(callback);
-        if (v8::ToCData<Address>(info->getter()) == 0) break;
- if (!ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), info,
-                                                              type)) {
-          break;
-        }
-        if (holder->IsGlobalObject()) break;
-        return compiler.CompileLoadCallback(name, info);
-      } else if (callback->IsAccessorPair()) {
- Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(),
-                              isolate());
-        if (!getter->IsJSFunction()) break;
-        if (holder->IsGlobalObject()) break;
-        if (!holder->HasFastProperties()) break;
-        Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
-        if (!object->IsJSObject() &&
-            !function->IsBuiltin() &&
-            function->shared()->strict_mode() == SLOPPY) {
-          // Calling sloppy non-builtins with a value as the receiver
-          // requires boxing.
-          break;
-        }
-        CallOptimization call_optimization(function);
-        if (call_optimization.is_simple_api_call() &&
-            call_optimization.IsCompatibleReceiver(object, holder)) {
-          return compiler.CompileLoadCallback(name, call_optimization);
-        }
-        return compiler.CompileLoadViaGetter(name, function);
-      }
-      // TODO(dcarney): Handle correctly.
-      ASSERT(callback->IsDeclaredAccessorInfo());
-      break;
+  // -------------- Dictionary properties --------------
+  ASSERT(lookup->property_kind() == LookupIterator::DATA);
+  if (lookup->property_encoding() == LookupIterator::DICTIONARY) {
+    if (kind() != Code::LOAD_IC) return slow_stub();
+    if (holder->IsGlobalObject()) {
+      Handle<PropertyCell> cell = lookup->GetPropertyCell();
+      Handle<Code> code =
+          compiler.CompileLoadGlobal(cell, name, lookup->IsConfigurable());
+ // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
+      CacheHolderFlag flag;
+      Handle<Map> stub_holder_map =
+ GetHandlerCacheHolder(*type, receiver_is_holder, isolate(), &flag);
+      Map::UpdateCodeCache(stub_holder_map, name, code);
+      return code;
+    }
+    // There is only one shared stub for loading normalized
+    // properties. It does not traverse the prototype chain, so the
+    // property must be found in the object for the stub to be
+    // applicable.
+    if (!receiver_is_holder) return slow_stub();
+    return isolate()->builtins()->LoadIC_Normal();
+  }
+
+  // -------------- Fields --------------
+  ASSERT(lookup->property_encoding() == LookupIterator::DESCRIPTOR);
+  if (lookup->property_details().type() == FIELD) {
+    FieldIndex field = lookup->GetFieldIndex();
+    if (receiver_is_holder) {
+      return SimpleFieldLoad(field);
     }
-    case INTERCEPTOR:
-      ASSERT(HasInterceptorGetter(*holder));
-      return compiler.CompileLoadInterceptor(name);
-    default:
-      break;
+ return compiler.CompileLoadField(name, field, lookup->representation());
   }

-  return slow_stub();
+  // -------------- Constant properties --------------
+  ASSERT(lookup->property_details().type() == CONSTANT);
+  Handle<Object> constant = lookup->GetDataValue();
+  return compiler.CompileLoadConstant(name, constant);
 }


@@ -1377,17 +1407,18 @@
   // These are not cacheable, so we never see such LookupResults here.
   ASSERT(!lookup->IsHandler());

-  Handle<Code> code = ComputeHandler(lookup, receiver, name, value);
+  Handle<Code> code = ComputeStoreHandler(lookup, receiver, name, value);

   PatchCache(name, code);
   TRACE_IC("StoreIC", name);
 }


-Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
- Handle<Object> object, Handle<String> name,
-                                     Handle<Object> value,
-                                     CacheHolderFlag cache_holder) {
+Handle<Code> StoreIC::CompileStoreHandler(LookupResult* lookup,
+                                          Handle<Object> object,
+                                          Handle<String> name,
+                                          Handle<Object> value,
+                                          CacheHolderFlag cache_holder) {
   if (object->IsAccessCheckNeeded()) return slow_stub();
   ASSERT(cache_holder == kCacheOnReceiver || lookup->type() == CALLBACKS ||
(object->IsJSGlobalProxy() && lookup->holder()->IsJSGlobalObject()));
=======================================
--- /branches/bleeding_edge/src/ic.h    Wed Jul 30 12:21:41 2014 UTC
+++ /branches/bleeding_edge/src/ic.h    Mon Aug  4 08:34:56 2014 UTC
@@ -179,17 +179,29 @@
static void PostPatching(Address address, Code* target, Code* old_target);

// Compute the handler either by compiling or by retrieving a cached version.
-  Handle<Code> ComputeHandler(LookupResult* lookup,
-                              Handle<Object> object,
+ Handle<Code> ComputeHandler(LookupIterator* lookup, Handle<Object> object,
                               Handle<String> name,
                               Handle<Object> value = Handle<Code>::null());
-  virtual Handle<Code> CompileHandler(LookupResult* lookup,
+  virtual Handle<Code> CompileHandler(LookupIterator* lookup,
                                       Handle<Object> object,
Handle<String> name, Handle<Object> value,
                                       CacheHolderFlag cache_holder) {
     UNREACHABLE();
     return Handle<Code>::null();
   }
+  // Temporary copy of the above, but using a LookupResult.
+  // TODO(jkummerow): Migrate callers to LookupIterator and delete these.
+ Handle<Code> ComputeStoreHandler(LookupResult* lookup, Handle<Object> object,
+                                   Handle<String> name,
+ Handle<Object> value = Handle<Code>::null());
+  virtual Handle<Code> CompileStoreHandler(LookupResult* lookup,
+                                           Handle<Object> object,
+                                           Handle<String> name,
+                                           Handle<Object> value,
+                                           CacheHolderFlag cache_holder) {
+    UNREACHABLE();
+    return Handle<Code>::null();
+  }

   void UpdateMonomorphicIC(Handle<Code> handler, Handle<String> name);
   bool UpdatePolymorphicIC(Handle<String> name, Handle<Code> code);
@@ -474,11 +486,10 @@

   // Update the inline cache and the global stub cache based on the
   // lookup result.
-  void UpdateCaches(LookupResult* lookup,
-                    Handle<Object> object,
+  void UpdateCaches(LookupIterator* lookup, Handle<Object> object,
                     Handle<String> name);

-  virtual Handle<Code> CompileHandler(LookupResult* lookup,
+  virtual Handle<Code> CompileHandler(LookupIterator* lookup,
                                       Handle<Object> object,
                                       Handle<String> name,
                                       Handle<Object> unused,
@@ -638,10 +649,11 @@
                     Handle<JSObject> receiver,
                     Handle<String> name,
                     Handle<Object> value);
-  virtual Handle<Code> CompileHandler(LookupResult* lookup,
-                                      Handle<Object> object,
- Handle<String> name, Handle<Object> value,
-                                      CacheHolderFlag cache_holder);
+  virtual Handle<Code> CompileStoreHandler(LookupResult* lookup,
+                                           Handle<Object> object,
+                                           Handle<String> name,
+                                           Handle<Object> value,
+                                           CacheHolderFlag cache_holder);

  private:
   void set_target(Code* code) {
=======================================
--- /branches/bleeding_edge/src/lookup.cc       Thu Jul 24 11:33:46 2014 UTC
+++ /branches/bleeding_edge/src/lookup.cc       Mon Aug  4 08:34:56 2014 UTC
@@ -120,8 +120,9 @@
       return false;
     }
   } else {
-    property_details_ = holder_map_->instance_descriptors()->GetDetails(
-        number_);
+ // Can't use descriptor_number() yet because has_property_ is still false.
+    property_details_ =
+        holder_map_->instance_descriptors()->GetDetails(number_);
   }

   switch (property_details_.type()) {
@@ -146,9 +147,10 @@

 void LookupIterator::PrepareForDataProperty(Handle<Object> value) {
   ASSERT(has_property_);
-  ASSERT(HolderIsReceiver());
+  ASSERT(HolderIsReceiverOrHiddenPrototype());
   if (property_encoding_ == DICTIONARY) return;
-  holder_map_ = Map::PrepareForDataProperty(holder_map_, number_, value);
+  holder_map_ =
+      Map::PrepareForDataProperty(holder_map_, descriptor_number(), value);
   JSObject::MigrateToMap(GetHolder<JSObject>(), holder_map_);
   // Reload property information.
   if (holder_map_->is_dictionary_map()) {
@@ -163,7 +165,7 @@
 void LookupIterator::TransitionToDataProperty(
     Handle<Object> value, PropertyAttributes attributes,
     Object::StoreFromKeyed store_mode) {
-  ASSERT(!has_property_ || !HolderIsReceiver());
+  ASSERT(!has_property_ || !HolderIsReceiverOrHiddenPrototype());

   // Can only be called when the receiver is a JSObject. JSProxy has to be
   // handled via a trap. Adding properties to primitive values is not
@@ -194,7 +196,7 @@
 }


-bool LookupIterator::HolderIsReceiver() const {
+bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const {
   ASSERT(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
   DisallowHeapAllocation no_gc;
   Handle<Object> receiver = GetReceiver();
@@ -228,8 +230,8 @@
       break;
     case DESCRIPTOR:
       if (property_details_.type() == v8::internal::FIELD) {
-        FieldIndex field_index = FieldIndex::ForDescriptor(
-            *holder_map_, number_);
+        FieldIndex field_index =
+            FieldIndex::ForDescriptor(*holder_map_, number_);
         return JSObject::FastPropertyAt(
             holder, property_details_.representation(), field_index);
       }
@@ -237,6 +239,23 @@
   }
   return handle(result, isolate_);
 }
+
+
+FieldIndex LookupIterator::GetFieldIndex() const {
+  ASSERT_EQ(PROPERTY, state_);
+  int index =
+ holder_map()->instance_descriptors()->GetFieldIndex(descriptor_number());
+  bool is_double = representation().IsDouble();
+  return FieldIndex::ForPropertyIndex(*holder_map(), index, is_double);
+}
+
+
+Handle<PropertyCell> LookupIterator::GetPropertyCell() const {
+  Handle<JSObject> holder = GetHolder<JSObject>();
+  Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
+ Object* value = global->property_dictionary()->ValueAt(dictionary_entry());
+  return Handle<PropertyCell>(PropertyCell::cast(value));
+}


 Handle<Object> LookupIterator::GetAccessors() const {
@@ -262,13 +281,13 @@
     NameDictionary* property_dictionary = holder->property_dictionary();
     if (holder->IsGlobalObject()) {
       Handle<PropertyCell> cell(
-          PropertyCell::cast(property_dictionary->ValueAt(number_)));
+ PropertyCell::cast(property_dictionary->ValueAt(dictionary_entry())));
       PropertyCell::SetValueInferType(cell, value);
     } else {
-      property_dictionary->ValueAtPut(number_, *value);
+      property_dictionary->ValueAtPut(dictionary_entry(), *value);
     }
   } else if (property_details_.type() == v8::internal::FIELD) {
-    holder->WriteToField(number_, *value);
+    holder->WriteToField(descriptor_number(), *value);
   } else {
     ASSERT_EQ(v8::internal::CONSTANT, property_details_.type());
   }
=======================================
--- /branches/bleeding_edge/src/lookup.h        Thu Jul 24 11:33:46 2014 UTC
+++ /branches/bleeding_edge/src/lookup.h        Mon Aug  4 08:34:56 2014 UTC
@@ -99,7 +99,7 @@
     return Handle<T>::cast(maybe_holder_.ToHandleChecked());
   }
   Handle<JSReceiver> GetRoot() const;
-  bool HolderIsReceiver() const;
+  bool HolderIsReceiverOrHiddenPrototype() const;

   /* Dynamically reduce the trapped types. */
   void skip_interceptor() {
@@ -127,15 +127,20 @@
     ASSERT(has_property_);
     return property_kind_;
   }
+  PropertyEncoding property_encoding() const {
+    ASSERT(has_property_);
+    return property_encoding_;
+  }
   PropertyDetails property_details() const {
     ASSERT(has_property_);
     return property_details_;
   }
-  int descriptor_number() const {
-    ASSERT(has_property_);
-    ASSERT_EQ(DESCRIPTOR, property_encoding_);
-    return number_;
+ bool IsConfigurable() const { return !property_details().IsDontDelete(); }
+  Representation representation() const {
+    return property_details().representation();
   }
+  FieldIndex GetFieldIndex() const;
+  Handle<PropertyCell> GetPropertyCell() const;
   Handle<Object> GetAccessors() const;
   Handle<Object> GetDataValue() const;
   void WriteDataValue(Handle<Object> value);
@@ -170,6 +175,16 @@
   bool check_access_check() const {
     return (configuration_ & CHECK_ACCESS_CHECK) != 0;
   }
+  int descriptor_number() const {
+    ASSERT(has_property_);
+    ASSERT_EQ(DESCRIPTOR, property_encoding_);
+    return number_;
+  }
+  int dictionary_entry() const {
+    ASSERT(has_property_);
+    ASSERT_EQ(DICTIONARY, property_encoding_);
+    return number_;
+  }

   Configuration configuration_;
   State state_;
=======================================
--- /branches/bleeding_edge/src/mips/stub-cache-mips.cc Wed Jul 30 17:46:10 2014 UTC +++ /branches/bleeding_edge/src/mips/stub-cache-mips.cc Mon Aug 4 08:34:56 2014 UTC
@@ -1210,7 +1210,7 @@


 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
-    Handle<PropertyCell> cell, Handle<Name> name, bool is_dont_delete) {
+    Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
   Label miss;

   FrontendHeader(receiver(), name, &miss);
@@ -1221,7 +1221,7 @@
   __ lw(result, FieldMemOperand(result, Cell::kValueOffset));

   // Check for deleted property if property can actually be deleted.
-  if (!is_dont_delete) {
+  if (is_configurable) {
     __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
     __ Branch(&miss, eq, result, Operand(at));
   }
=======================================
--- /branches/bleeding_edge/src/mips64/stub-cache-mips64.cc Wed Jul 30 17:46:10 2014 UTC +++ /branches/bleeding_edge/src/mips64/stub-cache-mips64.cc Mon Aug 4 08:34:56 2014 UTC
@@ -1211,7 +1211,7 @@


 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
-    Handle<PropertyCell> cell, Handle<Name> name, bool is_dont_delete) {
+    Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
   Label miss;

   FrontendHeader(receiver(), name, &miss);
@@ -1222,7 +1222,7 @@
   __ ld(result, FieldMemOperand(result, Cell::kValueOffset));

   // Check for deleted property if property can actually be deleted.
-  if (!is_dont_delete) {
+  if (is_configurable) {
     __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
     __ Branch(&miss, eq, result, Operand(at));
   }
=======================================
--- /branches/bleeding_edge/src/objects.cc      Wed Jul 30 13:54:45 2014 UTC
+++ /branches/bleeding_edge/src/objects.cc      Mon Aug  4 08:34:56 2014 UTC
@@ -3011,7 +3011,7 @@
                                                           strict_mode);

       case LookupIterator::JSPROXY:
-        if (it->HolderIsReceiver()) {
+        if (it->HolderIsReceiverOrHiddenPrototype()) {
           return JSProxy::SetPropertyWithHandler(it->GetHolder<JSProxy>(),
it->GetReceiver(), it->name(),
                                                  value, strict_mode);
@@ -3028,7 +3028,7 @@
         break;

       case LookupIterator::INTERCEPTOR:
-        if (it->HolderIsReceiver()) {
+        if (it->HolderIsReceiverOrHiddenPrototype()) {
           MaybeHandle<Object> maybe_result =
               JSObject::SetPropertyWithInterceptor(it, value);
           if (!maybe_result.is_null()) return maybe_result;
@@ -3052,7 +3052,7 @@
         }
         switch (it->property_kind()) {
           case LookupIterator::ACCESSOR:
-            if (it->HolderIsReceiver() ||
+            if (it->HolderIsReceiverOrHiddenPrototype() ||
                 !it->GetAccessors()->IsDeclaredAccessorInfo()) {
               return SetPropertyWithAccessor(it->GetReceiver(), it->name(),
value, it->GetHolder<JSObject>(),
@@ -3060,7 +3060,9 @@
             }
             break;
           case LookupIterator::DATA:
-            if (it->HolderIsReceiver()) return SetDataProperty(it, value);
+            if (it->HolderIsReceiverOrHiddenPrototype()) {
+              return SetDataProperty(it, value);
+            }
         }
         done = true;
         break;
@@ -3092,7 +3094,7 @@
   Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());

   // Store on the holder which may be hidden behind the receiver.
-  ASSERT(it->HolderIsReceiver());
+  ASSERT(it->HolderIsReceiverOrHiddenPrototype());

   // Old value for the observation change record.
   // Fetch before transforming the object since the encoding may become
=======================================
--- /branches/bleeding_edge/src/stub-cache.h    Wed Jul 30 12:01:48 2014 UTC
+++ /branches/bleeding_edge/src/stub-cache.h    Mon Aug  4 08:34:56 2014 UTC
@@ -478,7 +478,7 @@
                                     Handle<JSFunction> getter);

Handle<Code> CompileLoadGlobal(Handle<PropertyCell> cell, Handle<Name> name,
-                                 bool is_dont_delete);
+                                 bool is_configurable);

   // Static interface
   static Handle<Code> ComputeLoadNonexistent(Handle<Name> name,
=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Wed Jul 30 12:21:41 2014 UTC +++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Mon Aug 4 08:34:56 2014 UTC
@@ -1180,7 +1180,7 @@


 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
-    Handle<PropertyCell> cell, Handle<Name> name, bool is_dont_delete) {
+    Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
   Label miss;
   FrontendHeader(receiver(), name, &miss);

@@ -1190,7 +1190,7 @@
   __ movp(result, FieldOperand(result, PropertyCell::kValueOffset));

   // Check for deleted property if property can actually be deleted.
-  if (!is_dont_delete) {
+  if (is_configurable) {
     __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
     __ j(equal, &miss);
   } else if (FLAG_debug_code) {
=======================================
--- /branches/bleeding_edge/src/x87/stub-cache-x87.cc Fri Aug 1 01:58:56 2014 UTC +++ /branches/bleeding_edge/src/x87/stub-cache-x87.cc Mon Aug 4 08:34:56 2014 UTC
@@ -1258,7 +1258,7 @@
   }

   // Check for deleted property if property can actually be deleted.
-  if (!is_dont_delete) {
+  if (is_configurable) {
     __ cmp(result, factory()->the_hole_value());
     __ j(equal, &miss);
   } else if (FLAG_debug_code) {

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