Avoid one repeated property lookup when computing load ICs.
authorjkummerow@chromium.org <jkummerow@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 4 Aug 2014 08:34:56 +0000 (08:34 +0000)
committerjkummerow@chromium.org <jkummerow@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 4 Aug 2014 08:34:56 +0000 (08:34 +0000)
R=verwaest@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22802 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

13 files changed:
src/arm/stub-cache-arm.cc
src/arm64/stub-cache-arm64.cc
src/ia32/stub-cache-ia32.cc
src/ic.cc
src/ic.h
src/lookup.cc
src/lookup.h
src/mips/stub-cache-mips.cc
src/mips64/stub-cache-mips64.cc
src/objects.cc
src/stub-cache.h
src/x64/stub-cache-x64.cc
src/x87/stub-cache-x87.cc

index 70849c0..256d41e 100644 (file)
@@ -1221,7 +1221,7 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
 
 
 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 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
   __ 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);
index 32951e5..cdab29a 100644 (file)
@@ -1195,7 +1195,7 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
 
 
 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 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
   __ 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);
   }
 
index 1f01265..ca25d96 100644 (file)
@@ -1245,7 +1245,7 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
 
 
 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 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
   }
 
   // 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) {
index 1a8366d..0dc62aa 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -190,48 +190,32 @@ Code* IC::GetOriginalCode() const {
 }
 
 
-static bool HasInterceptorGetter(JSObject* object) {
-  return !object->GetNamedInterceptor()->getter()->IsUndefined();
-}
-
-
 static bool HasInterceptorSetter(JSObject* object) {
   return !object->GetNamedInterceptor()->setter()->IsUndefined();
 }
 
 
-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 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<String> name) {
   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 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<String> name) {
   }
 
   // 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 @@ Handle<Code> LoadIC::SimpleFieldLoad(FieldIndex index) {
 }
 
 
-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 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
   }
 
   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 @@ void IC::UpdateMegamorphicCache(HeapType* type, Name* name, Code* code) {
 }
 
 
-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 @@ Handle<Code> IC::ComputeHandler(LookupResult* lookup,
     }
   }
 
-  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> IC::ComputeHandler(LookupResult* lookup,
 }
 
 
-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<Code> LoadIC::CompileHandler(LookupResult* lookup, Handle<Object> object,
   }
 
   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);
       }
-
-      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;
+      return compiler.CompileLoadViaGetter(name, function);
     }
-    case INTERCEPTOR:
-      ASSERT(HasInterceptorGetter(*holder));
-      return compiler.CompileLoadInterceptor(name);
-    default:
-      break;
+    // TODO(dcarney): Handle correctly.
+    ASSERT(accessors->IsDeclaredAccessorInfo());
+    return slow_stub();
+  }
+
+  // -------------- 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);
+    }
+    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 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
   // 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()));
index 4df0c69..3b4b7fd 100644 (file)
--- a/src/ic.h
+++ b/src/ic.h
@@ -179,17 +179,29 @@ class IC {
   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 @@ class LoadIC: public IC {
 
   // 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 @@ class StoreIC: public IC {
                     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) {
index d275890..d1516c0 100644 (file)
@@ -120,8 +120,9 @@ bool LookupIterator::HasProperty() {
       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 @@ bool LookupIterator::HasProperty() {
 
 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::PrepareForDataProperty(Handle<Object> value) {
 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 @@ void LookupIterator::TransitionToDataProperty(
 }
 
 
-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 @@ Handle<Object> LookupIterator::FetchValue() const {
       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);
       }
@@ -239,6 +241,23 @@ Handle<Object> LookupIterator::FetchValue() const {
 }
 
 
+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 {
   ASSERT(has_property_);
   ASSERT_EQ(ACCESSOR, property_kind_);
@@ -262,13 +281,13 @@ void LookupIterator::WriteDataValue(Handle<Object> value) {
     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());
   }
index c96b2d1..5593188 100644 (file)
@@ -99,7 +99,7 @@ class LookupIterator V8_FINAL BASE_EMBEDDED {
     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 @@ class LookupIterator V8_FINAL BASE_EMBEDDED {
     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 @@ class LookupIterator V8_FINAL BASE_EMBEDDED {
   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_;
index e2ab36d..96c7d4d 100644 (file)
@@ -1210,7 +1210,7 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
 
 
 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 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
   __ 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));
   }
index 25e2823..ab89182 100644 (file)
@@ -1211,7 +1211,7 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
 
 
 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 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
   __ 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));
   }
index 4256ba6..4217666 100644 (file)
@@ -3011,7 +3011,7 @@ MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
                                                           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 @@ MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
         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 @@ MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
         }
         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 @@ MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
             }
             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 @@ MaybeHandle<Object> Object::SetDataProperty(LookupIterator* it,
   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
index 1a38361..9cf7d73 100644 (file)
@@ -478,7 +478,7 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
                                     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,
index ddd1bbe..add7b8d 100644 (file)
@@ -1180,7 +1180,7 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
 
 
 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 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
   __ 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) {
index a4c894f..aade4fe 100644 (file)
@@ -1258,7 +1258,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
   }
 
   // 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) {