Unify monomorphic and polymorphic cases in IC::PatchCache.
authorulan@chromium.org <ulan@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 27 Mar 2014 09:59:43 +0000 (09:59 +0000)
committerulan@chromium.org <ulan@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 27 Mar 2014 09:59:43 +0000 (09:59 +0000)
BUG=
R=verwaest@chromium.org

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

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

src/ic.cc
src/ic.h

index da8afca..a327173 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -624,28 +624,33 @@ bool IC::UpdatePolymorphicIC(Handle<HeapType> type,
   TypeHandleList types;
   CodeHandleList handlers;
 
-  int number_of_valid_types;
-  int handler_to_overwrite = -1;
-
   target()->FindAllTypes(&types);
   int number_of_types = types.length();
-  number_of_valid_types = number_of_types;
+  int deprecated_types = 0;
+  int handler_to_overwrite = -1;
 
   for (int i = 0; i < number_of_types; i++) {
     Handle<HeapType> current_type = types.at(i);
-    // Filter out deprecated maps to ensure their instances get migrated.
     if (current_type->IsClass() && current_type->AsClass()->is_deprecated()) {
-      number_of_valid_types--;
-    // If the receiver type is already in the polymorphic IC, this indicates
-    // there was a prototoype chain failure. In that case, just overwrite the
-    // handler.
+      // Filter out deprecated maps to ensure their instances get migrated.
+      ++deprecated_types;
     } else if (type->IsCurrently(current_type)) {
-      ASSERT(handler_to_overwrite == -1);
-      number_of_valid_types--;
+      // If the receiver type is already in the polymorphic IC, this indicates
+      // there was a prototoype chain failure. In that case, just overwrite the
+      // handler.
+      handler_to_overwrite = i;
+    } else if (handler_to_overwrite == -1 &&
+               current_type->IsClass() &&
+               type->IsClass() &&
+               IsTransitionOfMonomorphicTarget(*current_type->AsClass(),
+                                               *type->AsClass())) {
       handler_to_overwrite = i;
     }
   }
 
+  int number_of_valid_types =
+    number_of_types - deprecated_types - (handler_to_overwrite != -1);
+
   if (number_of_valid_types >= 4) return false;
   if (number_of_types == 0) return false;
   if (!target()->FindHandlers(&handlers, types.length())) return false;
@@ -653,6 +658,9 @@ bool IC::UpdatePolymorphicIC(Handle<HeapType> type,
   number_of_valid_types++;
   if (handler_to_overwrite >= 0) {
     handlers.Set(handler_to_overwrite, code);
+    if (!type->IsCurrently(types.at(handler_to_overwrite))) {
+      types.Set(handler_to_overwrite, type);
+    }
   } else {
     types.Add(type);
     handlers.Add(code);
@@ -727,19 +735,18 @@ void IC::CopyICToMegamorphicCache(Handle<String> name) {
 }
 
 
-bool IC::IsTransitionOfMonomorphicTarget(Handle<HeapType> type) {
-  if (!type->IsClass()) return false;
-  Map* receiver_map = *type->AsClass();
-  Map* current_map = target()->FindFirstMap();
-  ElementsKind receiver_elements_kind = receiver_map->elements_kind();
+bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
+  if (source_map == NULL) return true;
+  if (target_map == NULL) return false;
+  ElementsKind target_elements_kind = target_map->elements_kind();
   bool more_general_transition =
       IsMoreGeneralElementsKindTransition(
-        current_map->elements_kind(), receiver_elements_kind);
+        source_map->elements_kind(), target_elements_kind);
   Map* transitioned_map = more_general_transition
-      ? current_map->LookupElementsTransitionMap(receiver_elements_kind)
+      ? source_map->LookupElementsTransitionMap(target_elements_kind)
       : NULL;
 
-  return transitioned_map == receiver_map;
+  return transitioned_map == target_map;
 }
 
 
@@ -752,17 +759,7 @@ void IC::PatchCache(Handle<HeapType> type,
     case MONOMORPHIC_PROTOTYPE_FAILURE:
       UpdateMonomorphicIC(type, code, name);
       break;
-    case MONOMORPHIC: {
-      // For now, call stubs are allowed to rewrite to the same stub. This
-      // happens e.g., when the field does not contain a function.
-      ASSERT(!target().is_identical_to(code));
-      Code* old_handler = target()->FindFirstHandler();
-      if (old_handler == *code && IsTransitionOfMonomorphicTarget(type)) {
-        UpdateMonomorphicIC(type, code, name);
-        break;
-      }
-      // Fall through.
-    }
+    case MONOMORPHIC:  // Fall through.
     case POLYMORPHIC:
       if (!target()->is_keyed_stub()) {
         if (UpdatePolymorphicIC(type, name, code)) break;
@@ -1457,8 +1454,8 @@ Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
     }
     if ((receiver_map.is_identical_to(previous_receiver_map) &&
          IsTransitionStoreMode(store_mode)) ||
-        IsTransitionOfMonomorphicTarget(
-            MapToType<HeapType>(transitioned_receiver_map, isolate()))) {
+        IsTransitionOfMonomorphicTarget(*previous_receiver_map,
+                                        *transitioned_receiver_map)) {
       // If the "old" and "new" maps are in the same elements map family, or
       // if they at least come from the same origin for a transitioning store,
       // stay MONOMORPHIC and use the map for the most generic ElementsKind.
index 7d35471..e70cb82 100644 (file)
--- a/src/ic.h
+++ b/src/ic.h
@@ -217,7 +217,7 @@ class IC {
   virtual void UpdateMegamorphicCache(HeapType* type, Name* name, Code* code);
 
   void CopyICToMegamorphicCache(Handle<String> name);
-  bool IsTransitionOfMonomorphicTarget(Handle<HeapType> type);
+  bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map);
   void PatchCache(Handle<HeapType> type,
                   Handle<String> name,
                   Handle<Code> code);