Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index 51ae7f5a44c29fc4b69f66651b95fcfef7a6f2fa..0a25bb039ae0ffeb4d62ee77fa6d8fbca69484f0 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -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, |