Rewrite StoreIC handling using the LookupIterator. Continued from patch 494153002
authorverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 22 Aug 2014 11:38:21 +0000 (11:38 +0000)
committerverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 22 Aug 2014 11:38:21 +0000 (11:38 +0000)
BUG=
R=yangguo@chromium.org

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

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

17 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-inl.h
src/lookup.cc
src/lookup.h
src/mips/stub-cache-mips.cc
src/mips64/stub-cache-mips64.cc
src/objects.cc
src/objects.h
src/runtime.cc
src/stub-cache.cc
src/stub-cache.h
src/x64/stub-cache-x64.cc
src/x87/stub-cache-x87.cc

index b3b5674..b870403 100644 (file)
@@ -581,7 +581,7 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
 }
 
 
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupResult* lookup,
+void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
                                                    Register value_reg,
                                                    Label* miss_label) {
   DCHECK(lookup->representation().IsHeapObject());
index 94609e8..b6f4c8a 100644 (file)
@@ -531,7 +531,7 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
 }
 
 
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupResult* lookup,
+void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
                                                    Register value_reg,
                                                    Label* miss_label) {
   DCHECK(lookup->representation().IsHeapObject());
index 75ee53a..da00359 100644 (file)
@@ -568,7 +568,7 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
 }
 
 
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupResult* lookup,
+void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
                                                    Register value_reg,
                                                    Label* miss_label) {
   DCHECK(lookup->representation().IsHeapObject());
index ceed585..4d0b247 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -202,15 +202,11 @@ Code* IC::GetOriginalCode() const {
 }
 
 
-static bool HasInterceptorSetter(JSObject* object) {
-  return !object->GetNamedInterceptor()->setter()->IsUndefined();
-}
-
-
 static void LookupForRead(LookupIterator* it) {
   for (; it->IsFound(); it->Next()) {
     switch (it->state()) {
       case LookupIterator::NOT_FOUND:
+      case LookupIterator::TRANSITION:
         UNREACHABLE();
       case LookupIterator::JSPROXY:
         return;
@@ -302,7 +298,7 @@ bool IC::IsNameCompatibleWithPrototypeFailure(Handle<Object> name) {
 
 
 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
-  receiver_type_ = CurrentTypeOf(receiver, isolate());
+  update_receiver_type(receiver);
   if (!name->IsString()) return;
   if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
   if (receiver->IsUndefined() || receiver->IsNull()) return;
@@ -621,27 +617,22 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
   LookupIterator it(object, name);
   LookupForRead(&it);
 
-  // If we did not find a property, check if we need to throw an exception.
-  if (!it.IsFound()) {
-    if (IsUndeclaredGlobal(object)) {
-      return ReferenceError("not_defined", name);
-    }
-    LOG(isolate(), SuspectReadEvent(*name, *object));
-  }
+  if (it.IsFound() || !IsUndeclaredGlobal(object)) {
+    // Update inline cache and stub cache.
+    if (use_ic) UpdateCaches(&it);
 
-  // Update inline cache and stub cache.
-  if (use_ic) UpdateCaches(&it, object, name);
-
-  // Get the property.
-  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 (!it.IsFound() && IsUndeclaredGlobal(object)) {
-    return ReferenceError("not_defined", name);
+    // Get the property.
+    Handle<Object> result;
+    ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, Object::GetProperty(&it),
+                               Object);
+    if (it.IsFound()) {
+      return result;
+    } else if (!IsUndeclaredGlobal(object)) {
+      LOG(isolate(), SuspectReadEvent(*name, *object));
+      return result;
+    }
   }
-
-  return result;
+  return ReferenceError("not_defined", name);
 }
 
 
@@ -871,14 +862,12 @@ Handle<Code> LoadIC::SimpleFieldLoad(FieldIndex index) {
 }
 
 
-void LoadIC::UpdateCaches(LookupIterator* lookup, Handle<Object> object,
-                          Handle<Name> name) {
+void LoadIC::UpdateCaches(LookupIterator* lookup) {
   if (state() == UNINITIALIZED) {
-    // This is the first time we execute this inline cache.
-    // Set the target to the pre monomorphic stub to delay
-    // setting the monomorphic state.
+    // This is the first time we execute this inline cache. Set the target to
+    // the pre monomorphic stub to delay setting the monomorphic state.
     set_target(*pre_monomorphic_stub());
-    TRACE_IC("LoadIC", name);
+    TRACE_IC("LoadIC", lookup->name());
     return;
   }
 
@@ -888,7 +877,7 @@ void LoadIC::UpdateCaches(LookupIterator* lookup, Handle<Object> object,
     code = slow_stub();
   } else if (!lookup->IsFound()) {
     if (kind() == Code::LOAD_IC) {
-      code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(name,
+      code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(),
                                                               receiver_type());
       // TODO(jkummerow/verwaest): Introduce a builtin that handles this case.
       if (code.is_null()) code = slow_stub();
@@ -896,11 +885,11 @@ void LoadIC::UpdateCaches(LookupIterator* lookup, Handle<Object> object,
       code = slow_stub();
     }
   } else {
-    code = ComputeHandler(lookup, object, name);
+    code = ComputeHandler(lookup);
   }
 
-  PatchCache(name, code);
-  TRACE_IC("LoadIC", name);
+  PatchCache(lookup->name(), code);
+  TRACE_IC("LoadIC", lookup->name());
 }
 
 
@@ -911,16 +900,15 @@ void IC::UpdateMegamorphicCache(HeapType* type, Name* name, Code* code) {
 }
 
 
-Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> object,
-                                Handle<Name> name, Handle<Object> value) {
+Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) {
   bool receiver_is_holder =
-      object.is_identical_to(lookup->GetHolder<JSObject>());
+      lookup->GetReceiver().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->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.
@@ -933,54 +921,10 @@ Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> object,
       // 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);
-  DCHECK(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<Name> name,
-                                     Handle<Object> value) {
-  bool receiver_is_holder = lookup->ReceiverIsHolder(object);
-  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, handler_kind(), flag,
-      lookup->holder()->HasFastProperties() ? Code::FAST : Code::NORMAL);
-  // 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();
+      if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject()) {
+        Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map();
         Code* megamorphic_cached_code =
-            isolate()->stub_cache()->Get(*name, map, code->flags());
+            isolate()->stub_cache()->Get(*lookup->name(), map, code->flags());
         if (megamorphic_cached_code != *code) return code;
       } else {
         return code;
@@ -988,11 +932,11 @@ Handle<Code> IC::ComputeStoreHandler(LookupResult* lookup,
     }
   }
 
-  code = CompileStoreHandler(lookup, object, name, value, flag);
+  code = CompileHandler(lookup, value, flag);
   DCHECK(code->is_handler());
 
   if (code->type() != Code::NORMAL) {
-    Map::UpdateCodeCache(stub_holder_map, name, code);
+    Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
   }
 
   return code;
@@ -1000,26 +944,28 @@ Handle<Code> IC::ComputeStoreHandler(LookupResult* lookup,
 
 
 Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
-                                    Handle<Object> object, Handle<Name> name,
                                     Handle<Object> unused,
                                     CacheHolderFlag cache_holder) {
-  if (object->IsString() &&
-      Name::Equals(isolate()->factory()->length_string(), name)) {
+  Handle<Object> receiver = lookup->GetReceiver();
+  if (receiver->IsString() &&
+      Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
     FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset);
     return SimpleFieldLoad(index);
   }
 
-  if (object->IsStringWrapper() &&
-      Name::Equals(isolate()->factory()->length_string(), name)) {
+  if (receiver->IsStringWrapper() &&
+      Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
     StringLengthStub string_length_stub(isolate());
     return string_length_stub.GetCode();
   }
 
   // Use specialized code for getting prototype of functions.
-  if (object->IsJSFunction() &&
-      Name::Equals(isolate()->factory()->prototype_string(), name) &&
-      Handle<JSFunction>::cast(object)->should_have_prototype() &&
-      !Handle<JSFunction>::cast(object)->map()->has_non_instance_prototype()) {
+  if (receiver->IsJSFunction() &&
+      Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) &&
+      Handle<JSFunction>::cast(receiver)->should_have_prototype() &&
+      !Handle<JSFunction>::cast(receiver)
+           ->map()
+           ->has_non_instance_prototype()) {
     Handle<Code> stub;
     FunctionPrototypeStub function_prototype_stub(isolate());
     return function_prototype_stub.GetCode();
@@ -1027,7 +973,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
 
   Handle<HeapType> type = receiver_type();
   Handle<JSObject> holder = lookup->GetHolder<JSObject>();
-  bool receiver_is_holder = object.is_identical_to(holder);
+  bool receiver_is_holder = receiver.is_identical_to(holder);
   // -------------- Interceptors --------------
   if (lookup->state() == LookupIterator::INTERCEPTOR) {
     DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined());
@@ -1038,21 +984,21 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
     LookupIterator it(lookup);
     it.Next();
     LookupForRead(&it);
-    return compiler.CompileLoadInterceptor(&it, name);
+    return compiler.CompileLoadInterceptor(&it);
   }
-  DCHECK(lookup->state() == LookupIterator::PROPERTY);
 
   // -------------- Accessors --------------
+  DCHECK(lookup->state() == LookupIterator::PROPERTY);
   if (lookup->property_kind() == LookupIterator::ACCESSOR) {
     // Use simple field loads for some well-known callback properties.
     if (receiver_is_holder) {
-      DCHECK(object->IsJSObject());
-      Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+      DCHECK(receiver->IsJSObject());
+      Handle<JSObject> js_receiver = Handle<JSObject>::cast(receiver);
       int object_offset;
-      if (Accessors::IsJSObjectFieldAccessor<HeapType>(type, name,
+      if (Accessors::IsJSObjectFieldAccessor<HeapType>(type, lookup->name(),
                                                        &object_offset)) {
         FieldIndex index =
-            FieldIndex::ForInObjectOffset(object_offset, receiver->map());
+            FieldIndex::ForInObjectOffset(object_offset, js_receiver->map());
         return SimpleFieldLoad(index);
       }
     }
@@ -1069,7 +1015,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
       if (!holder->HasFastProperties()) return slow_stub();
       NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
                                         cache_holder);
-      return compiler.CompileLoadCallback(name, info);
+      return compiler.CompileLoadCallback(lookup->name(), info);
     }
     if (accessors->IsAccessorPair()) {
       Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
@@ -1077,7 +1023,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
       if (!getter->IsJSFunction()) return slow_stub();
       if (!holder->HasFastProperties()) return slow_stub();
       Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
-      if (!object->IsJSObject() && !function->IsBuiltin() &&
+      if (!receiver->IsJSObject() && !function->IsBuiltin() &&
           function->shared()->strict_mode() == SLOPPY) {
         // Calling sloppy non-builtins with a value as the receiver
         // requires boxing.
@@ -1087,10 +1033,10 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
       NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
                                         cache_holder);
       if (call_optimization.is_simple_api_call() &&
-          call_optimization.IsCompatibleReceiver(object, holder)) {
-        return compiler.CompileLoadCallback(name, call_optimization);
+          call_optimization.IsCompatibleReceiver(receiver, holder)) {
+        return compiler.CompileLoadCallback(lookup->name(), call_optimization);
       }
-      return compiler.CompileLoadViaGetter(name, function);
+      return compiler.CompileLoadViaGetter(lookup->name(), function);
     }
     // TODO(dcarney): Handle correctly.
     DCHECK(accessors->IsDeclaredAccessorInfo());
@@ -1105,13 +1051,13 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
       NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
                                         cache_holder);
       Handle<PropertyCell> cell = lookup->GetPropertyCell();
-      Handle<Code> code =
-          compiler.CompileLoadGlobal(cell, name, lookup->IsConfigurable());
+      Handle<Code> code = compiler.CompileLoadGlobal(cell, lookup->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);
+      Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
       return code;
     }
     // There is only one shared stub for loading normalized
@@ -1131,7 +1077,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
     }
     NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
                                       cache_holder);
-    return compiler.CompileLoadField(name, field);
+    return compiler.CompileLoadField(lookup->name(), field);
   }
 
   // -------------- Constant properties --------------
@@ -1142,7 +1088,8 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
   }
   NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
                                     cache_holder);
-  return compiler.CompileLoadConstant(name, lookup->GetConstantIndex());
+  return compiler.CompileLoadConstant(lookup->name(),
+                                      lookup->GetConstantIndex());
 }
 
 
@@ -1284,70 +1231,60 @@ MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
 }
 
 
