Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index 7841e1f92f8fe7d93cac3fe86fe40120a88596b1..deb113bb54e36885768c26fc42f188c4dd6f8f22 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -6855,6 +6855,9 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( |
if (TryCallPolymorphicAsMonomorphic(expr, receiver, types, name)) return; |
int argument_count = expr->arguments()->length() + 1; // Includes receiver. |
+ HBasicBlock* join = NULL; |
+ FunctionSorter order[kMaxCallPolymorphism]; |
+ int ordered_functions = 0; |
Handle<Map> initial_string_map( |
isolate()->native_context()->string_function()->initial_map()); |
@@ -6868,121 +6871,72 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( |
bool handle_smi = false; |
- // A map from functions to a set of receivers' maps. |
- struct FuncMapEntry { |
- Handle<JSFunction> func; |
- SmallMapList maps; |
- }; |
- FuncMapEntry func_map[kMaxCallPolymorphism]; |
- FunctionSorter order[kMaxCallPolymorphism]; |
- int func_count = 0; |
- int maps_count = 0; |
- |
for (int i = 0; |
- i < types->length() && func_count < kMaxCallPolymorphism; |
+ i < types->length() && ordered_functions < kMaxCallPolymorphism; |
++i) { |
Handle<Map> map = types->at(i); |
if (expr->ComputeTarget(map, name)) { |
if (map.is_identical_to(number_marker_map)) handle_smi = true; |
- |
- // Try to find the target function among known targets. |
- int func_index = 0; |
- for (; func_index < func_count; ++func_index) { |
- if (*func_map[func_index].func == *expr->target()) { |
- break; |
- } |
- } |
- FuncMapEntry* entry = &func_map[func_index]; |
- if (func_index == func_count) { |
- // Entry not found, "allocate" it. |
- entry->func = expr->target(); |
- entry->maps.Reserve(types->length() - maps_count, zone()); |
- order[func_index] = |
- FunctionSorter(func_index, |
- entry->func->shared()->profiler_ticks(), |
- InliningAstSize(entry->func), |
- entry->func->shared()->SourceSize()); |
- ++func_count; |
- } |
- entry->maps.Add(map, zone()); |
- ++maps_count; |
+ order[ordered_functions++] = |
+ FunctionSorter(i, |
+ expr->target()->shared()->profiler_ticks(), |
+ InliningAstSize(expr->target()), |
+ expr->target()->shared()->SourceSize()); |
} |
} |
- std::sort(order, order + func_count); |
+ std::sort(order, order + ordered_functions); |
HBasicBlock* number_block = NULL; |
- HBasicBlock* join = NULL; |
- if (func_count > 0) { |
- // Only needed once. |
- join = graph()->CreateBasicBlock(); |
- if (handle_smi) { |
- HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); |
- HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); |
- number_block = graph()->CreateBasicBlock(); |
- FinishCurrentBlock( |
- New<HIsSmiAndBranch>(receiver, empty_smi_block, not_smi_block)); |
- Goto(empty_smi_block, number_block); |
- set_current_block(not_smi_block); |
- } else { |
- BuildCheckHeapObject(receiver); |
- } |
- } |
- |
- for (int fn = 0; fn < func_count; ++fn) { |
+ for (int fn = 0; fn < ordered_functions; ++fn) { |
int i = order[fn].index(); |
- FuncMapEntry* func_map_entry = &func_map[i]; |
- |
- HBasicBlock* call_block = graph()->CreateBasicBlock(); |
- HBasicBlock* if_false = NULL; |
- |
- int maps_count = func_map_entry->maps.length(); |
- for (int m = 0; m < maps_count; ++m) { |
- Handle<Map> map = func_map_entry->maps.at(m); |
- HBasicBlock* if_true = graph()->CreateBasicBlock(); |
- if_false = graph()->CreateBasicBlock(); |
- HUnaryControlInstruction* compare; |
- |
- if (handle_smi && map.is_identical_to(number_marker_map)) { |
- compare = |
- New<HCompareMap>(receiver, heap_number_map, if_true, if_false); |
- map = initial_number_map; |
- expr->set_number_check( |
- Handle<JSObject>(JSObject::cast(map->prototype()))); |
- } else if (map.is_identical_to(string_marker_map)) { |
- compare = New<HIsStringAndBranch>(receiver, if_true, if_false); |
- map = initial_string_map; |
- expr->set_string_check( |
- Handle<JSObject>(JSObject::cast(map->prototype()))); |
+ Handle<Map> map = types->at(i); |
+ if (fn == 0) { |
+ // Only needed once. |
+ join = graph()->CreateBasicBlock(); |
+ if (handle_smi) { |
+ HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); |
+ HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); |
+ number_block = graph()->CreateBasicBlock(); |
+ FinishCurrentBlock(New<HIsSmiAndBranch>( |
+ receiver, empty_smi_block, not_smi_block)); |
+ Goto(empty_smi_block, number_block); |
+ set_current_block(not_smi_block); |
} else { |
- compare = New<HCompareMap>(receiver, map, if_true, if_false); |
- expr->set_map_check(); |
- } |
- |
- FinishCurrentBlock(compare); |
- |
- if (expr->check_type() == NUMBER_CHECK) { |
- Goto(if_true, number_block); |
- if_true = number_block; |
- number_block->SetJoinId(expr->id()); |
+ BuildCheckHeapObject(receiver); |
} |
- set_current_block(if_true); |
- |
- expr->ComputeTarget(map, name); |
- ASSERT(*expr->target() == *func_map_entry->func); |
- |
- AddCheckPrototypeMaps(expr->holder(), map); |
+ } |
+ HBasicBlock* if_true = graph()->CreateBasicBlock(); |
+ HBasicBlock* if_false = graph()->CreateBasicBlock(); |
+ HUnaryControlInstruction* compare; |
+ |
+ if (handle_smi && map.is_identical_to(number_marker_map)) { |
+ compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false); |
+ map = initial_number_map; |
+ expr->set_number_check( |
+ Handle<JSObject>(JSObject::cast(map->prototype()))); |
+ } else if (map.is_identical_to(string_marker_map)) { |
+ compare = New<HIsStringAndBranch>(receiver, if_true, if_false); |
+ map = initial_string_map; |
+ expr->set_string_check( |
+ Handle<JSObject>(JSObject::cast(map->prototype()))); |
+ } else { |
+ compare = New<HCompareMap>(receiver, map, if_true, if_false); |
+ expr->set_map_check(); |
+ } |
- Goto(if_true, call_block); |
+ FinishCurrentBlock(compare); |
- set_current_block(if_false); |
+ if (expr->check_type() == NUMBER_CHECK) { |
+ Goto(if_true, number_block); |
+ if_true = number_block; |
+ number_block->SetJoinId(expr->id()); |
} |
+ set_current_block(if_true); |
- // Generate call once for all corresponding maps. |
- call_block->SetJoinId(expr->id()); |
- set_current_block(call_block); |
- |
+ expr->ComputeTarget(map, name); |
+ AddCheckPrototypeMaps(expr->holder(), map); |
if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { |
Handle<JSFunction> caller = current_info()->closure(); |
SmartArrayPointer<char> caller_name = |
@@ -7002,15 +6956,15 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( |
AddInstruction(call); |
if (!ast_context()->IsEffect()) Push(call); |
} |
- if (current_block() != NULL) Goto(join); |
+ if (current_block() != NULL) Goto(join); |
set_current_block(if_false); |
} |
// Finish up. Unconditionally deoptimize if we've handled all the maps we |
// know about and do not want to handle ones we've never seen. Otherwise |
// use a generic IC. |
- if (maps_count == types->length() && FLAG_deoptimize_uncommon_cases) { |
+ if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) { |
// Because the deopt may be the only path in the polymorphic call, make sure |
// that the environment stack matches the depth on deopt that it otherwise |
// would have had after a successful call. |