Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index bbcdd3b7b90a76ac01728da4a5782524cd902878..8499b9925eaee3523628d2352cfdfc5ad2c626b6 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -7371,10 +7371,24 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( |
HBasicBlock* join = NULL; |
FunctionSorter order[kMaxCallPolymorphism]; |
int ordered_functions = 0; |
+ |
+ Handle<Map> initial_string_map( |
+ isolate()->native_context()->string_function()->initial_map()); |
+ Handle<Map> string_marker_map( |
+ JSObject::cast(initial_string_map->prototype())->map()); |
+ Handle<Map> initial_number_map( |
+ isolate()->native_context()->number_function()->initial_map()); |
+ Handle<Map> number_marker_map( |
+ JSObject::cast(initial_number_map->prototype())->map()); |
+ Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); |
+ |
+ bool handle_smi = false; |
+ |
for (int i = 0; |
i < types->length() && ordered_functions < kMaxCallPolymorphism; |
++i) { |
Handle<Map> map = types->at(i); |
+ if (map.is_identical_to(number_marker_map)) handle_smi = true; |
if (expr->ComputeTarget(map, name)) { |
order[ordered_functions++] = |
FunctionSorter(i, |
@@ -7389,21 +7403,59 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( |
sizeof(order[0]), |
&CompareHotness); |
+ HBasicBlock* number_block = NULL; |
+ |
for (int fn = 0; fn < ordered_functions; ++fn) { |
int i = order[fn].index(); |
Handle<Map> map = types->at(i); |
if (fn == 0) { |
// Only needed once. |
- AddInstruction(new(zone()) HCheckNonSmi(receiver)); |
join = graph()->CreateBasicBlock(); |
+ if (handle_smi) { |
+ HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); |
+ HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); |
+ number_block = graph()->CreateBasicBlock(); |
+ HIsSmiAndBranch* smicheck = new(zone()) HIsSmiAndBranch(receiver); |
+ smicheck->SetSuccessorAt(0, empty_smi_block); |
+ smicheck->SetSuccessorAt(1, not_smi_block); |
+ current_block()->Finish(smicheck); |
+ empty_smi_block->Goto(number_block); |
+ set_current_block(not_smi_block); |
+ } else { |
+ AddInstruction(new(zone()) HCheckNonSmi(receiver)); |
+ } |
} |
HBasicBlock* if_true = graph()->CreateBasicBlock(); |
HBasicBlock* if_false = graph()->CreateBasicBlock(); |
- HCompareMap* compare = |
- new(zone()) HCompareMap(receiver, map, if_true, if_false); |
+ HUnaryControlInstruction* compare; |
+ |
+ if (handle_smi && map.is_identical_to(number_marker_map)) { |
+ compare = new(zone()) 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(zone()) HIsStringAndBranch(receiver); |
+ compare->SetSuccessorAt(0, if_true); |
+ compare->SetSuccessorAt(1, if_false); |
+ map = initial_string_map; |
+ expr->set_string_check( |
+ Handle<JSObject>(JSObject::cast(map->prototype()))); |
+ } else { |
+ compare = new(zone()) HCompareMap(receiver, map, if_true, if_false); |
+ expr->set_map_check(); |
+ } |
+ |
current_block()->Finish(compare); |
+ if (expr->check_type() == NUMBER_CHECK) { |
+ if_true->Goto(number_block); |
+ if_true = number_block; |
+ number_block->SetJoinId(expr->id()); |
+ } |
set_current_block(if_true); |
+ |
expr->ComputeTarget(map, name); |
AddCheckPrototypeMaps(expr->holder(), map); |
if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { |