OLD | NEW |
---|---|
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
6 | 6 |
7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
9 #include "vm/flow_graph_builder.h" | 9 #include "vm/flow_graph_builder.h" |
10 #include "vm/flow_graph_compiler.h" | 10 #include "vm/flow_graph_compiler.h" |
(...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
544 ConstantInstr* array_def = (*array)->definition()->AsConstant(); | 544 ConstantInstr* array_def = (*array)->definition()->AsConstant(); |
545 const ImmutableArray& constant_array = | 545 const ImmutableArray& constant_array = |
546 ImmutableArray::Cast(array_def->value()); | 546 ImmutableArray::Cast(array_def->value()); |
547 ConstantInstr* index_def = (*index)->definition()->AsConstant(); | 547 ConstantInstr* index_def = (*index)->definition()->AsConstant(); |
548 if (index_def->value().IsSmi()) { | 548 if (index_def->value().IsSmi()) { |
549 intptr_t constant_index = Smi::Cast(index_def->value()).Value(); | 549 intptr_t constant_index = Smi::Cast(index_def->value()).Value(); |
550 skip_check = (constant_index < constant_array.Length()); | 550 skip_check = (constant_index < constant_array.Length()); |
551 } | 551 } |
552 } | 552 } |
553 if (!skip_check) { | 553 if (!skip_check) { |
554 // Insert array bounds check. | 554 // Insert array length load and bounds check. |
555 const bool is_immutable = (class_id != kGrowableObjectArrayCid); | |
srdjan
2013/02/01 19:01:28
It may be better to compute is_immutable by checki
Florian Schneider
2013/02/06 13:08:19
Agree. I'll change it.
| |
556 LoadFieldInstr* length = new LoadFieldInstr( | |
557 (*array)->Copy(), | |
558 CheckArrayBoundInstr::LengthOffsetFor(class_id), | |
559 Type::ZoneHandle(Type::SmiType()), | |
560 is_immutable); | |
561 length->set_result_cid(kSmiCid); | |
562 length->set_recognized_kind( | |
563 LoadFieldInstr::RecognizedKindFromArrayCid(class_id)); | |
564 InsertBefore(call, length, NULL, Definition::kValue); | |
555 InsertBefore(call, | 565 InsertBefore(call, |
556 new CheckArrayBoundInstr((*array)->Copy(), | 566 new CheckArrayBoundInstr(new Value(length), |
557 (*index)->Copy(), | 567 (*index)->Copy(), |
558 class_id, | 568 class_id, |
559 call), | 569 call), |
560 call->env(), | 570 call->env(), |
561 Definition::kEffect); | 571 Definition::kEffect); |
562 } | 572 } |
563 if (class_id == kGrowableObjectArrayCid) { | 573 if (class_id == kGrowableObjectArrayCid) { |
564 // Insert data elements load. | 574 // Insert data elements load. |
565 LoadFieldInstr* elements = | 575 LoadFieldInstr* elements = |
566 new LoadFieldInstr((*array)->Copy(), | 576 new LoadFieldInstr((*array)->Copy(), |
(...skipping 725 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1292 const String& constant_string = | 1302 const String& constant_string = |
1293 String::Cast(string_def->value()); | 1303 String::Cast(string_def->value()); |
1294 ConstantInstr* index_def = index->definition()->AsConstant(); | 1304 ConstantInstr* index_def = index->definition()->AsConstant(); |
1295 if (index_def->value().IsSmi()) { | 1305 if (index_def->value().IsSmi()) { |
1296 intptr_t constant_index = Smi::Cast(index_def->value()).Value(); | 1306 intptr_t constant_index = Smi::Cast(index_def->value()).Value(); |
1297 skip_check = (constant_index < constant_string.Length()); | 1307 skip_check = (constant_index < constant_string.Length()); |
1298 } | 1308 } |
1299 } | 1309 } |
1300 if (!skip_check) { | 1310 if (!skip_check) { |
1301 // Insert bounds check. | 1311 // Insert bounds check. |
1312 const bool is_immutable = true; | |
1313 LoadFieldInstr* length = new LoadFieldInstr( | |
1314 str->Copy(), | |
1315 CheckArrayBoundInstr::LengthOffsetFor(cid), | |
1316 Type::ZoneHandle(Type::SmiType()), | |
1317 is_immutable); | |
1318 length->set_result_cid(kSmiCid); | |
1319 length->set_recognized_kind(MethodRecognizer::kStringBaseLength); | |
1320 InsertBefore(call, length, NULL, Definition::kValue); | |
1302 InsertBefore(call, | 1321 InsertBefore(call, |
1303 new CheckArrayBoundInstr(str->Copy(), | 1322 new CheckArrayBoundInstr(new Value(length), |
1304 index->Copy(), | 1323 index->Copy(), |
1305 cid, | 1324 cid, |
1306 call), | 1325 call), |
1307 call->env(), | 1326 call->env(), |
1308 Definition::kEffect); | 1327 Definition::kEffect); |
1309 } | 1328 } |
1310 return new LoadIndexedInstr(str, index, cid, Isolate::kNoDeoptId); | 1329 return new LoadIndexedInstr(str, index, cid, Isolate::kNoDeoptId); |
1311 } | 1330 } |
1312 | 1331 |
1313 | 1332 |
(...skipping 724 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2038 | 2057 |
2039 // Create a constraint for defn, insert it after given instruction and | 2058 // Create a constraint for defn, insert it after given instruction and |
2040 // rename all uses that are dominated by it. | 2059 // rename all uses that are dominated by it. |
2041 ConstraintInstr* InsertConstraintFor(Definition* defn, | 2060 ConstraintInstr* InsertConstraintFor(Definition* defn, |
2042 Range* constraint, | 2061 Range* constraint, |
2043 Instruction* after); | 2062 Instruction* after); |
2044 | 2063 |
2045 void ConstrainValueAfterBranch(Definition* defn, Value* use); | 2064 void ConstrainValueAfterBranch(Definition* defn, Value* use); |
2046 void ConstrainValueAfterCheckArrayBound(Definition* defn, | 2065 void ConstrainValueAfterCheckArrayBound(Definition* defn, |
2047 CheckArrayBoundInstr* check); | 2066 CheckArrayBoundInstr* check); |
2048 Definition* LoadArrayLength(CheckArrayBoundInstr* check); | |
2049 | 2067 |
2050 // Replace uses of the definition def that are dominated by instruction dom | 2068 // Replace uses of the definition def that are dominated by instruction dom |
2051 // with uses of other definition. | 2069 // with uses of other definition. |
2052 void RenameDominatedUses(Definition* def, | 2070 void RenameDominatedUses(Definition* def, |
2053 Instruction* dom, | 2071 Instruction* dom, |
2054 Definition* other); | 2072 Definition* other); |
2055 | 2073 |
2056 | 2074 |
2057 // Walk the dominator tree and infer ranges for smi values. | 2075 // Walk the dominator tree and infer ranges for smi values. |
2058 void InferRanges(); | 2076 void InferRanges(); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2098 // as smi values. | 2116 // as smi values. |
2099 GrowableArray<ConstraintInstr*> constraints_; | 2117 GrowableArray<ConstraintInstr*> constraints_; |
2100 | 2118 |
2101 // Bitvector for a quick filtering of known smi values. | 2119 // Bitvector for a quick filtering of known smi values. |
2102 BitVector* smi_definitions_; | 2120 BitVector* smi_definitions_; |
2103 | 2121 |
2104 // Worklist for induction variables analysis. | 2122 // Worklist for induction variables analysis. |
2105 GrowableArray<Definition*> worklist_; | 2123 GrowableArray<Definition*> worklist_; |
2106 BitVector* marked_defns_; | 2124 BitVector* marked_defns_; |
2107 | 2125 |
2108 class ArrayLengthData : public ValueObject { | |
2109 public: | |
2110 ArrayLengthData(Definition* array, Definition* array_length) | |
2111 : array_(array), array_length_(array_length) { } | |
2112 | |
2113 ArrayLengthData(const ArrayLengthData& other) | |
2114 : ValueObject(), | |
2115 array_(other.array_), | |
2116 array_length_(other.array_length_) { } | |
2117 | |
2118 ArrayLengthData& operator=(const ArrayLengthData& other) { | |
2119 array_ = other.array_; | |
2120 array_length_ = other.array_length_; | |
2121 return *this; | |
2122 } | |
2123 | |
2124 Definition* array() const { return array_; } | |
2125 Definition* array_length() const { return array_length_; } | |
2126 | |
2127 typedef Definition* Value; | |
2128 typedef Definition* Key; | |
2129 typedef class ArrayLengthData Pair; | |
2130 | |
2131 // KeyValueTrait members. | |
2132 static Key KeyOf(const ArrayLengthData& data) { | |
2133 return data.array(); | |
2134 } | |
2135 | |
2136 static Value ValueOf(const ArrayLengthData& data) { | |
2137 return data.array_length(); | |
2138 } | |
2139 | |
2140 static inline intptr_t Hashcode(Key key) { | |
2141 return reinterpret_cast<intptr_t>(key); | |
2142 } | |
2143 | |
2144 static inline bool IsKeyEqual(const ArrayLengthData& kv, Key key) { | |
2145 return kv.array() == key; | |
2146 } | |
2147 | |
2148 private: | |
2149 Definition* array_; | |
2150 Definition* array_length_; | |
2151 }; | |
2152 | |
2153 DirectChainedHashMap<ArrayLengthData> array_lengths_; | |
2154 | |
2155 DISALLOW_COPY_AND_ASSIGN(RangeAnalysis); | 2126 DISALLOW_COPY_AND_ASSIGN(RangeAnalysis); |
2156 }; | 2127 }; |
2157 | 2128 |
2158 | 2129 |
2159 void RangeAnalysis::Analyze() { | 2130 void RangeAnalysis::Analyze() { |
2160 CollectSmiValues(); | 2131 CollectSmiValues(); |
2161 InsertConstraints(); | 2132 InsertConstraints(); |
2162 InferRanges(); | 2133 InferRanges(); |
2163 RemoveConstraints(); | 2134 RemoveConstraints(); |
2164 } | 2135 } |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2378 ConstrainValueAfterBranch(defn, use); | 2349 ConstrainValueAfterBranch(defn, use); |
2379 } else if (use->instruction()->IsCheckArrayBound()) { | 2350 } else if (use->instruction()->IsCheckArrayBound()) { |
2380 ConstrainValueAfterCheckArrayBound( | 2351 ConstrainValueAfterCheckArrayBound( |
2381 defn, | 2352 defn, |
2382 use->instruction()->AsCheckArrayBound()); | 2353 use->instruction()->AsCheckArrayBound()); |
2383 } | 2354 } |
2384 } | 2355 } |
2385 } | 2356 } |
2386 | 2357 |
2387 | 2358 |
2388 Definition* RangeAnalysis::LoadArrayLength(CheckArrayBoundInstr* check) { | |
2389 Definition* array = check->array()->definition(); | |
2390 | |
2391 Definition* length = array_lengths_.Lookup(array); | |
2392 if (length != NULL) return length; | |
2393 | |
2394 StaticCallInstr* allocation = array->AsStaticCall(); | |
2395 if ((allocation != NULL) && | |
2396 allocation->is_known_constructor() && | |
2397 (allocation->ResultCid() == kArrayCid)) { | |
2398 // For fixed length arrays check if array is the result of a constructor | |
2399 // call. In this case we can use the length passed to the constructor | |
2400 // instead of loading it from array itself. | |
2401 length = allocation->ArgumentAt(1)->value()->definition(); | |
2402 } else { | |
2403 // Load length from the array. Do not insert instruction into the graph. | |
2404 // It will only be used in range boundaries. | |
2405 LoadFieldInstr* length_load = new LoadFieldInstr( | |
2406 check->array()->Copy(), | |
2407 CheckArrayBoundInstr::LengthOffsetFor(check->array_type()), | |
2408 Type::ZoneHandle(Type::SmiType()), | |
2409 true); // Immutable. | |
2410 length_load->set_recognized_kind(MethodRecognizer::kObjectArrayLength); | |
2411 length_load->set_result_cid(kSmiCid); | |
2412 length_load->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); | |
2413 length = length_load; | |
2414 } | |
2415 | |
2416 ASSERT(length != NULL); | |
2417 array_lengths_.Insert(ArrayLengthData(array, length)); | |
2418 return length; | |
2419 } | |
2420 | |
2421 | |
2422 void RangeAnalysis::ConstrainValueAfterCheckArrayBound( | 2359 void RangeAnalysis::ConstrainValueAfterCheckArrayBound( |
2423 Definition* defn, CheckArrayBoundInstr* check) { | 2360 Definition* defn, CheckArrayBoundInstr* check) { |
2424 if (!CheckArrayBoundInstr::IsFixedLengthArrayType(check->array_type())) { | 2361 if (!CheckArrayBoundInstr::IsFixedLengthArrayType(check->array_type())) { |
2425 return; | 2362 return; |
2426 } | 2363 } |
2427 | 2364 |
2428 Definition* length = LoadArrayLength(check); | 2365 Definition* length = check->length()->definition(); |
2429 | 2366 |
2430 Range* constraint_range = new Range( | 2367 Range* constraint_range = new Range( |
2431 RangeBoundary::FromConstant(0), | 2368 RangeBoundary::FromConstant(0), |
2432 RangeBoundary::FromDefinition(length, -1)); | 2369 RangeBoundary::FromDefinition(length, -1)); |
2433 InsertConstraintFor(defn, constraint_range, check); | 2370 InsertConstraintFor(defn, constraint_range, check); |
2434 } | 2371 } |
2435 | 2372 |
2436 | 2373 |
2437 void RangeAnalysis::InsertConstraints() { | 2374 void RangeAnalysis::InsertConstraints() { |
2438 for (intptr_t i = 0; i < smi_checks_.length(); i++) { | 2375 for (intptr_t i = 0; i < smi_checks_.length(); i++) { |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2615 | 2552 |
2616 Definition* defn = current->AsDefinition(); | 2553 Definition* defn = current->AsDefinition(); |
2617 if ((defn != NULL) && | 2554 if ((defn != NULL) && |
2618 (defn->ssa_temp_index() != -1) && | 2555 (defn->ssa_temp_index() != -1) && |
2619 smi_definitions_->Contains(defn->ssa_temp_index())) { | 2556 smi_definitions_->Contains(defn->ssa_temp_index())) { |
2620 defn->InferRange(); | 2557 defn->InferRange(); |
2621 } else if (FLAG_array_bounds_check_elimination && | 2558 } else if (FLAG_array_bounds_check_elimination && |
2622 current->IsCheckArrayBound()) { | 2559 current->IsCheckArrayBound()) { |
2623 CheckArrayBoundInstr* check = current->AsCheckArrayBound(); | 2560 CheckArrayBoundInstr* check = current->AsCheckArrayBound(); |
2624 RangeBoundary array_length = | 2561 RangeBoundary array_length = |
2625 RangeBoundary::FromDefinition(LoadArrayLength(check)); | 2562 RangeBoundary::FromDefinition(check->length()->definition()); |
2626 if (check->IsRedundant(array_length)) it.RemoveCurrentFromGraph(); | 2563 if (check->IsRedundant(array_length)) it.RemoveCurrentFromGraph(); |
2627 } | 2564 } |
2628 } | 2565 } |
2629 | 2566 |
2630 for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) { | 2567 for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) { |
2631 InferRangesRecursive(block->dominated_blocks()[i]); | 2568 InferRangesRecursive(block->dominated_blocks()[i]); |
2632 } | 2569 } |
2633 } | 2570 } |
2634 | 2571 |
2635 | 2572 |
(...skipping 1569 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4205 } | 4142 } |
4206 | 4143 |
4207 | 4144 |
4208 void ConstantPropagator::VisitLoadField(LoadFieldInstr* instr) { | 4145 void ConstantPropagator::VisitLoadField(LoadFieldInstr* instr) { |
4209 if ((instr->recognized_kind() == MethodRecognizer::kObjectArrayLength) && | 4146 if ((instr->recognized_kind() == MethodRecognizer::kObjectArrayLength) && |
4210 (instr->value()->definition()->IsCreateArray())) { | 4147 (instr->value()->definition()->IsCreateArray())) { |
4211 const intptr_t length = | 4148 const intptr_t length = |
4212 instr->value()->definition()->AsCreateArray()->ArgumentCount(); | 4149 instr->value()->definition()->AsCreateArray()->ArgumentCount(); |
4213 const Object& result = Smi::ZoneHandle(Smi::New(length)); | 4150 const Object& result = Smi::ZoneHandle(Smi::New(length)); |
4214 SetValue(instr, result); | 4151 SetValue(instr, result); |
4215 } else { | 4152 return; |
4216 SetValue(instr, non_constant_); | |
4217 } | 4153 } |
4154 | |
4155 if (instr->IsImmutableLengthLoad()) { | |
4156 ConstantInstr* constant = instr->value()->definition()->AsConstant(); | |
4157 if (constant != NULL) { | |
4158 if (constant->value().IsString()) { | |
4159 SetValue(instr, Smi::ZoneHandle( | |
4160 Smi::New(String::Cast(constant->value()).Length()))); | |
4161 return; | |
4162 } | |
4163 if (constant->value().IsArray()) { | |
4164 SetValue(instr, Smi::ZoneHandle( | |
4165 Smi::New(Array::Cast(constant->value()).Length()))); | |
4166 return; | |
4167 } | |
4168 } | |
4169 } | |
4170 SetValue(instr, non_constant_); | |
4218 } | 4171 } |
4219 | 4172 |
4220 | 4173 |
4221 void ConstantPropagator::VisitStoreVMField(StoreVMFieldInstr* instr) { | 4174 void ConstantPropagator::VisitStoreVMField(StoreVMFieldInstr* instr) { |
4222 SetValue(instr, instr->value()->definition()->constant_value()); | 4175 SetValue(instr, instr->value()->definition()->constant_value()); |
4223 } | 4176 } |
4224 | 4177 |
4225 | 4178 |
4226 void ConstantPropagator::VisitInstantiateTypeArguments( | 4179 void ConstantPropagator::VisitInstantiateTypeArguments( |
4227 InstantiateTypeArgumentsInstr* instr) { | 4180 InstantiateTypeArgumentsInstr* instr) { |
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4605 | 4558 |
4606 if (FLAG_trace_constant_propagation) { | 4559 if (FLAG_trace_constant_propagation) { |
4607 OS::Print("\n==== After constant propagation ====\n"); | 4560 OS::Print("\n==== After constant propagation ====\n"); |
4608 FlowGraphPrinter printer(*graph_); | 4561 FlowGraphPrinter printer(*graph_); |
4609 printer.PrintBlocks(); | 4562 printer.PrintBlocks(); |
4610 } | 4563 } |
4611 } | 4564 } |
4612 | 4565 |
4613 | 4566 |
4614 } // namespace dart | 4567 } // namespace dart |
OLD | NEW |