-static bool LookupForWrite(Handle<Object> object, Handle<Name> name,
-                           Handle<Object> value, LookupResult* lookup, IC* ic) {
+bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
+                             JSReceiver::StoreFromKeyed store_mode) {
   // Disable ICs for non-JSObjects for now.
-  if (!object->IsJSObject()) return false;
-  Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+  Handle<Object> receiver = it->GetReceiver();
+  if (!receiver->IsJSObject()) return false;
+  DCHECK(!Handle<JSObject>::cast(receiver)->map()->is_deprecated());
 
-  Handle<JSObject> holder = receiver;
-  receiver->Lookup(name, lookup);
-  if (lookup->IsFound()) {
-    if (lookup->IsInterceptor() && !HasInterceptorSetter(lookup->holder())) {
-      receiver->LookupOwnRealNamedProperty(name, lookup);
-      if (!lookup->IsFound()) return false;
-    }
+  for (; it->IsFound(); it->Next()) {
+    switch (it->state()) {
+      case LookupIterator::NOT_FOUND:
+      case LookupIterator::TRANSITION:
+        UNREACHABLE();
+      case LookupIterator::JSPROXY:
+        return false;
+      case LookupIterator::INTERCEPTOR: {
+        Handle<JSObject> holder = it->GetHolder<JSObject>();
+        InterceptorInfo* info = holder->GetNamedInterceptor();
+        if (it->HolderIsReceiverOrHiddenPrototype()) {
+          if (!info->setter()->IsUndefined()) return true;
+        } else if (!info->getter()->IsUndefined() ||
+                   !info->query()->IsUndefined()) {
+          return false;
+        }
+        break;
+      }
+      case LookupIterator::ACCESS_CHECK:
+        if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false;
+        break;
+      case LookupIterator::PROPERTY:
+        if (!it->HasProperty()) break;
+        if (it->IsReadOnly()) return false;
+        if (it->property_kind() == LookupIterator::ACCESSOR) return true;
+        if (it->GetHolder<Object>().is_identical_to(receiver)) {
+          it->PrepareForDataProperty(value);
+          // The previous receiver map might just have been deprecated,
+          // so reload it.
+          update_receiver_type(receiver);
+          return true;
+        }
+
+        // Receiver != holder.
+        if (receiver->IsJSGlobalProxy()) {
+          PrototypeIterator iter(it->isolate(), receiver);
+          return it->GetHolder<Object>().is_identical_to(
+              PrototypeIterator::GetCurrent(iter));
+        }
 
-    if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false;
-    if (lookup->holder() == *receiver) return lookup->CanHoldValue(value);
-    if (lookup->IsPropertyCallbacks()) return true;
-    // JSGlobalProxy either stores on the global object in the prototype, or
-    // goes into the runtime if access checks are needed, so this is always
-    // safe.
-    if (receiver->IsJSGlobalProxy()) {
-      PrototypeIterator iter(lookup->isolate(), receiver);
-      return lookup->holder() == *PrototypeIterator::GetCurrent(iter);
+        it->PrepareTransitionToDataProperty(value, NONE, store_mode);
+        return it->IsCacheableTransition();
     }
-    // Currently normal holders in the prototype chain are not supported. They
-    // would require a runtime positive lookup and verification that the details
-    // have not changed.
-    if (lookup->IsInterceptor() || lookup->IsNormal()) return false;
-    holder = Handle<JSObject>(lookup->holder(), lookup->isolate());
-  }
-
-  // While normally LookupTransition gets passed the receiver, in this case we
-  // pass the holder of the property that we overwrite. This keeps the holder in
-  // the LookupResult intact so we can later use it to generate a prototype
-  // chain check. This avoids a double lookup, but requires us to pass in the
-  // receiver when trying to fetch extra information from the transition.
-  receiver->map()->LookupTransition(*holder, *name, lookup);
-  if (!lookup->IsTransition() || lookup->IsReadOnly()) return false;
-
-  // If the value that's being stored does not fit in the field that the
-  // instance would transition to, create a new transition that fits the value.
-  // This has to be done before generating the IC, since that IC will embed the
-  // transition target.
-  // Ensure the instance and its map were migrated before trying to update the
-  // transition target.
-  DCHECK(!receiver->map()->is_deprecated());
-  if (!lookup->CanHoldValue(value)) {
-    Handle<Map> target(lookup->GetTransitionTarget());
-    Representation field_representation = value->OptimalRepresentation();
-    Handle<HeapType> field_type = value->OptimalType(
-        lookup->isolate(), field_representation);
-    Map::GeneralizeRepresentation(
-        target, target->LastAdded(),
-        field_representation, field_type, FORCE_FIELD);
-    // Lookup the transition again since the transition tree may have changed
-    // entirely by the migration above.
-    receiver->map()->LookupTransition(*holder, *name, lookup);
-    if (!lookup->IsTransition()) return false;
-    if (!ic->IsNameCompatibleWithPrototypeFailure(name)) return false;
-    ic->MarkPrototypeFailure(name);
-    return true;
   }
 
-  return true;
+  it->PrepareTransitionToDataProperty(value, NONE, store_mode);
+  return it->IsCacheableTransition();
 }
 
 
@@ -1399,35 +1336,14 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object,
     return result;
   }
 
-  LookupResult lookup(isolate());
-  bool can_store = LookupForWrite(object, name, value, &lookup, this);
-  if (!can_store &&
-      strict_mode() == STRICT &&
-      !(lookup.IsProperty() && lookup.IsReadOnly()) &&
-      object->IsGlobalObject()) {
-    // Strict mode doesn't allow setting non-existent global property.
-    return ReferenceError("not_defined", name);
-  }
-  if (FLAG_use_ic) {
-    if (state() == UNINITIALIZED) {
-      Handle<Code> stub = pre_monomorphic_stub();
-      set_target(*stub);
-      TRACE_IC("StoreIC", name);
-    } else if (can_store) {
-      UpdateCaches(&lookup, Handle<JSObject>::cast(object), name, value);
-    } else if (lookup.IsNormal() ||
-               (lookup.IsField() && lookup.CanHoldValue(value))) {
-      Handle<Code> stub = generic_stub();
-      set_target(*stub);
-    }
-  }
+  LookupIterator it(object, name);
+  if (FLAG_use_ic) UpdateCaches(&it, value, store_mode);
 
   // Set the property.
   Handle<Object> result;
   ASSIGN_RETURN_ON_EXCEPTION(
       isolate(), result,
-      Object::SetProperty(object, name, value, strict_mode(), store_mode),
-      Object);
+      Object::SetProperty(&it, value, strict_mode(), store_mode), Object);
   return result;
 }
 
@@ -1475,133 +1391,127 @@ Handle<Code> StoreIC::pre_monomorphic_stub(Isolate* isolate,
 }
 
 
-void StoreIC::UpdateCaches(LookupResult* lookup,
-                           Handle<JSObject> receiver,
-                           Handle<Name> name,
-                           Handle<Object> value) {
-  DCHECK(lookup->IsFound());
-
-  // These are not cacheable, so we never see such LookupResults here.
-  DCHECK(!lookup->IsHandler());
+void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
+                           JSReceiver::StoreFromKeyed store_mode) {
+  if (state() == UNINITIALIZED) {
+    // This is the first time we execute this inline cache. Set the target to
+    // the pre monomorphic stub to delay setting the monomorphic state.
+    set_target(*pre_monomorphic_stub());
+    TRACE_IC("StoreIC", lookup->name());
+    return;
+  }
 
-  Handle<Code> code = ComputeStoreHandler(lookup, receiver, name, value);
+  Handle<Code> code = LookupForWrite(lookup, value, store_mode)
+                          ? ComputeHandler(lookup, value)
+                          : slow_stub();
 
-  PatchCache(name, code);
-  TRACE_IC("StoreIC", name);
+  PatchCache(lookup->name(), code);
+  TRACE_IC("StoreIC", lookup->name());
 }
 
 
-Handle<Code> StoreIC::CompileStoreHandler(LookupResult* lookup,
-                                          Handle<Object> object,
-                                          Handle<Name> name,
-                                          Handle<Object> value,
-                                          CacheHolderFlag cache_holder) {
-  if (object->IsAccessCheckNeeded()) return slow_stub();
-  DCHECK(cache_holder == kCacheOnReceiver || lookup->type() == CALLBACKS ||
-         (object->IsJSGlobalProxy() && lookup->holder()->IsJSGlobalObject()));
+Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
+                                     Handle<Object> value,
+                                     CacheHolderFlag cache_holder) {
+  DCHECK_NE(LookupIterator::JSPROXY, lookup->state());
+
   // This is currently guaranteed by checks in StoreIC::Store.
-  Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+  Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
+  Handle<JSObject> holder = lookup->GetHolder<JSObject>();
+  DCHECK(!receiver->IsAccessCheckNeeded());
 
-  Handle<JSObject> holder(lookup->holder());
+  // -------------- Transition --------------
+  if (lookup->state() == LookupIterator::TRANSITION) {
+    Handle<Map> transition = lookup->transition_map();
+    // Currently not handled by CompileStoreTransition.
+    if (!holder->HasFastProperties()) return slow_stub();
 
-  if (lookup->IsTransition()) {
-    // Explicitly pass in the receiver map since LookupForWrite may have
-    // stored something else than the receiver in the holder.
-    Handle<Map> transition(lookup->GetTransitionTarget());
-    PropertyDetails details = lookup->GetPropertyDetails();
+    DCHECK(lookup->IsCacheableTransition());
+    NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
+    return compiler.CompileStoreTransition(transition, lookup->name());
+  }
 
-    if (details.type() != CALLBACKS && details.attributes() == NONE &&
-        holder->HasFastProperties()) {
-      NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
-      return compiler.CompileStoreTransition(transition, name);
-    }
-  } else {
-    switch (lookup->type()) {
-      case FIELD: {
-        bool use_stub = true;
-        if (lookup->representation().IsHeapObject()) {
-          // Only use a generic stub if no types need to be tracked.
-          HeapType* field_type = lookup->GetFieldType();
-          HeapType::Iterator<Map> it = field_type->Classes();
-          use_stub = it.Done();
-        }
-        if (use_stub) {
-          StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
-                              lookup->representation());
-          return stub.GetCode();
-        }
-        NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
-        return compiler.CompileStoreField(lookup, name);
-      }
-      case NORMAL:
-        if (receiver->IsJSGlobalProxy() || receiver->IsGlobalObject()) {
-          // The stub generated for the global object picks the value directly
-          // from the property cell. So the property must be directly on the
-          // global object.
-          PrototypeIterator iter(isolate(), receiver);
-          Handle<GlobalObject> global =
-              receiver->IsJSGlobalProxy()
-                  ? Handle<GlobalObject>::cast(
-                        PrototypeIterator::GetCurrent(iter))
-                  : Handle<GlobalObject>::cast(receiver);
-          Handle<PropertyCell> cell(global->GetPropertyCell(lookup), isolate());
-          Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value);
-          StoreGlobalStub stub(
-              isolate(), union_type->IsConstant(), receiver->IsJSGlobalProxy());
-          Handle<Code> code = stub.GetCodeCopyFromTemplate(global, cell);
-          // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
-          HeapObject::UpdateMapCodeCache(receiver, name, code);
-          return code;
-        }
-        DCHECK(holder.is_identical_to(receiver));
-        return isolate()->builtins()->StoreIC_Normal();
-      case CALLBACKS: {
-        if (!holder->HasFastProperties()) break;
-        Handle<Object> callback(lookup->GetValueFromMap(holder->map()),
-                                isolate());
-        if (callback->IsExecutableAccessorInfo()) {
-          Handle<ExecutableAccessorInfo> info =
-              Handle<ExecutableAccessorInfo>::cast(callback);
-          if (v8::ToCData<Address>(info->setter()) == 0) break;
-          if (!ExecutableAccessorInfo::IsCompatibleReceiverType(
-                  isolate(), info, receiver_type())) {
-            break;
-          }
-          NamedStoreHandlerCompiler compiler(isolate(), receiver_type(),
-                                             holder);
-          return compiler.CompileStoreCallback(receiver, name, info);
-        } else if (callback->IsAccessorPair()) {
-          Handle<Object> setter(
-              Handle<AccessorPair>::cast(callback)->setter(), isolate());
-          if (!setter->IsJSFunction()) break;
-          Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
-          CallOptimization call_optimization(function);
-          NamedStoreHandlerCompiler compiler(isolate(), receiver_type(),
-                                             holder);
-          if (call_optimization.is_simple_api_call() &&
-              call_optimization.IsCompatibleReceiver(receiver, holder)) {
-            return compiler.CompileStoreCallback(receiver, name,
-                                                 call_optimization);
-          }
-          return compiler.CompileStoreViaSetter(
-              receiver, name, Handle<JSFunction>::cast(setter));
-        }
-        // TODO(dcarney): Handle correctly.
-        DCHECK(callback->IsDeclaredAccessorInfo());
-        break;
+  // -------------- Interceptors --------------
+  if (lookup->state() == LookupIterator::INTERCEPTOR) {
+    DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined());
+    NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
+    return compiler.CompileStoreInterceptor(lookup->name());
+  }
+
+  // -------------- Accessors --------------
+  DCHECK(lookup->state() == LookupIterator::PROPERTY);
+  if (lookup->property_kind() == LookupIterator::ACCESSOR) {
+    if (!holder->HasFastProperties()) return slow_stub();
+    Handle<Object> accessors = lookup->GetAccessors();
+    if (accessors->IsExecutableAccessorInfo()) {
+      Handle<ExecutableAccessorInfo> info =
+          Handle<ExecutableAccessorInfo>::cast(accessors);
+      if (v8::ToCData<Address>(info->setter()) == 0) return slow_stub();
+      if (!ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), info,
+                                                            receiver_type())) {
+        return slow_stub();
       }
-      case INTERCEPTOR: {
-        DCHECK(HasInterceptorSetter(*holder));
-        NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
-        return compiler.CompileStoreInterceptor(name);
+      NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
+      return compiler.CompileStoreCallback(receiver, lookup->name(), info);
+    } else if (accessors->IsAccessorPair()) {
+      Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
+                            isolate());
+      if (!setter->IsJSFunction()) return slow_stub();
+      Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
+      CallOptimization call_optimization(function);
+      NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
+      if (call_optimization.is_simple_api_call() &&
+          call_optimization.IsCompatibleReceiver(receiver, holder)) {
+        return compiler.CompileStoreCallback(receiver, lookup->name(),
+                                             call_optimization);
       }
-      case CONSTANT:
-        break;
-      case HANDLER:
-        UNREACHABLE();
-        break;
+      return compiler.CompileStoreViaSetter(receiver, lookup->name(),
+                                            Handle<JSFunction>::cast(setter));
     }
+    // TODO(dcarney): Handle correctly.
+    DCHECK(accessors->IsDeclaredAccessorInfo());
+    return slow_stub();
   }
+
+  // -------------- Dictionary properties --------------
+  DCHECK(lookup->property_kind() == LookupIterator::DATA);
+  if (lookup->property_encoding() == LookupIterator::DICTIONARY) {
+    if (holder->IsGlobalObject()) {
+      Handle<PropertyCell> cell = lookup->GetPropertyCell();
+      Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value);
+      StoreGlobalStub stub(isolate(), union_type->IsConstant(),
+                           receiver->IsJSGlobalProxy());
+      Handle<Code> code = stub.GetCodeCopyFromTemplate(
+          Handle<GlobalObject>::cast(holder), cell);
+      // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
+      HeapObject::UpdateMapCodeCache(receiver, lookup->name(), code);
+      return code;
+    }
+    DCHECK(holder.is_identical_to(receiver));
+    return isolate()->builtins()->StoreIC_Normal();
+  }
+
+  // -------------- Fields --------------
+  DCHECK(lookup->property_encoding() == LookupIterator::DESCRIPTOR);
+  if (lookup->property_details().type() == FIELD) {
+    bool use_stub = true;
+    if (lookup->representation().IsHeapObject()) {
+      // Only use a generic stub if no types need to be tracked.
+      Handle<HeapType> field_type = lookup->GetFieldType();
+      HeapType::Iterator<Map> it = field_type->Classes();
+      use_stub = it.Done();
+    }
+    if (use_stub) {
+      StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
+                          lookup->representation());
+      return stub.GetCode();
+    }
+    NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
+    return compiler.CompileStoreField(lookup);
+  }
+
+  // -------------- Constant properties --------------
+  DCHECK(lookup->property_details().type() == CONSTANT);
   return slow_stub();
 }
 
index eb844cf..8d41f80 100644 (file)
--- a/src/ic.h
+++ b/src/ic.h
@@ -183,29 +183,14 @@ 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(LookupIterator* lookup, Handle<Object> object,
-                              Handle<Name> name,
+  Handle<Code> ComputeHandler(LookupIterator* lookup,
                               Handle<Object> value = Handle<Code>::null());
   virtual Handle<Code> CompileHandler(LookupIterator* lookup,
-                                      Handle<Object> object,
-                                      Handle<Name> name, Handle<Object> value,
+                                      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<Name> name,
-                                   Handle<Object> value = Handle<Code>::null());
-  virtual Handle<Code> CompileStoreHandler(LookupResult* lookup,
-                                           Handle<Object> object,
-                                           Handle<Name> name,
-                                           Handle<Object> value,
-                                           CacheHolderFlag cache_holder) {
-    UNREACHABLE();
-    return Handle<Code>::null();
-  }
 
   void UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name);
   bool UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code);
@@ -235,6 +220,9 @@ class IC {
   }
 
   Handle<HeapType> receiver_type() { return receiver_type_; }
+  void update_receiver_type(Handle<Object> receiver) {
+    receiver_type_ = CurrentTypeOf(receiver, isolate_);
+  }
 
   void TargetMaps(MapHandleList* list) {
     FindTargetMaps();
@@ -493,12 +481,9 @@ class LoadIC: public IC {
 
   // Update the inline cache and the global stub cache based on the
   // lookup result.
-  void UpdateCaches(LookupIterator* lookup, Handle<Object> object,
-                    Handle<Name> name);
+  void UpdateCaches(LookupIterator* lookup);
 
   virtual Handle<Code> CompileHandler(LookupIterator* lookup,
-                                      Handle<Object> object,
-                                      Handle<Name> name,
                                       Handle<Object> unused,
                                       CacheHolderFlag cache_holder);
 
@@ -633,6 +618,9 @@ class StoreIC: public IC {
       JSReceiver::StoreFromKeyed store_mode =
           JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED);
 
+  bool LookupForWrite(LookupIterator* it, Handle<Object> value,
+                      JSReceiver::StoreFromKeyed store_mode);
+
  protected:
   virtual Handle<Code> megamorphic_stub();
 
@@ -652,15 +640,11 @@ class StoreIC: public IC {
 
   // Update the inline cache and the global stub cache based on the
   // lookup result.
-  void UpdateCaches(LookupResult* lookup,
-                    Handle<JSObject> receiver,
-                    Handle<Name> name,
-                    Handle<Object> value);
-  virtual Handle<Code> CompileStoreHandler(LookupResult* lookup,
-                                           Handle<Object> object,
-                                           Handle<Name> name,
-                                           Handle<Object> value,
-                                           CacheHolderFlag cache_holder);
+  void UpdateCaches(LookupIterator* lookup, Handle<Object> value,
+                    JSReceiver::StoreFromKeyed store_mode);
+  virtual Handle<Code> CompileHandler(LookupIterator* lookup,
+                                      Handle<Object> value,
+                                      CacheHolderFlag cache_holder);
 
  private:
   void set_target(Code* code) {
index 0650997..a32295b 100644 (file)
@@ -61,6 +61,7 @@ LookupIterator::State LookupIterator::LookupInHolder(Map* map) {
     case PROPERTY:
       return NOT_FOUND;
     case JSPROXY:
+    case TRANSITION:
       UNREACHABLE();
   }
   UNREACHABLE();
index 719d4fa..56001c3 100644 (file)
@@ -57,6 +57,18 @@ Handle<Map> LookupIterator::GetReceiverMap() const {
 }
 
 
+Handle<JSObject> LookupIterator::GetStoreTarget() const {
+  Handle<JSObject> receiver = Handle<JSObject>::cast(GetReceiver());
+
+  if (receiver->IsJSGlobalProxy()) {
+    PrototypeIterator iter(isolate(), receiver);
+    if (iter.IsAtEnd()) return receiver;
+    return Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter));
+  }
+  return receiver;
+}
+
+
 bool LookupIterator::IsBootstrapping() const {
   return isolate_->bootstrapper()->IsActive();
 }
@@ -90,6 +102,14 @@ bool LookupIterator::HasProperty() {
         holder_map_->instance_descriptors()->GetDetails(number_);
   }
 
+  LoadPropertyKind();
+
+  has_property_ = true;
+  return true;
+}
+
+
+void LookupIterator::LoadPropertyKind() {
   switch (property_details_.type()) {
     case v8::internal::FIELD:
     case v8::internal::NORMAL:
@@ -103,9 +123,6 @@ bool LookupIterator::HasProperty() {
     case v8::internal::INTERCEPTOR:
       UNREACHABLE();
   }
-
-  has_property_ = true;
-  return true;
 }
 
 
@@ -148,27 +165,37 @@ void LookupIterator::ReconfigureDataProperty(Handle<Object> value,
 }
 
 
-void LookupIterator::TransitionToDataProperty(
+void LookupIterator::PrepareTransitionToDataProperty(
     Handle<Object> value, PropertyAttributes attributes,
     Object::StoreFromKeyed store_mode) {
-  DCHECK(!has_property_ || !HolderIsReceiverOrHiddenPrototype());
+  if (state_ == TRANSITION) return;
+  DCHECK(!has_property_ || property_kind_ != ACCESSOR);
+  DCHECK(!(has_property_ || state_ == JSPROXY) ||
+         !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
   // observable.
-  Handle<JSObject> receiver = Handle<JSObject>::cast(GetReceiver());
+  Handle<JSObject> receiver = GetStoreTarget();
 
-  if (receiver->IsJSGlobalProxy()) {
-    PrototypeIterator iter(isolate(), receiver);
-    receiver =
-        Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter));
+  if (!name().is_identical_to(isolate()->factory()->hidden_string()) &&
+      !receiver->map()->is_extensible()) {
+    return;
   }
 
+  transition_map_ = Map::TransitionToDataProperty(
+      handle(receiver->map()), name_, value, attributes, store_mode);
+  state_ = TRANSITION;
+}
+
+
+void LookupIterator::ApplyTransitionToDataProperty() {
+  DCHECK_EQ(TRANSITION, state_);
+
+  Handle<JSObject> receiver = GetStoreTarget();
   maybe_holder_ = receiver;
-  holder_map_ = Map::TransitionToDataProperty(handle(receiver->map()), name_,
-                                              value, attributes, store_mode);
+  holder_map_ = transition_map_;
   JSObject::MigrateToMap(receiver, holder_map_);
-
   ReloadPropertyInformation();
 }
 
@@ -180,14 +207,7 @@ void LookupIterator::TransitionToAccessorProperty(
   // 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
   // observable.
-  Handle<JSObject> receiver = Handle<JSObject>::cast(GetReceiver());
-
-  if (receiver->IsJSGlobalProxy()) {
-    PrototypeIterator iter(isolate(), receiver);
-    receiver =
-        Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter));
-  }
-
+  Handle<JSObject> receiver = GetStoreTarget();
   maybe_holder_ = receiver;
   holder_map_ = Map::TransitionToAccessorProperty(
       handle(receiver->map()), name_, component, accessor, attributes);
@@ -304,6 +324,16 @@ FieldIndex LookupIterator::GetFieldIndex() const {
 }
 
 
+Handle<HeapType> LookupIterator::GetFieldType() const {
+  DCHECK(has_property_);
+  DCHECK_EQ(DESCRIPTOR, property_encoding_);
+  DCHECK_EQ(v8::internal::FIELD, property_details_.type());
+  return handle(
+      holder_map()->instance_descriptors()->GetFieldType(descriptor_number()),
+      isolate_);
+}
+
+
 Handle<PropertyCell> LookupIterator::GetPropertyCell() const {
   Handle<JSObject> holder = GetHolder<JSObject>();
   Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
index e09eeee..d6fa35b 100644 (file)
@@ -37,6 +37,7 @@ class LookupIterator V8_FINAL BASE_EMBEDDED {
     JSPROXY,
     NOT_FOUND,
     PROPERTY,
+    TRANSITION,
     // Set state_ to BEFORE_PROPERTY to ensure that the next lookup will be a
     // PROPERTY lookup.
     BEFORE_PROPERTY = INTERCEPTOR
@@ -114,7 +115,12 @@ class LookupIterator V8_FINAL BASE_EMBEDDED {
   Handle<Object> GetReceiver() const {
     return maybe_receiver_.ToHandleChecked();
   }
+  Handle<JSObject> GetStoreTarget() const;
   Handle<Map> holder_map() const { return holder_map_; }
+  Handle<Map> transition_map() const {
+    DCHECK_EQ(TRANSITION, state_);
+    return transition_map_;
+  }
   template <class T>
   Handle<T> GetHolder() const {
     DCHECK(IsFound());
@@ -133,9 +139,20 @@ class LookupIterator V8_FINAL BASE_EMBEDDED {
   // answer, and loads extra information about the property.
   bool HasProperty();
   void PrepareForDataProperty(Handle<Object> value);
-  void TransitionToDataProperty(Handle<Object> value,
-                                PropertyAttributes attributes,
-                                Object::StoreFromKeyed store_mode);
+  void PrepareTransitionToDataProperty(Handle<Object> value,
+                                       PropertyAttributes attributes,
+                                       Object::StoreFromKeyed store_mode);
+  bool IsCacheableTransition() {
+    bool cacheable =
+        state_ == TRANSITION && transition_map()->GetBackPointer()->IsMap();
+    if (cacheable) {
+      property_details_ = transition_map_->GetLastDescriptorDetails();
+      LoadPropertyKind();
+      has_property_ = true;
+    }
+    return cacheable;
+  }
+  void ApplyTransitionToDataProperty();
   void ReconfigureDataProperty(Handle<Object> value,
                                PropertyAttributes attributes);
   void TransitionToAccessorProperty(AccessorComponent component,
@@ -159,6 +176,7 @@ class LookupIterator V8_FINAL BASE_EMBEDDED {
     return property_details().representation();
   }
   FieldIndex GetFieldIndex() const;
+  Handle<HeapType> GetFieldType() const;
   int GetConstantIndex() const;
   Handle<PropertyCell> GetPropertyCell() const;
   Handle<Object> GetAccessors() const;
@@ -174,6 +192,7 @@ class LookupIterator V8_FINAL BASE_EMBEDDED {
   inline State LookupInHolder(Map* map);
   Handle<Object> FetchValue() const;
   void ReloadPropertyInformation();
+  void LoadPropertyKind();
 
   bool IsBootstrapping() const;
 
@@ -227,6 +246,7 @@ class LookupIterator V8_FINAL BASE_EMBEDDED {
   Isolate* isolate_;
   Handle<Name> name_;
   Handle<Map> holder_map_;
+  Handle<Map> transition_map_;
   MaybeHandle<Object> maybe_receiver_;
   MaybeHandle<JSReceiver> maybe_holder_;
 
index 0dcee22..f8487d3 100644 (file)
@@ -576,7 +576,7 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
 }
 
 
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupResult* lookup,
+void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
                                                    Register value_reg,
                                                    Label* miss_label) {
   DCHECK(lookup->representation().IsHeapObject());
index 4198885..3e73fd5 100644 (file)
@@ -580,7 +580,7 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
 }
 
 
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupResult* lookup,
+void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
                                                    Register value_reg,
                                                    Label* miss_label) {
   DCHECK(lookup->representation().IsHeapObject());
index 9d6be50..6e67b5a 100644 (file)
@@ -108,6 +108,7 @@ MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
   for (; it->IsFound(); it->Next()) {
     switch (it->state()) {
       case LookupIterator::NOT_FOUND:
+      case LookupIterator::TRANSITION:
         UNREACHABLE();
       case LookupIterator::JSPROXY:
         return JSProxy::GetPropertyWithHandler(it->GetHolder<JSProxy>(),
@@ -150,9 +151,10 @@ Handle<Object> JSObject::GetDataProperty(Handle<JSObject> object,
 Handle<Object> JSObject::GetDataProperty(LookupIterator* it) {
   for (; it->IsFound(); it->Next()) {
     switch (it->state()) {
-      case LookupIterator::NOT_FOUND:
       case LookupIterator::ACCESS_CHECK:
       case LookupIterator::INTERCEPTOR:
+      case LookupIterator::NOT_FOUND:
+      case LookupIterator::TRANSITION:
         UNREACHABLE();
       case LookupIterator::JSPROXY:
         it->NotFound();
@@ -2714,6 +2716,7 @@ MaybeHandle<Map> Map::TryUpdate(Handle<Map> map) {
 
 // static
 Handle<Map> Map::Update(Handle<Map> map) {
+  if (!map->is_deprecated()) return map;
   return GeneralizeRepresentation(map, 0, Representation::None(),
                                   HeapType::None(map->GetIsolate()),
                                   ALLOW_AS_CONSTANT);
@@ -2894,11 +2897,25 @@ MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
         }
         done = true;
         break;
+
+      case LookupIterator::TRANSITION:
+        done = true;
+        break;
     }
 
     if (done) break;
   }
 
+  // If the receiver is the JSGlobalObject, the store was contextual. In case
+  // the property did not exist yet on the global object itself, we have to
+  // throw a reference error in strict mode.
+  if (it->GetReceiver()->IsJSGlobalObject() && strict_mode == STRICT) {
+    Handle<Object> args[1] = {it->name()};
+    Handle<Object> error = it->isolate()->factory()->NewReferenceError(
+        "not_defined", HandleVector(args, 1));
+    return it->isolate()->Throw<Object>(error);
+  }
+
   return AddDataProperty(it, value, NONE, strict_mode, store_mode);
 }
 
@@ -2960,20 +2977,17 @@ MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it,
     // TODO(verwaest): Throw a TypeError with a more specific message.
     return WriteToReadOnlyProperty(it, value, strict_mode);
   }
-  Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
+
+  Handle<JSObject> receiver = it->GetStoreTarget();
 
   // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
   // instead. If the prototype is Null, the proxy is detached.
-  if (receiver->IsJSGlobalProxy()) {
-    // Trying to assign to a detached proxy.
-    PrototypeIterator iter(it->isolate(), receiver);
-    if (iter.IsAtEnd()) return value;
-    receiver =
-        Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter));
-  }
+  if (receiver->IsJSGlobalProxy()) return value;
 
-  if (!it->name().is_identical_to(it->isolate()->factory()->hidden_string()) &&
-      !receiver->map()->is_extensible()) {
+  // Possibly migrate to the most up-to-date map that will be able to store
+  // |value| under it->name() with |attributes|.
+  it->PrepareTransitionToDataProperty(value, attributes, store_mode);
+  if (it->state() != LookupIterator::TRANSITION) {
     if (strict_mode == SLOPPY) return value;
 
     Handle<Object> args[1] = {it->name()};
@@ -2981,10 +2995,7 @@ MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it,
         "object_not_extensible", HandleVector(args, ARRAY_SIZE(args)));
     return it->isolate()->Throw<Object>(error);
   }
-
-  // Possibly migrate to the most up-to-date map that will be able to store
-  // |value| under it->name() with |attributes|.
-  it->TransitionToDataProperty(value, attributes, store_mode);
+  it->ApplyTransitionToDataProperty();
 
   // TODO(verwaest): Encapsulate dictionary handling better.
   if (receiver->map()->is_dictionary_map()) {
@@ -3379,46 +3390,6 @@ Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
 }
 
 
-void JSObject::LookupOwnRealNamedProperty(Handle<Name> name,
-                                          LookupResult* result) {
-  DisallowHeapAllocation no_gc;
-  if (IsJSGlobalProxy()) {
-    PrototypeIterator iter(GetIsolate(), this);
-    if (iter.IsAtEnd()) return result->NotFound();
-    DCHECK(iter.GetCurrent()->IsJSGlobalObject());
-    return JSObject::cast(iter.GetCurrent())
-        ->LookupOwnRealNamedProperty(name, result);
-  }
-
-  if (HasFastProperties()) {
-    map()->LookupDescriptor(this, *name, result);
-    // A property or a map transition was found. We return all of these result
-    // types because LookupOwnRealNamedProperty is used when setting
-    // properties where map transitions are handled.
-    DCHECK(!result->IsFound() ||
-           (result->holder() == this && result->IsFastPropertyType()));
-    return;
-  }
-
-  int entry = property_dictionary()->FindEntry(name);
-  if (entry != NameDictionary::kNotFound) {
-    Object* value = property_dictionary()->ValueAt(entry);
-    if (IsGlobalObject()) {
-      PropertyDetails d = property_dictionary()->DetailsAt(entry);
-      if (d.IsDeleted() || PropertyCell::cast(value)->value()->IsTheHole()) {
-        result->NotFound();
-        return;
-      }
-      value = PropertyCell::cast(value)->value();
-    }
-    result->DictionaryResult(this, entry);
-    return;
-  }
-
-  result->NotFound();
-}
-
-
 Maybe<bool> JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy,
                                             Handle<Name> name) {
   Isolate* isolate = proxy->GetIsolate();
@@ -3847,9 +3818,10 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
                      *name != it.isolate()->heap()->hidden_string();
   for (; it.IsFound(); it.Next()) {
     switch (it.state()) {
-      case LookupIterator::NOT_FOUND:
-      case LookupIterator::JSPROXY:
       case LookupIterator::INTERCEPTOR:
+      case LookupIterator::JSPROXY:
+      case LookupIterator::NOT_FOUND:
+      case LookupIterator::TRANSITION:
         UNREACHABLE();
 
       case LookupIterator::ACCESS_CHECK:
@@ -4022,6 +3994,7 @@ Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
   for (; it->IsFound(); it->Next()) {
     switch (it->state()) {
       case LookupIterator::NOT_FOUND:
+      case LookupIterator::TRANSITION:
         UNREACHABLE();
       case LookupIterator::JSPROXY:
         return JSProxy::GetPropertyAttributesWithHandler(
@@ -4961,8 +4934,9 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
 
   for (; it.IsFound(); it.Next()) {
     switch (it.state()) {
-      case LookupIterator::NOT_FOUND:
       case LookupIterator::JSPROXY:
+      case LookupIterator::NOT_FOUND:
+      case LookupIterator::TRANSITION:
         UNREACHABLE();
       case LookupIterator::ACCESS_CHECK:
         if (it.HasAccess(v8::ACCESS_DELETE)) break;
@@ -5710,58 +5684,6 @@ int Map::NextFreePropertyIndex() {
 }
 
 
-void JSReceiver::LookupOwn(Handle<Name> name, LookupResult* result) {
-  DisallowHeapAllocation no_gc;
-  DCHECK(name->IsName());
-
-  if (IsJSGlobalProxy()) {
-    PrototypeIterator iter(GetIsolate(), this);
-    if (iter.IsAtEnd()) return result->NotFound();
-    DCHECK(iter.GetCurrent()->IsJSGlobalObject());
-    return JSReceiver::cast(iter.GetCurrent())->LookupOwn(name, result);
-  }
-
-  if (IsJSProxy()) {
-    result->HandlerResult(JSProxy::cast(this));
-    return;
-  }
-
-  // Do not use inline caching if the object is a non-global object
-  // that requires access checks.
-  if (IsAccessCheckNeeded()) {
-    result->DisallowCaching();
-  }
-
-  JSObject* js_object = JSObject::cast(this);
-
-  // Check for lookup interceptor except when bootstrapping.
-  if (js_object->HasNamedInterceptor() &&
-      !GetIsolate()->bootstrapper()->IsActive()) {
-    result->InterceptorResult(js_object);
-    return;
-  }
-
-  js_object->LookupOwnRealNamedProperty(name, result);
-}
-
-
-void JSReceiver::Lookup(Handle<Name> name, LookupResult* result) {
-  DisallowHeapAllocation no_gc;
-  // Ecma-262 3rd 8.6.2.4
-  for (PrototypeIterator iter(GetIsolate(), this,
-                              PrototypeIterator::START_AT_RECEIVER);
-       !iter.IsAtEnd(); iter.Advance()) {
-    JSReceiver::cast(iter.GetCurrent())->LookupOwn(name, result);
-    if (result->IsFound()) return;
-    if (name->IsOwn()) {
-      result->NotFound();
-      return;
-    }
-  }
-  result->NotFound();
-}
-
-
 static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
   int len = array->length();
   for (int i = 0; i < len; i++) {
@@ -6397,8 +6319,9 @@ MaybeHandle<Object> JSObject::GetAccessor(Handle<JSObject> object,
                       LookupIterator::CHECK_DERIVED_SKIP_INTERCEPTOR);
     for (; it.IsFound(); it.Next()) {
       switch (it.state()) {
-        case LookupIterator::NOT_FOUND:
         case LookupIterator::INTERCEPTOR:
+        case LookupIterator::NOT_FOUND:
+        case LookupIterator::TRANSITION:
           UNREACHABLE();
 
         case LookupIterator::ACCESS_CHECK:
@@ -6835,7 +6758,7 @@ Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
   if (map->is_dictionary_map()) return map;
 
   // Migrate to the newest map before storing the property.
-  if (map->is_deprecated()) map = Update(map);
+  map = Update(map);
 
   Handle<DescriptorArray> descriptors(map->instance_descriptors());
 
@@ -6857,8 +6780,8 @@ Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
   // Dictionary maps can always have additional data properties.
   if (map->is_dictionary_map()) return map;
 
-  // Migrate to the newest map before transitioning to the new property.
-  if (map->is_deprecated()) map = Update(map);
+  // Migrate to the newest map before storing the property.
+  map = Update(map);
 
   int index = map->SearchTransition(*name);
   if (index != TransitionArray::kNotFound) {
@@ -6868,9 +6791,7 @@ Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
     // TODO(verwaest): Handle attributes better.
     DescriptorArray* descriptors = transition->instance_descriptors();
     if (descriptors->GetDetails(descriptor).attributes() != attributes) {
-      return CopyGeneralizeAllRepresentations(transition, descriptor,
-                                              FORCE_FIELD, attributes,
-                                              "attributes mismatch");
+      return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES);
     }
 
     return Map::PrepareForDataProperty(transition, descriptor, value);
@@ -6925,7 +6846,7 @@ Handle<Map> Map::TransitionToAccessorProperty(Handle<Map> map,
   }
 
   // Migrate to the newest map before transitioning to the new property.
-  if (map->is_deprecated()) map = Update(map);
+  map = Update(map);
 
   PropertyNormalizationMode mode = map->is_prototype_map()
                                        ? KEEP_INOBJECT_PROPERTIES
index 055bfdb..53b95d2 100644 (file)
@@ -1997,10 +1997,6 @@ class JSReceiver: public HeapObject {
   inline static Handle<Smi> GetOrCreateIdentityHash(
       Handle<JSReceiver> object);
 
-  // Lookup a property.  If found, the result is valid and has
-  // detailed information.
-  void Lookup(Handle<Name> name, LookupResult* result);
-
   enum KeyCollectionType { OWN_ONLY, INCLUDE_PROTOS };
 
   // Computes the enumerable keys for a JSObject. Used for implementing
@@ -2010,7 +2006,6 @@ class JSReceiver: public HeapObject {
       KeyCollectionType type);
 
  private:
-  void LookupOwn(Handle<Name> name, LookupResult* result);
   DISALLOW_IMPLICIT_CONSTRUCTORS(JSReceiver);
 };
 
@@ -2368,9 +2363,6 @@ class JSObject: public JSReceiver {
   inline void SetInternalField(int index, Object* value);
   inline void SetInternalField(int index, Smi* value);
 
-  // The following lookup functions skip interceptors.
-  void LookupOwnRealNamedProperty(Handle<Name> name, LookupResult* result);
-
   // Returns the number of properties on this object filtering out properties
   // with the specified attributes (ignoring interceptors).
   int NumberOfOwnProperties(PropertyAttributes filter = NONE);
index 2e15266..f7dd0e8 100644 (file)
@@ -10900,6 +10900,7 @@ static Handle<Object> DebugLookupResultValue(LookupIterator* it,
   for (; it->IsFound(); it->Next()) {
     switch (it->state()) {
       case LookupIterator::NOT_FOUND:
+      case LookupIterator::TRANSITION:
         UNREACHABLE();
       case LookupIterator::ACCESS_CHECK:
         // Ignore access checks.
index 4a7a7a6..32ff8d1 100644 (file)
@@ -614,14 +614,18 @@ RUNTIME_FUNCTION(StorePropertyWithInterceptor) {
   Handle<Name> name = args.at<Name>(1);
   Handle<Object> value = args.at<Object>(2);
 #ifdef DEBUG
-  if (receiver->IsJSGlobalProxy()) {
-    PrototypeIterator iter(isolate, receiver);
-    DCHECK(iter.IsAtEnd() ||
-           Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter))
-               ->HasNamedInterceptor());
-  } else {
-    DCHECK(receiver->HasNamedInterceptor());
+  PrototypeIterator iter(isolate, receiver,
+                         PrototypeIterator::START_AT_RECEIVER);
+  bool found = false;
+  while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) {
+    Handle<Object> current = PrototypeIterator::GetCurrent(iter);
+    if (current->IsJSObject() &&
+        Handle<JSObject>::cast(current)->HasNamedInterceptor()) {
+      found = true;
+      break;
+    }
   }
+  DCHECK(found);
 #endif
   Handle<Object> result;
   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
@@ -889,7 +893,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
 
 
 Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
-    LookupIterator* it, Handle<Name> name) {
+    LookupIterator* it) {
   // So far the most popular follow ups for interceptor loads are FIELD and
   // ExecutableAccessorInfo, so inline only them. Other cases may be added
   // later.
@@ -912,7 +916,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
     }
   }
 
-  Register reg = Frontend(receiver(), name);
+  Register reg = Frontend(receiver(), it->name());
   if (inline_followup) {
     // TODO(368): Compile in the whole chain: all the interceptors in
     // prototypes and ultimate answer.
@@ -920,7 +924,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
   } else {
     GenerateLoadInterceptor(reg);
   }
-  return GetCode(kind(), Code::FAST, name);
+  return GetCode(kind(), Code::FAST, it->name());
 }
 
 
@@ -1007,13 +1011,12 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
 }
 
 
-Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupResult* lookup,
-                                                          Handle<Name> name) {
+Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) {
   Label miss;
-  GenerateStoreField(lookup, value(), &miss);
+  GenerateStoreField(it, value(), &miss);
   __ bind(&miss);
   TailCallBuiltin(masm(), MissBuiltin(kind()));
-  return GetCode(kind(), Code::FAST, name);
+  return GetCode(kind(), Code::FAST, it->name());
 }
 
 
index d8aafdf..a734c8a 100644 (file)
@@ -476,7 +476,7 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
   // The LookupIterator is used to perform a lookup behind the interceptor. If
   // the iterator points to a LookupIterator::PROPERTY, its access will be
   // inlined.
-  Handle<Code> CompileLoadInterceptor(LookupIterator* it, Handle<Name> name);
+  Handle<Code> CompileLoadInterceptor(LookupIterator* it);
 
   Handle<Code> CompileLoadViaGetter(Handle<Name> name,
                                     Handle<JSFunction> getter);
@@ -558,7 +558,7 @@ class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
 
   Handle<Code> CompileStoreTransition(Handle<Map> transition,
                                       Handle<Name> name);
-  Handle<Code> CompileStoreField(LookupResult* lookup, Handle<Name> name);
+  Handle<Code> CompileStoreField(LookupIterator* it);
   Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name,
                                     Handle<ExecutableAccessorInfo> callback);
   Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name,
@@ -590,7 +590,7 @@ class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
                                Register scratch2, Register scratch3,
                                Label* miss_label, Label* slow);
 
-  void GenerateStoreField(LookupResult* lookup, Register value_reg,
+  void GenerateStoreField(LookupIterator* lookup, Register value_reg,
                           Label* miss_label);
 
   static Builtins::Name SlowBuiltin(Code::Kind kind) {
index a32b073..3619a9b 100644 (file)
@@ -516,7 +516,7 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
 }
 
 
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupResult* lookup,
+void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
                                                    Register value_reg,
                                                    Label* miss_label) {
   DCHECK(lookup->representation().IsHeapObject());
index acb7964..dedbaa6 100644 (file)
@@ -567,7 +567,7 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
 }
 
 
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupResult* lookup,
+void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
                                                    Register value_reg,
                                                    Label* miss_label) {
   DCHECK(lookup->representation().IsHeapObject());