Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 679 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 690 } | 690 } |
| 691 | 691 |
| 692 | 692 |
| 693 HGraph::HGraph(CompilationInfo* info) | 693 HGraph::HGraph(CompilationInfo* info) |
| 694 : isolate_(info->isolate()), | 694 : isolate_(info->isolate()), |
| 695 next_block_id_(0), | 695 next_block_id_(0), |
| 696 entry_block_(NULL), | 696 entry_block_(NULL), |
| 697 blocks_(8, info->zone()), | 697 blocks_(8, info->zone()), |
| 698 values_(16, info->zone()), | 698 values_(16, info->zone()), |
| 699 phi_list_(NULL), | 699 phi_list_(NULL), |
| 700 array_lengths_(8, info->zone()), | |
| 700 uint32_instructions_(NULL), | 701 uint32_instructions_(NULL), |
| 701 info_(info), | 702 info_(info), |
| 702 zone_(info->zone()), | 703 zone_(info->zone()), |
| 703 is_recursive_(false), | 704 is_recursive_(false), |
| 704 use_optimistic_licm_(false), | 705 use_optimistic_licm_(false), |
| 705 type_change_checksum_(0) { | 706 type_change_checksum_(0) { |
| 706 start_environment_ = | 707 start_environment_ = |
| 707 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); | 708 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); |
| 708 start_environment_->set_ast_id(BailoutId::FunctionEntry()); | 709 start_environment_->set_ast_id(BailoutId::FunctionEntry()); |
| 709 entry_block_ = CreateBasicBlock(); | 710 entry_block_ = CreateBasicBlock(); |
| 710 entry_block_->SetInitialEnvironment(start_environment_); | 711 entry_block_->SetInitialEnvironment(start_environment_); |
| 711 } | 712 } |
| 712 | 713 |
| 713 | 714 |
| 714 HBasicBlock* HGraph::CreateBasicBlock() { | 715 HBasicBlock* HGraph::CreateBasicBlock() { |
| 715 HBasicBlock* result = new(zone()) HBasicBlock(this); | 716 HBasicBlock* result = new(zone()) HBasicBlock(this); |
| 716 blocks_.Add(result, zone()); | 717 blocks_.Add(result, zone()); |
| 717 return result; | 718 return result; |
| 718 } | 719 } |
| 719 | 720 |
| 720 | 721 |
| 722 static int CompareJSArrayLengthsByValues(HJSArrayLength* const* x, | |
| 723 HJSArrayLength* const* y) { | |
| 724 return Compare<int>((*x)->value()->id(), (*y)->value()->id()); | |
| 725 } | |
| 726 | |
| 727 | |
| 728 void HGraph::ProcessJSArrayLengths() { | |
| 729 HPhase phase("H_ProcessJSArrayLengths", this); | |
| 730 array_lengths_.Sort(CompareJSArrayLengthsByValues); | |
| 731 | |
| 732 int group_start_index = 0; | |
| 733 while (group_start_index < array_lengths_.length()) { | |
| 734 // First, find the set of HJSArrayLength insts that operate on the same | |
|
danno
2012/11/28 12:44:31
please don't use abbreviations, "insts" should be
| |
| 735 // array and see if all the ones that are guarded by a map check do a | |
| 736 // check for the same map. | |
| 737 bool map_check_can_be_shared = true; | |
| 738 HCheckMaps* map_check = NULL; | |
| 739 HType type = HType::Tagged(); | |
| 740 int group_end_index = group_start_index; | |
| 741 while (group_end_index < array_lengths_.length() && | |
|
danno
2012/11/28 12:44:31
This algorithm is a no-go. It is quadratic with r
| |
| 742 array_lengths_.at(group_end_index)->value()->id() == | |
| 743 array_lengths_.at(group_start_index)->value()->id()) { | |
| 744 HJSArrayLength* inst = array_lengths_.at(group_end_index); | |
| 745 if (inst->typecheck()->IsCheckMaps()) { | |
| 746 HCheckMaps* current_map_check = HCheckMaps::cast(inst->typecheck()); | |
| 747 if (current_map_check->has_dependency()) { | |
| 748 // Element transitions would cause deopts... | |
| 749 map_check_can_be_shared = false; | |
| 750 } else { | |
| 751 if (map_check != NULL) { | |
| 752 if (current_map_check->map_set()->length() == | |
| 753 map_check->map_set()->length()) { | |
| 754 for (int i = 0; i < map_check->map_set()->length(); i++) { | |
| 755 if (*(map_check->map_set()->at(i)) != | |
| 756 *(current_map_check->map_set()->at(i))) { | |
| 757 map_check_can_be_shared = false; | |
| 758 break; | |
| 759 } | |
| 760 | |
| 761 // Record the check higher in the dominator tree. | |
| 762 if (current_map_check->block()->Dominates( | |
| 763 map_check->block())) { | |
| 764 map_check = current_map_check; | |
|
danno
2012/11/28 12:44:31
This is not sufficient and leads to incorrect code
| |
| 765 } | |
| 766 } | |
| 767 } else { | |
| 768 map_check_can_be_shared = false; | |
| 769 } | |
| 770 } else { | |
| 771 map_check = current_map_check; | |
| 772 type = inst->type(); | |
| 773 } | |
| 774 } | |
| 775 } else if (!inst->typecheck()->IsCheckInstanceType()) { | |
| 776 map_check_can_be_shared = false; | |
| 777 } | |
| 778 | |
| 779 group_end_index++; | |
| 780 } | |
| 781 | |
| 782 // If we do have a map check and it is unique, make so that all the other | |
| 783 // HJSArrayLength instructions are guarded by the same check. | |
| 784 if (map_check != NULL && map_check_can_be_shared) { | |
| 785 for (int i = group_start_index; i < group_end_index; i++) { | |
| 786 HJSArrayLength* inst = array_lengths_.at(i); | |
| 787 if (inst->typecheck()->IsCheckInstanceType()) { | |
| 788 HValue* typecheck = inst->typecheck(); | |
| 789 // For now don't handle complex cases which should not even happen. | |
| 790 if (typecheck->UseCount() == 1) { | |
| 791 // Use new_check directly if it dominates this location, otherwise | |
| 792 // create a new identical check (GVN can collapse them anyway). | |
| 793 HCheckMaps* new_check; | |
| 794 if (map_check->block()->Dominates(inst->block())) { | |
| 795 new_check = map_check; | |
| 796 } else { | |
| 797 new_check = new(zone()) HCheckMaps( | |
| 798 inst->value(), map_check->map_set(), zone()); | |
| 799 new_check->InsertBefore(inst); | |
| 800 } | |
| 801 typecheck->DeleteAndReplaceWith(new_check); | |
| 802 inst->set_type(type); | |
| 803 } | |
| 804 } | |
| 805 } | |
| 806 } | |
| 807 | |
| 808 // Move to next "group". | |
| 809 group_start_index = group_end_index; | |
| 810 } | |
| 811 } | |
| 812 | |
| 813 | |
| 721 void HGraph::Canonicalize() { | 814 void HGraph::Canonicalize() { |
| 722 if (!FLAG_use_canonicalizing) return; | 815 if (!FLAG_use_canonicalizing) return; |
| 723 HPhase phase("H_Canonicalize", this); | 816 HPhase phase("H_Canonicalize", this); |
| 724 for (int i = 0; i < blocks()->length(); ++i) { | 817 for (int i = 0; i < blocks()->length(); ++i) { |
| 725 HInstruction* instr = blocks()->at(i)->first(); | 818 HInstruction* instr = blocks()->at(i)->first(); |
| 726 while (instr != NULL) { | 819 while (instr != NULL) { |
| 727 HValue* value = instr->Canonicalize(); | 820 HValue* value = instr->Canonicalize(); |
| 728 if (value != instr) instr->DeleteAndReplaceWith(value); | 821 if (value != instr) instr->DeleteAndReplaceWith(value); |
| 729 instr = instr->next(); | 822 instr = instr->next(); |
| 730 } | 823 } |
| (...skipping 2564 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3295 | 3388 |
| 3296 InitializeInferredTypes(); | 3389 InitializeInferredTypes(); |
| 3297 | 3390 |
| 3298 // Must be performed before canonicalization to ensure that Canonicalize | 3391 // Must be performed before canonicalization to ensure that Canonicalize |
| 3299 // will not remove semantically meaningful ToInt32 operations e.g. BIT_OR with | 3392 // will not remove semantically meaningful ToInt32 operations e.g. BIT_OR with |
| 3300 // zero. | 3393 // zero. |
| 3301 ComputeSafeUint32Operations(); | 3394 ComputeSafeUint32Operations(); |
| 3302 | 3395 |
| 3303 Canonicalize(); | 3396 Canonicalize(); |
| 3304 | 3397 |
| 3398 ProcessJSArrayLengths(); | |
| 3399 | |
| 3305 // Perform common subexpression elimination and loop-invariant code motion. | 3400 // Perform common subexpression elimination and loop-invariant code motion. |
| 3306 if (FLAG_use_gvn) { | 3401 if (FLAG_use_gvn) { |
| 3307 HPhase phase("H_Global value numbering", this); | 3402 HPhase phase("H_Global value numbering", this); |
| 3308 HGlobalValueNumberer gvn(this, info()); | 3403 HGlobalValueNumberer gvn(this, info()); |
| 3309 bool removed_side_effects = gvn.Analyze(); | 3404 bool removed_side_effects = gvn.Analyze(); |
| 3310 // Trigger a second analysis pass to further eliminate duplicate values that | 3405 // Trigger a second analysis pass to further eliminate duplicate values that |
| 3311 // could only be discovered by removing side-effect-generating instructions | 3406 // could only be discovered by removing side-effect-generating instructions |
| 3312 // during the first pass. | 3407 // during the first pass. |
| 3313 if (FLAG_smi_only_arrays && removed_side_effects) { | 3408 if (FLAG_smi_only_arrays && removed_side_effects) { |
| 3314 removed_side_effects = gvn.Analyze(); | 3409 removed_side_effects = gvn.Analyze(); |
| (...skipping 2842 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6157 new(zone()) HLoadExternalArrayPointer(elements); | 6252 new(zone()) HLoadExternalArrayPointer(elements); |
| 6158 AddInstruction(external_elements); | 6253 AddInstruction(external_elements); |
| 6159 return BuildExternalArrayElementAccess( | 6254 return BuildExternalArrayElementAccess( |
| 6160 external_elements, checked_key, val, mapcheck, | 6255 external_elements, checked_key, val, mapcheck, |
| 6161 map->elements_kind(), is_store); | 6256 map->elements_kind(), is_store); |
| 6162 } | 6257 } |
| 6163 ASSERT(fast_smi_only_elements || | 6258 ASSERT(fast_smi_only_elements || |
| 6164 fast_elements || | 6259 fast_elements || |
| 6165 map->has_fast_double_elements()); | 6260 map->has_fast_double_elements()); |
| 6166 if (map->instance_type() == JS_ARRAY_TYPE) { | 6261 if (map->instance_type() == JS_ARRAY_TYPE) { |
| 6167 length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck, | 6262 length = AddInstruction(HJSArrayLength::Create( |
| 6168 HType::Smi())); | 6263 graph(), object, mapcheck, HType::Smi())); |
| 6169 } else { | 6264 } else { |
| 6170 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); | 6265 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
| 6171 } | 6266 } |
| 6172 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, | 6267 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, |
| 6173 ALLOW_SMI_KEY)); | 6268 ALLOW_SMI_KEY)); |
| 6174 return BuildFastElementAccess(elements, checked_key, val, mapcheck, | 6269 return BuildFastElementAccess(elements, checked_key, val, mapcheck, |
| 6175 map->elements_kind(), is_store); | 6270 map->elements_kind(), is_store); |
| 6176 } | 6271 } |
| 6177 | 6272 |
| 6178 | 6273 |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6382 HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); | 6477 HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); |
| 6383 HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); | 6478 HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); |
| 6384 HHasInstanceTypeAndBranch* typecheck = | 6479 HHasInstanceTypeAndBranch* typecheck = |
| 6385 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE); | 6480 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE); |
| 6386 typecheck->SetSuccessorAt(0, if_jsarray); | 6481 typecheck->SetSuccessorAt(0, if_jsarray); |
| 6387 typecheck->SetSuccessorAt(1, if_fastobject); | 6482 typecheck->SetSuccessorAt(1, if_fastobject); |
| 6388 current_block()->Finish(typecheck); | 6483 current_block()->Finish(typecheck); |
| 6389 | 6484 |
| 6390 set_current_block(if_jsarray); | 6485 set_current_block(if_jsarray); |
| 6391 HInstruction* length; | 6486 HInstruction* length; |
| 6392 length = AddInstruction(new(zone()) HJSArrayLength(object, typecheck, | 6487 length = AddInstruction(HJSArrayLength::Create( |
| 6393 HType::Smi())); | 6488 graph(), object, typecheck, HType::Smi())); |
| 6394 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, | 6489 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length, |
| 6395 ALLOW_SMI_KEY)); | 6490 ALLOW_SMI_KEY)); |
| 6396 access = AddInstruction(BuildFastElementAccess( | 6491 access = AddInstruction(BuildFastElementAccess( |
| 6397 elements, checked_key, val, elements_kind_branch, | 6492 elements, checked_key, val, elements_kind_branch, |
| 6398 elements_kind, is_store)); | 6493 elements_kind, is_store)); |
| 6399 if (!is_store) { | 6494 if (!is_store) { |
| 6400 Push(access); | 6495 Push(access); |
| 6401 } | 6496 } |
| 6402 | 6497 |
| 6403 *has_side_effects |= access->HasObservableSideEffects(); | 6498 *has_side_effects |= access->HasObservableSideEffects(); |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6588 if (TryArgumentsAccess(expr)) return; | 6683 if (TryArgumentsAccess(expr)) return; |
| 6589 | 6684 |
| 6590 CHECK_ALIVE(VisitForValue(expr->obj())); | 6685 CHECK_ALIVE(VisitForValue(expr->obj())); |
| 6591 | 6686 |
| 6592 HInstruction* instr = NULL; | 6687 HInstruction* instr = NULL; |
| 6593 if (expr->AsProperty()->IsArrayLength()) { | 6688 if (expr->AsProperty()->IsArrayLength()) { |
| 6594 HValue* array = Pop(); | 6689 HValue* array = Pop(); |
| 6595 AddInstruction(new(zone()) HCheckNonSmi(array)); | 6690 AddInstruction(new(zone()) HCheckNonSmi(array)); |
| 6596 HInstruction* mapcheck = | 6691 HInstruction* mapcheck = |
| 6597 AddInstruction(HCheckInstanceType::NewIsJSArray(array, zone())); | 6692 AddInstruction(HCheckInstanceType::NewIsJSArray(array, zone())); |
| 6598 instr = new(zone()) HJSArrayLength(array, mapcheck); | 6693 instr = HJSArrayLength::Create(graph(), array, mapcheck); |
| 6599 } else if (expr->IsStringLength()) { | 6694 } else if (expr->IsStringLength()) { |
| 6600 HValue* string = Pop(); | 6695 HValue* string = Pop(); |
| 6601 AddInstruction(new(zone()) HCheckNonSmi(string)); | 6696 AddInstruction(new(zone()) HCheckNonSmi(string)); |
| 6602 AddInstruction(HCheckInstanceType::NewIsString(string, zone())); | 6697 AddInstruction(HCheckInstanceType::NewIsString(string, zone())); |
| 6603 instr = new(zone()) HStringLength(string); | 6698 instr = new(zone()) HStringLength(string); |
| 6604 } else if (expr->IsStringAccess()) { | 6699 } else if (expr->IsStringAccess()) { |
| 6605 CHECK_ALIVE(VisitForValue(expr->key())); | 6700 CHECK_ALIVE(VisitForValue(expr->key())); |
| 6606 HValue* index = Pop(); | 6701 HValue* index = Pop(); |
| 6607 HValue* string = Pop(); | 6702 HValue* string = Pop(); |
| 6608 HValue* context = environment()->LookupContext(); | 6703 HValue* context = environment()->LookupContext(); |
| (...skipping 3450 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 10059 } | 10154 } |
| 10060 } | 10155 } |
| 10061 | 10156 |
| 10062 #ifdef DEBUG | 10157 #ifdef DEBUG |
| 10063 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 10158 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
| 10064 if (allocator_ != NULL) allocator_->Verify(); | 10159 if (allocator_ != NULL) allocator_->Verify(); |
| 10065 #endif | 10160 #endif |
| 10066 } | 10161 } |
| 10067 | 10162 |
| 10068 } } // namespace v8::internal | 10163 } } // namespace v8::internal |
| OLD | NEW |