| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 718 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 729 order->Contains(block->end()->SecondSuccessor()) || | 729 order->Contains(block->end()->SecondSuccessor()) || |
| 730 block->end()->SecondSuccessor()->IsLoopHeader()); | 730 block->end()->SecondSuccessor()->IsLoopHeader()); |
| 731 order->Add(block); | 731 order->Add(block); |
| 732 } | 732 } |
| 733 | 733 |
| 734 | 734 |
| 735 void HGraph::AssignDominators() { | 735 void HGraph::AssignDominators() { |
| 736 HPhase phase("Assign dominators", this); | 736 HPhase phase("Assign dominators", this); |
| 737 for (int i = 0; i < blocks_.length(); ++i) { | 737 for (int i = 0; i < blocks_.length(); ++i) { |
| 738 if (blocks_[i]->IsLoopHeader()) { | 738 if (blocks_[i]->IsLoopHeader()) { |
| 739 // Only the first predecessor of a loop header is from outside the loop. |
| 740 // All others are back edges, and thus cannot dominate the loop header. |
| 739 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->first()); | 741 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->first()); |
| 740 } else { | 742 } else { |
| 741 for (int j = 0; j < blocks_[i]->predecessors()->length(); ++j) { | 743 for (int j = 0; j < blocks_[i]->predecessors()->length(); ++j) { |
| 742 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j)); | 744 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j)); |
| 743 } | 745 } |
| 744 } | 746 } |
| 745 } | 747 } |
| 748 } |
| 746 | 749 |
| 747 // Propagate flag marking blocks containing unconditional deoptimize. | 750 // Mark all blocks that are dominated by an unconditional soft deoptimize to |
| 751 // prevent code motion across those blocks. |
| 752 void HGraph::PropagateDeoptimizingMark() { |
| 753 HPhase phase("Propagate deoptimizing mark", this); |
| 748 MarkAsDeoptimizingRecursively(entry_block()); | 754 MarkAsDeoptimizingRecursively(entry_block()); |
| 749 } | 755 } |
| 750 | 756 |
| 751 | |
| 752 // Mark all blocks that are dominated by an unconditional deoptimize. | |
| 753 void HGraph::MarkAsDeoptimizingRecursively(HBasicBlock* block) { | 757 void HGraph::MarkAsDeoptimizingRecursively(HBasicBlock* block) { |
| 754 for (int i = 0; i < block->dominated_blocks()->length(); ++i) { | 758 for (int i = 0; i < block->dominated_blocks()->length(); ++i) { |
| 755 HBasicBlock* dominated = block->dominated_blocks()->at(i); | 759 HBasicBlock* dominated = block->dominated_blocks()->at(i); |
| 756 if (block->IsDeoptimizing()) dominated->MarkAsDeoptimizing(); | 760 if (block->IsDeoptimizing()) dominated->MarkAsDeoptimizing(); |
| 757 MarkAsDeoptimizingRecursively(dominated); | 761 MarkAsDeoptimizingRecursively(dominated); |
| 758 } | 762 } |
| 759 } | 763 } |
| 760 | 764 |
| 761 void HGraph::EliminateRedundantPhis() { | 765 void HGraph::EliminateRedundantPhis() { |
| 762 HPhase phase("Redundant phi elimination", this); | 766 HPhase phase("Redundant phi elimination", this); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 829 HPhi* phi = phi_list[i]; | 833 HPhi* phi = phi_list[i]; |
| 830 if (!phi->is_live()) { | 834 if (!phi->is_live()) { |
| 831 HBasicBlock* block = phi->block(); | 835 HBasicBlock* block = phi->block(); |
| 832 block->RemovePhi(phi); | 836 block->RemovePhi(phi); |
| 833 block->RecordDeletedPhi(phi->merged_index()); | 837 block->RecordDeletedPhi(phi->merged_index()); |
| 834 } | 838 } |
| 835 } | 839 } |
| 836 } | 840 } |
| 837 | 841 |
| 838 | 842 |
| 843 bool HGraph::CheckPhis() { |
| 844 int block_count = blocks_.length(); |
| 845 for (int i = 0; i < block_count; ++i) { |
| 846 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { |
| 847 HPhi* phi = blocks_[i]->phis()->at(j); |
| 848 // We don't support phi uses of arguments for now. |
| 849 if (phi->CheckFlag(HValue::kIsArguments)) return false; |
| 850 } |
| 851 } |
| 852 return true; |
| 853 } |
| 854 |
| 855 |
| 839 bool HGraph::CollectPhis() { | 856 bool HGraph::CollectPhis() { |
| 840 int block_count = blocks_.length(); | 857 int block_count = blocks_.length(); |
| 841 phi_list_ = new ZoneList<HPhi*>(block_count); | 858 phi_list_ = new ZoneList<HPhi*>(block_count); |
| 842 for (int i = 0; i < block_count; ++i) { | 859 for (int i = 0; i < block_count; ++i) { |
| 843 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { | 860 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { |
| 844 HPhi* phi = blocks_[i]->phis()->at(j); | 861 HPhi* phi = blocks_[i]->phis()->at(j); |
| 845 phi_list_->Add(phi); | 862 phi_list_->Add(phi); |
| 846 // We don't support phi uses of arguments for now. | |
| 847 if (phi->CheckFlag(HValue::kIsArguments)) return false; | |
| 848 // Check for the hole value (from an uninitialized const). | 863 // Check for the hole value (from an uninitialized const). |
| 849 for (int k = 0; k < phi->OperandCount(); k++) { | 864 for (int k = 0; k < phi->OperandCount(); k++) { |
| 850 if (phi->OperandAt(k) == GetConstantHole()) return false; | 865 if (phi->OperandAt(k) == GetConstantHole()) return false; |
| 851 } | 866 } |
| 852 } | 867 } |
| 853 } | 868 } |
| 854 return true; | 869 return true; |
| 855 } | 870 } |
| 856 | 871 |
| 857 | 872 |
| (...skipping 801 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1659 // indirectly through a transitive closure of the def-use relation. | 1674 // indirectly through a transitive closure of the def-use relation. |
| 1660 bool change = true; | 1675 bool change = true; |
| 1661 while (change) { | 1676 while (change) { |
| 1662 change = false; | 1677 change = false; |
| 1663 for (int i = 0; i < phi_count; ++i) { | 1678 for (int i = 0; i < phi_count; ++i) { |
| 1664 HPhi* phi = phi_list->at(i); | 1679 HPhi* phi = phi_list->at(i); |
| 1665 for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) { | 1680 for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) { |
| 1666 HValue* use = it.value(); | 1681 HValue* use = it.value(); |
| 1667 if (use->IsPhi()) { | 1682 if (use->IsPhi()) { |
| 1668 int id = HPhi::cast(use)->phi_id(); | 1683 int id = HPhi::cast(use)->phi_id(); |
| 1669 change = change || | 1684 if (connected_phis[i]->UnionIsChanged(*connected_phis[id])) |
| 1670 connected_phis[i]->UnionIsChanged(*connected_phis[id]); | 1685 change = true; |
| 1671 } | 1686 } |
| 1672 } | 1687 } |
| 1673 } | 1688 } |
| 1674 } | 1689 } |
| 1675 | 1690 |
| 1676 // (3) Sum up the non-phi use counts of all connected phis. Don't include | 1691 // (3) Sum up the non-phi use counts of all connected phis. Don't include |
| 1677 // the non-phi uses of the phi itself. | 1692 // the non-phi uses of the phi itself. |
| 1678 for (int i = 0; i < phi_count; ++i) { | 1693 for (int i = 0; i < phi_count; ++i) { |
| 1679 HPhi* phi = phi_list->at(i); | 1694 HPhi* phi = phi_list->at(i); |
| 1680 for (BitVector::Iterator it(connected_phis.at(i)); | 1695 for (BitVector::Iterator it(connected_phis.at(i)); |
| (...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2151 // We expect the graph to be in edge-split form: there is no edge that | 2166 // We expect the graph to be in edge-split form: there is no edge that |
| 2152 // connects a branch node to a join node. We conservatively ensure that | 2167 // connects a branch node to a join node. We conservatively ensure that |
| 2153 // property by always adding an empty block on the outgoing edges of this | 2168 // property by always adding an empty block on the outgoing edges of this |
| 2154 // branch. | 2169 // branch. |
| 2155 HGraphBuilder* builder = owner(); | 2170 HGraphBuilder* builder = owner(); |
| 2156 if (value != NULL && value->CheckFlag(HValue::kIsArguments)) { | 2171 if (value != NULL && value->CheckFlag(HValue::kIsArguments)) { |
| 2157 builder->Bailout("arguments object value in a test context"); | 2172 builder->Bailout("arguments object value in a test context"); |
| 2158 } | 2173 } |
| 2159 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); | 2174 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); |
| 2160 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); | 2175 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); |
| 2161 HBranch* test = new(zone()) HBranch(value, empty_true, empty_false); | 2176 unsigned test_id = condition()->test_id(); |
| 2177 ToBooleanStub::Types expected(builder->oracle()->ToBooleanTypes(test_id)); |
| 2178 HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected); |
| 2162 builder->current_block()->Finish(test); | 2179 builder->current_block()->Finish(test); |
| 2163 | 2180 |
| 2164 empty_true->Goto(if_true()); | 2181 empty_true->Goto(if_true()); |
| 2165 empty_false->Goto(if_false()); | 2182 empty_false->Goto(if_false()); |
| 2166 builder->set_current_block(NULL); | 2183 builder->set_current_block(NULL); |
| 2167 } | 2184 } |
| 2168 | 2185 |
| 2169 | 2186 |
| 2170 // HGraphBuilder infrastructure for bailing out and checking bailouts. | 2187 // HGraphBuilder infrastructure for bailing out and checking bailouts. |
| 2171 #define CHECK_BAILOUT(call) \ | 2188 #define CHECK_BAILOUT(call) \ |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2286 | 2303 |
| 2287 if (current_block() != NULL) { | 2304 if (current_block() != NULL) { |
| 2288 HReturn* instr = new(zone()) HReturn(graph()->GetConstantUndefined()); | 2305 HReturn* instr = new(zone()) HReturn(graph()->GetConstantUndefined()); |
| 2289 current_block()->FinishExit(instr); | 2306 current_block()->FinishExit(instr); |
| 2290 set_current_block(NULL); | 2307 set_current_block(NULL); |
| 2291 } | 2308 } |
| 2292 } | 2309 } |
| 2293 | 2310 |
| 2294 graph()->OrderBlocks(); | 2311 graph()->OrderBlocks(); |
| 2295 graph()->AssignDominators(); | 2312 graph()->AssignDominators(); |
| 2313 graph()->PropagateDeoptimizingMark(); |
| 2314 if (!graph()->CheckPhis()) { |
| 2315 Bailout("Unsupported phi use of arguments object"); |
| 2316 return NULL; |
| 2317 } |
| 2296 graph()->EliminateRedundantPhis(); | 2318 graph()->EliminateRedundantPhis(); |
| 2297 if (FLAG_eliminate_dead_phis) graph()->EliminateUnreachablePhis(); | 2319 if (FLAG_eliminate_dead_phis) graph()->EliminateUnreachablePhis(); |
| 2298 if (!graph()->CollectPhis()) { | 2320 if (!graph()->CollectPhis()) { |
| 2299 Bailout("Unsupported phi-use"); | 2321 Bailout("Unsupported phi use of uninitialized constant"); |
| 2300 return NULL; | 2322 return NULL; |
| 2301 } | 2323 } |
| 2302 | 2324 |
| 2303 HInferRepresentation rep(graph()); | 2325 HInferRepresentation rep(graph()); |
| 2304 rep.Analyze(); | 2326 rep.Analyze(); |
| 2305 | 2327 |
| 2306 if (FLAG_use_range) { | 2328 if (FLAG_use_range) { |
| 2307 HRangeAnalysis rangeAnalysis(graph()); | 2329 HRangeAnalysis rangeAnalysis(graph()); |
| 2308 rangeAnalysis.Analyze(); | 2330 rangeAnalysis.Analyze(); |
| 2309 } | 2331 } |
| (...skipping 957 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3267 // If the subexpression is a literal or a simple materialized literal it | 3289 // If the subexpression is a literal or a simple materialized literal it |
| 3268 // is already set in the cloned array. | 3290 // is already set in the cloned array. |
| 3269 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; | 3291 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; |
| 3270 | 3292 |
| 3271 CHECK_ALIVE(VisitForValue(subexpr)); | 3293 CHECK_ALIVE(VisitForValue(subexpr)); |
| 3272 HValue* value = Pop(); | 3294 HValue* value = Pop(); |
| 3273 if (!Smi::IsValid(i)) return Bailout("Non-smi key in array literal"); | 3295 if (!Smi::IsValid(i)) return Bailout("Non-smi key in array literal"); |
| 3274 | 3296 |
| 3275 // Load the elements array before the first store. | 3297 // Load the elements array before the first store. |
| 3276 if (elements == NULL) { | 3298 if (elements == NULL) { |
| 3277 elements = new(zone()) HLoadElements(literal); | 3299 elements = new(zone()) HLoadElements(literal); |
| 3278 AddInstruction(elements); | 3300 AddInstruction(elements); |
| 3279 } | 3301 } |
| 3280 | 3302 |
| 3281 HValue* key = AddInstruction( | 3303 HValue* key = AddInstruction( |
| 3282 new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)), | 3304 new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)), |
| 3283 Representation::Integer32())); | 3305 Representation::Integer32())); |
| 3284 AddInstruction(new(zone()) HStoreKeyedFastElement(elements, key, value)); | 3306 AddInstruction(new(zone()) HStoreKeyedFastElement(elements, key, value)); |
| 3285 AddSimulate(expr->GetIdForElement(i)); | 3307 AddSimulate(expr->GetIdForElement(i)); |
| 3286 } | 3308 } |
| 3287 return ast_context()->ReturnValue(Pop()); | 3309 return ast_context()->ReturnValue(Pop()); |
| 3288 } | 3310 } |
| (...skipping 605 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3894 } | 3916 } |
| 3895 | 3917 |
| 3896 | 3918 |
| 3897 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, | 3919 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, |
| 3898 HValue* key, | 3920 HValue* key, |
| 3899 HValue* val, | 3921 HValue* val, |
| 3900 Expression* expr, | 3922 Expression* expr, |
| 3901 bool is_store) { | 3923 bool is_store) { |
| 3902 ASSERT(expr->IsMonomorphic()); | 3924 ASSERT(expr->IsMonomorphic()); |
| 3903 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 3925 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| 3904 if (!map->has_fast_elements() && !map->has_external_array_elements()) { | 3926 if (!map->has_fast_elements() && |
| 3927 !map->has_fast_double_elements() && |
| 3928 !map->has_external_array_elements()) { |
| 3905 return is_store ? BuildStoreKeyedGeneric(object, key, val) | 3929 return is_store ? BuildStoreKeyedGeneric(object, key, val) |
| 3906 : BuildLoadKeyedGeneric(object, key); | 3930 : BuildLoadKeyedGeneric(object, key); |
| 3907 } | 3931 } |
| 3908 AddInstruction(new(zone()) HCheckNonSmi(object)); | 3932 AddInstruction(new(zone()) HCheckNonSmi(object)); |
| 3909 AddInstruction(new(zone()) HCheckMap(object, map)); | 3933 HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMap(object, map)); |
| 3910 HInstruction* elements = new(zone()) HLoadElements(object); | 3934 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); |
| 3935 bool fast_double_elements = map->has_fast_double_elements(); |
| 3936 if (is_store && map->has_fast_elements()) { |
| 3937 AddInstruction(new(zone()) HCheckMap( |
| 3938 elements, isolate()->factory()->fixed_array_map())); |
| 3939 } |
| 3911 HInstruction* length = NULL; | 3940 HInstruction* length = NULL; |
| 3912 HInstruction* checked_key = NULL; | 3941 HInstruction* checked_key = NULL; |
| 3913 if (map->has_external_array_elements()) { | 3942 if (map->has_external_array_elements()) { |
| 3914 AddInstruction(elements); | |
| 3915 length = AddInstruction(new(zone()) HExternalArrayLength(elements)); | 3943 length = AddInstruction(new(zone()) HExternalArrayLength(elements)); |
| 3916 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 3944 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 3917 HLoadExternalArrayPointer* external_elements = | 3945 HLoadExternalArrayPointer* external_elements = |
| 3918 new(zone()) HLoadExternalArrayPointer(elements); | 3946 new(zone()) HLoadExternalArrayPointer(elements); |
| 3919 AddInstruction(external_elements); | 3947 AddInstruction(external_elements); |
| 3920 return BuildExternalArrayElementAccess(external_elements, checked_key, | 3948 return BuildExternalArrayElementAccess(external_elements, checked_key, |
| 3921 val, map->elements_kind(), is_store); | 3949 val, map->elements_kind(), is_store); |
| 3922 } | 3950 } |
| 3923 ASSERT(map->has_fast_elements()); | 3951 ASSERT(map->has_fast_elements() || fast_double_elements); |
| 3924 if (map->instance_type() == JS_ARRAY_TYPE) { | 3952 if (map->instance_type() == JS_ARRAY_TYPE) { |
| 3925 length = AddInstruction(new(zone()) HJSArrayLength(object)); | 3953 length = AddInstruction(new(zone()) HJSArrayLength(object, mapcheck)); |
| 3926 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | |
| 3927 AddInstruction(elements); | |
| 3928 } else { | 3954 } else { |
| 3929 AddInstruction(elements); | |
| 3930 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); | 3955 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); |
| 3931 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | |
| 3932 } | 3956 } |
| 3957 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 3933 if (is_store) { | 3958 if (is_store) { |
| 3934 return new(zone()) HStoreKeyedFastElement(elements, checked_key, val); | 3959 if (fast_double_elements) { |
| 3960 return new(zone()) HStoreKeyedFastDoubleElement(elements, |
| 3961 checked_key, |
| 3962 val); |
| 3963 } else { |
| 3964 return new(zone()) HStoreKeyedFastElement(elements, checked_key, val); |
| 3965 } |
| 3935 } else { | 3966 } else { |
| 3936 return new(zone()) HLoadKeyedFastElement(elements, checked_key); | 3967 if (fast_double_elements) { |
| 3968 return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key); |
| 3969 } else { |
| 3970 return new(zone()) HLoadKeyedFastElement(elements, checked_key); |
| 3971 } |
| 3937 } | 3972 } |
| 3938 } | 3973 } |
| 3939 | 3974 |
| 3940 | 3975 |
| 3941 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, | 3976 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, |
| 3942 HValue* key, | 3977 HValue* key, |
| 3943 HValue* val, | 3978 HValue* val, |
| 3944 Expression* prop, | 3979 Expression* prop, |
| 3945 int ast_id, | 3980 int ast_id, |
| 3946 int position, | 3981 int position, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3959 } | 3994 } |
| 3960 | 3995 |
| 3961 for (int i = 0; i < maps->length(); ++i) { | 3996 for (int i = 0; i < maps->length(); ++i) { |
| 3962 ASSERT(maps->at(i)->IsMap()); | 3997 ASSERT(maps->at(i)->IsMap()); |
| 3963 type_todo[maps->at(i)->elements_kind()] = true; | 3998 type_todo[maps->at(i)->elements_kind()] = true; |
| 3964 if (maps->at(i)->elements_kind() | 3999 if (maps->at(i)->elements_kind() |
| 3965 >= JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) { | 4000 >= JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) { |
| 3966 todo_external_array = true; | 4001 todo_external_array = true; |
| 3967 } | 4002 } |
| 3968 } | 4003 } |
| 3969 // Support for FAST_DOUBLE_ELEMENTS isn't implemented yet, so we deopt. | |
| 3970 type_todo[JSObject::FAST_DOUBLE_ELEMENTS] = false; | |
| 3971 | 4004 |
| 3972 HBasicBlock* join = graph()->CreateBasicBlock(); | 4005 HBasicBlock* join = graph()->CreateBasicBlock(); |
| 3973 | 4006 |
| 3974 HInstruction* elements_kind_instr = | 4007 HInstruction* elements_kind_instr = |
| 3975 AddInstruction(new(zone()) HElementsKind(object)); | 4008 AddInstruction(new(zone()) HElementsKind(object)); |
| 3976 HInstruction* elements = NULL; | 4009 HCompareConstantEqAndBranch* elements_kind_branch = NULL; |
| 4010 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); |
| 3977 HLoadExternalArrayPointer* external_elements = NULL; | 4011 HLoadExternalArrayPointer* external_elements = NULL; |
| 3978 HInstruction* checked_key = NULL; | 4012 HInstruction* checked_key = NULL; |
| 3979 | 4013 |
| 3980 // FAST_ELEMENTS is assumed to be the first case. | 4014 // FAST_ELEMENTS is assumed to be the first case. |
| 3981 STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0); | 4015 STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0); |
| 3982 | 4016 |
| 3983 for (JSObject::ElementsKind elements_kind = JSObject::FAST_ELEMENTS; | 4017 for (JSObject::ElementsKind elements_kind = JSObject::FAST_ELEMENTS; |
| 3984 elements_kind <= JSObject::LAST_ELEMENTS_KIND; | 4018 elements_kind <= JSObject::LAST_ELEMENTS_KIND; |
| 3985 elements_kind = JSObject::ElementsKind(elements_kind + 1)) { | 4019 elements_kind = JSObject::ElementsKind(elements_kind + 1)) { |
| 3986 // After having handled FAST_ELEMENTS and DICTIONARY_ELEMENTS, we | 4020 // After having handled FAST_ELEMENTS and DICTIONARY_ELEMENTS, we |
| 3987 // need to add some code that's executed for all external array cases. | 4021 // need to add some code that's executed for all external array cases. |
| 3988 STATIC_ASSERT(JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND == | 4022 STATIC_ASSERT(JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND == |
| 3989 JSObject::LAST_ELEMENTS_KIND); | 4023 JSObject::LAST_ELEMENTS_KIND); |
| 3990 if (elements_kind == JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND | 4024 if (elements_kind == JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND |
| 3991 && todo_external_array) { | 4025 && todo_external_array) { |
| 3992 elements = AddInstruction(new(zone()) HLoadElements(object)); | |
| 3993 // We need to forcibly prevent some ElementsKind-dependent instructions | |
| 3994 // from being hoisted out of any loops they might occur in, because | |
| 3995 // the current loop-invariant-code-motion algorithm isn't clever enough | |
| 3996 // to deal with them properly. | |
| 3997 // There's some performance to be gained by developing a smarter | |
| 3998 // solution for this. | |
| 3999 elements->ClearFlag(HValue::kUseGVN); | |
| 4000 HInstruction* length = | 4026 HInstruction* length = |
| 4001 AddInstruction(new(zone()) HExternalArrayLength(elements)); | 4027 AddInstruction(new(zone()) HExternalArrayLength(elements)); |
| 4002 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 4028 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 4003 external_elements = new(zone()) HLoadExternalArrayPointer(elements); | 4029 external_elements = new(zone()) HLoadExternalArrayPointer(elements); |
| 4004 AddInstruction(external_elements); | 4030 AddInstruction(external_elements); |
| 4005 } | 4031 } |
| 4006 if (type_todo[elements_kind]) { | 4032 if (type_todo[elements_kind]) { |
| 4007 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 4033 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 4008 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 4034 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 4009 HCompareConstantEqAndBranch* compare = | 4035 elements_kind_branch = new(zone()) HCompareConstantEqAndBranch( |
| 4010 new(zone()) HCompareConstantEqAndBranch(elements_kind_instr, | 4036 elements_kind_instr, elements_kind, Token::EQ_STRICT); |
| 4011 elements_kind, | 4037 elements_kind_branch->SetSuccessorAt(0, if_true); |
| 4012 Token::EQ_STRICT); | 4038 elements_kind_branch->SetSuccessorAt(1, if_false); |
| 4013 compare->SetSuccessorAt(0, if_true); | 4039 current_block()->Finish(elements_kind_branch); |
| 4014 compare->SetSuccessorAt(1, if_false); | |
| 4015 current_block()->Finish(compare); | |
| 4016 | 4040 |
| 4017 set_current_block(if_true); | 4041 set_current_block(if_true); |
| 4018 HInstruction* access; | 4042 HInstruction* access; |
| 4019 if (elements_kind == JSObject::FAST_ELEMENTS) { | 4043 if (elements_kind == JSObject::FAST_ELEMENTS || |
| 4044 elements_kind == JSObject::FAST_DOUBLE_ELEMENTS) { |
| 4045 bool fast_double_elements = |
| 4046 elements_kind == JSObject::FAST_DOUBLE_ELEMENTS; |
| 4047 if (is_store && elements_kind == JSObject::FAST_ELEMENTS) { |
| 4048 AddInstruction(new(zone()) HCheckMap( |
| 4049 elements, isolate()->factory()->fixed_array_map(), |
| 4050 elements_kind_branch)); |
| 4051 } |
| 4020 HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); | 4052 HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); |
| 4021 HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); | 4053 HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); |
| 4022 HHasInstanceTypeAndBranch* typecheck = | 4054 HHasInstanceTypeAndBranch* typecheck = |
| 4023 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE); | 4055 new(zone()) HHasInstanceTypeAndBranch(object, JS_ARRAY_TYPE); |
| 4024 typecheck->SetSuccessorAt(0, if_jsarray); | 4056 typecheck->SetSuccessorAt(0, if_jsarray); |
| 4025 typecheck->SetSuccessorAt(1, if_fastobject); | 4057 typecheck->SetSuccessorAt(1, if_fastobject); |
| 4026 current_block()->Finish(typecheck); | 4058 current_block()->Finish(typecheck); |
| 4027 | 4059 |
| 4028 set_current_block(if_jsarray); | 4060 set_current_block(if_jsarray); |
| 4029 HInstruction* length = new(zone()) HJSArrayLength(object); | 4061 HInstruction* length = new(zone()) HJSArrayLength(object, typecheck); |
| 4030 AddInstruction(length); | 4062 AddInstruction(length); |
| 4031 length->ClearFlag(HValue::kUseGVN); | |
| 4032 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 4063 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 4033 elements = AddInstruction(new(zone()) HLoadElements(object)); | |
| 4034 elements->ClearFlag(HValue::kUseGVN); | |
| 4035 if (is_store) { | 4064 if (is_store) { |
| 4036 access = AddInstruction( | 4065 if (fast_double_elements) { |
| 4037 new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); | 4066 access = AddInstruction( |
| 4067 new(zone()) HStoreKeyedFastDoubleElement(elements, |
| 4068 checked_key, |
| 4069 val)); |
| 4070 } else { |
| 4071 access = AddInstruction( |
| 4072 new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); |
| 4073 } |
| 4038 } else { | 4074 } else { |
| 4039 access = AddInstruction( | 4075 if (fast_double_elements) { |
| 4040 new(zone()) HLoadKeyedFastElement(elements, checked_key)); | 4076 access = AddInstruction( |
| 4077 new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key)); |
| 4078 } else { |
| 4079 access = AddInstruction( |
| 4080 new(zone()) HLoadKeyedFastElement(elements, checked_key)); |
| 4081 } |
| 4041 Push(access); | 4082 Push(access); |
| 4042 } | 4083 } |
| 4043 *has_side_effects |= access->HasSideEffects(); | 4084 *has_side_effects |= access->HasSideEffects(); |
| 4044 if (position != -1) { | 4085 if (position != -1) { |
| 4045 access->set_position(position); | 4086 access->set_position(position); |
| 4046 } | 4087 } |
| 4047 if_jsarray->Goto(join); | 4088 if_jsarray->Goto(join); |
| 4048 | 4089 |
| 4049 set_current_block(if_fastobject); | 4090 set_current_block(if_fastobject); |
| 4050 elements = AddInstruction(new(zone()) HLoadElements(object)); | |
| 4051 elements->ClearFlag(HValue::kUseGVN); | |
| 4052 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); | 4091 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); |
| 4053 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 4092 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 4054 if (is_store) { | 4093 if (is_store) { |
| 4055 access = AddInstruction( | 4094 if (fast_double_elements) { |
| 4056 new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); | 4095 access = AddInstruction( |
| 4096 new(zone()) HStoreKeyedFastDoubleElement(elements, |
| 4097 checked_key, |
| 4098 val)); |
| 4099 } else { |
| 4100 access = AddInstruction( |
| 4101 new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); |
| 4102 } |
| 4057 } else { | 4103 } else { |
| 4058 access = AddInstruction( | 4104 if (fast_double_elements) { |
| 4059 new(zone()) HLoadKeyedFastElement(elements, checked_key)); | 4105 access = AddInstruction( |
| 4106 new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key)); |
| 4107 } else { |
| 4108 access = AddInstruction( |
| 4109 new(zone()) HLoadKeyedFastElement(elements, checked_key)); |
| 4110 } |
| 4060 } | 4111 } |
| 4061 } else if (elements_kind == JSObject::DICTIONARY_ELEMENTS) { | 4112 } else if (elements_kind == JSObject::DICTIONARY_ELEMENTS) { |
| 4062 if (is_store) { | 4113 if (is_store) { |
| 4063 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); | 4114 access = AddInstruction(BuildStoreKeyedGeneric(object, key, val)); |
| 4064 } else { | 4115 } else { |
| 4065 access = AddInstruction(BuildLoadKeyedGeneric(object, key)); | 4116 access = AddInstruction(BuildLoadKeyedGeneric(object, key)); |
| 4066 } | 4117 } |
| 4067 } else { // External array elements. | 4118 } else { // External array elements. |
| 4068 access = AddInstruction(BuildExternalArrayElementAccess( | 4119 access = AddInstruction(BuildExternalArrayElementAccess( |
| 4069 external_elements, checked_key, val, elements_kind, is_store)); | 4120 external_elements, checked_key, val, elements_kind, is_store)); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4174 expr->RecordTypeFeedback(oracle()); | 4225 expr->RecordTypeFeedback(oracle()); |
| 4175 | 4226 |
| 4176 if (TryArgumentsAccess(expr)) return; | 4227 if (TryArgumentsAccess(expr)) return; |
| 4177 | 4228 |
| 4178 CHECK_ALIVE(VisitForValue(expr->obj())); | 4229 CHECK_ALIVE(VisitForValue(expr->obj())); |
| 4179 | 4230 |
| 4180 HInstruction* instr = NULL; | 4231 HInstruction* instr = NULL; |
| 4181 if (expr->IsArrayLength()) { | 4232 if (expr->IsArrayLength()) { |
| 4182 HValue* array = Pop(); | 4233 HValue* array = Pop(); |
| 4183 AddInstruction(new(zone()) HCheckNonSmi(array)); | 4234 AddInstruction(new(zone()) HCheckNonSmi(array)); |
| 4184 AddInstruction(HCheckInstanceType::NewIsJSArray(array)); | 4235 HInstruction* mapcheck = |
| 4185 instr = new(zone()) HJSArrayLength(array); | 4236 AddInstruction(HCheckInstanceType::NewIsJSArray(array)); |
| 4237 instr = new(zone()) HJSArrayLength(array, mapcheck); |
| 4186 | 4238 |
| 4187 } else if (expr->IsStringLength()) { | 4239 } else if (expr->IsStringLength()) { |
| 4188 HValue* string = Pop(); | 4240 HValue* string = Pop(); |
| 4189 AddInstruction(new(zone()) HCheckNonSmi(string)); | 4241 AddInstruction(new(zone()) HCheckNonSmi(string)); |
| 4190 AddInstruction(HCheckInstanceType::NewIsString(string)); | 4242 AddInstruction(HCheckInstanceType::NewIsString(string)); |
| 4191 instr = new(zone()) HStringLength(string); | 4243 instr = new(zone()) HStringLength(string); |
| 4192 } else if (expr->IsStringAccess()) { | 4244 } else if (expr->IsStringAccess()) { |
| 4193 CHECK_ALIVE(VisitForValue(expr->key())); | 4245 CHECK_ALIVE(VisitForValue(expr->key())); |
| 4194 HValue* index = Pop(); | 4246 HValue* index = Pop(); |
| 4195 HValue* string = Pop(); | 4247 HValue* string = Pop(); |
| (...skipping 1271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5467 Visit(expr->right()); | 5519 Visit(expr->right()); |
| 5468 } | 5520 } |
| 5469 | 5521 |
| 5470 } else if (ast_context()->IsValue()) { | 5522 } else if (ast_context()->IsValue()) { |
| 5471 CHECK_ALIVE(VisitForValue(expr->left())); | 5523 CHECK_ALIVE(VisitForValue(expr->left())); |
| 5472 ASSERT(current_block() != NULL); | 5524 ASSERT(current_block() != NULL); |
| 5473 | 5525 |
| 5474 // We need an extra block to maintain edge-split form. | 5526 // We need an extra block to maintain edge-split form. |
| 5475 HBasicBlock* empty_block = graph()->CreateBasicBlock(); | 5527 HBasicBlock* empty_block = graph()->CreateBasicBlock(); |
| 5476 HBasicBlock* eval_right = graph()->CreateBasicBlock(); | 5528 HBasicBlock* eval_right = graph()->CreateBasicBlock(); |
| 5529 unsigned test_id = expr->left()->test_id(); |
| 5530 ToBooleanStub::Types expected(oracle()->ToBooleanTypes(test_id)); |
| 5477 HBranch* test = is_logical_and | 5531 HBranch* test = is_logical_and |
| 5478 ? new(zone()) HBranch(Top(), eval_right, empty_block) | 5532 ? new(zone()) HBranch(Top(), eval_right, empty_block, expected) |
| 5479 : new(zone()) HBranch(Top(), empty_block, eval_right); | 5533 : new(zone()) HBranch(Top(), empty_block, eval_right, expected); |
| 5480 current_block()->Finish(test); | 5534 current_block()->Finish(test); |
| 5481 | 5535 |
| 5482 set_current_block(eval_right); | 5536 set_current_block(eval_right); |
| 5483 Drop(1); // Value of the left subexpression. | 5537 Drop(1); // Value of the left subexpression. |
| 5484 CHECK_BAILOUT(VisitForValue(expr->right())); | 5538 CHECK_BAILOUT(VisitForValue(expr->right())); |
| 5485 | 5539 |
| 5486 HBasicBlock* join_block = | 5540 HBasicBlock* join_block = |
| 5487 CreateJoin(empty_block, current_block(), expr->id()); | 5541 CreateJoin(empty_block, current_block(), expr->id()); |
| 5488 set_current_block(join_block); | 5542 set_current_block(join_block); |
| 5489 return ast_context()->ReturnValue(Pop()); | 5543 return ast_context()->ReturnValue(Pop()); |
| (...skipping 1202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6692 } | 6746 } |
| 6693 } | 6747 } |
| 6694 | 6748 |
| 6695 #ifdef DEBUG | 6749 #ifdef DEBUG |
| 6696 if (graph_ != NULL) graph_->Verify(); | 6750 if (graph_ != NULL) graph_->Verify(); |
| 6697 if (allocator_ != NULL) allocator_->Verify(); | 6751 if (allocator_ != NULL) allocator_->Verify(); |
| 6698 #endif | 6752 #endif |
| 6699 } | 6753 } |
| 6700 | 6754 |
| 6701 } } // namespace v8::internal | 6755 } } // namespace v8::internal |
| OLD | NEW |