Consolidate polymorphic calls due to elements transitions.
authorverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 14 Nov 2012 12:10:51 +0000 (12:10 +0000)
committerverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 14 Nov 2012 12:10:51 +0000 (12:10 +0000)
Review URL: https://chromiumcodereview.appspot.com/11359104

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

src/hydrogen.cc

index 51ae7f5a44c29fc4b69f66651b95fcfef7a6f2fa..0a25bb039ae0ffeb4d62ee77fa6d8fbca69484f0 100644 (file)
@@ -7512,6 +7512,55 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
 }
 
 
+// Checks if all maps in |types| are from the same family, i.e., are elements
+// transitions of each other. Returns either NULL if they are not from the same
+// family, or a Map* indicating the map with the first elements kind of the
+// family that is in the list.
+static Map* CheckSameElementsFamily(SmallMapList* types) {
+  if (types->length() <= 1) return NULL;
+  // Check if all maps belong to the same transition family.
+  Map* kinds[kFastElementsKindCount];
+  Map* first_map = *types->first();
+  ElementsKind first_kind = first_map->elements_kind();
+  if (!IsFastElementsKind(first_kind)) return NULL;
+  int first_index = GetSequenceIndexFromFastElementsKind(first_kind);
+  int last_index = first_index;
+
+  for (int i = 0; i < kFastElementsKindCount; i++) kinds[i] = NULL;
+
+  kinds[first_index] = first_map;
+
+  for (int i = 1; i < types->length(); ++i) {
+    Map* map = *types->at(i);
+    ElementsKind elements_kind = map->elements_kind();
+    if (!IsFastElementsKind(elements_kind)) return NULL;
+    int index = GetSequenceIndexFromFastElementsKind(elements_kind);
+    if (index < first_index) {
+      first_index = index;
+    } else if (index > last_index) {
+      last_index = index;
+    } else if (kinds[index] != map) {
+      return NULL;
+    }
+    kinds[index] = map;
+  }
+
+  Map* current = kinds[first_index];
+  for (int i = first_index + 1; i <= last_index; i++) {
+    Map* next = kinds[i];
+    if (next != NULL) {
+      ElementsKind current_kind = next->elements_kind();
+      if (next != current->LookupElementsTransitionMap(current_kind)) {
+        return NULL;
+      }
+      current = next;
+    }
+  }
+
+  return kinds[first_index];
+}
+
+
 void HGraphBuilder::VisitCall(Call* expr) {
   ASSERT(!HasStackOverflow());
   ASSERT(current_block() != NULL);
@@ -7551,15 +7600,25 @@ void HGraphBuilder::VisitCall(Call* expr) {
     CHECK_ALIVE(VisitExpressions(expr->arguments()));
 
     Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
-
     SmallMapList* types = expr->GetReceiverTypes();
 
-    HValue* receiver =
-        environment()->ExpressionStackAt(expr->arguments()->length());
-    if (expr->IsMonomorphic()) {
-      Handle<Map> receiver_map = (types == NULL || types->is_empty())
+    bool monomorphic = expr->IsMonomorphic();
+    Handle<Map> receiver_map;
+    if (monomorphic) {
+      receiver_map = (types == NULL || types->is_empty())
           ? Handle<Map>::null()
           : types->first();
+    } else {
+      Map* family_map = CheckSameElementsFamily(types);
+      if (family_map != NULL) {
+        receiver_map = Handle<Map>(family_map);
+        monomorphic = expr->ComputeTarget(receiver_map, name);
+      }
+    }
+
+    HValue* receiver =
+        environment()->ExpressionStackAt(expr->arguments()->length());
+    if (monomorphic) {
       if (TryInlineBuiltinMethodCall(expr,
                                      receiver,
                                      receiver_map,