Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: runtime/vm/flow_graph_optimizer.cc

Issue 12088108: Separate the array/string .length load from the bounds check. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | runtime/vm/intermediate_language.h » ('j') | runtime/vm/intermediate_language.cc » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/intermediate_language.h » ('j') | runtime/vm/intermediate_language.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698