OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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/intermediate_language.h" | 5 #include "vm/intermediate_language.h" |
6 | 6 |
7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
8 #include "vm/dart_entry.h" | 8 #include "vm/dart_entry.h" |
9 #include "vm/flow_graph_allocator.h" | 9 #include "vm/flow_graph_allocator.h" |
10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
(...skipping 2059 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2070 for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) { | 2070 for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) { |
2071 Value* value = it.CurrentValue(); | 2071 Value* value = it.CurrentValue(); |
2072 value->set_instruction(instr); | 2072 value->set_instruction(instr); |
2073 value->set_use_index(use_index++); | 2073 value->set_use_index(use_index++); |
2074 value->AddToEnvUseList(); | 2074 value->AddToEnvUseList(); |
2075 } | 2075 } |
2076 instr->env()->outer_ = copy; | 2076 instr->env()->outer_ = copy; |
2077 } | 2077 } |
2078 | 2078 |
2079 | 2079 |
| 2080 RangeBoundary RangeBoundary::FromDefinition(Definition* defn, intptr_t offs) { |
| 2081 if (defn->IsConstant() && defn->AsConstant()->value().IsSmi()) { |
| 2082 return FromConstant(Smi::Cast(defn->AsConstant()->value()).Value() + offs); |
| 2083 } |
| 2084 return RangeBoundary(kSymbol, reinterpret_cast<intptr_t>(defn), offs); |
| 2085 } |
| 2086 |
| 2087 |
2080 RangeBoundary RangeBoundary::LowerBound() const { | 2088 RangeBoundary RangeBoundary::LowerBound() const { |
2081 if (IsConstant()) return *this; | 2089 if (IsConstant()) return *this; |
2082 if (symbol()->range() == NULL) return MinSmi(); | 2090 if (symbol()->range() == NULL) return MinSmi(); |
2083 return Add(symbol()->range()->min().LowerBound(), | 2091 return Add(symbol()->range()->min().LowerBound(), |
2084 RangeBoundary::FromConstant(offset_), | 2092 RangeBoundary::FromConstant(offset_), |
2085 MinSmi()); | 2093 MinSmi()); |
2086 } | 2094 } |
2087 | 2095 |
2088 | 2096 |
2089 RangeBoundary RangeBoundary::UpperBound() const { | 2097 RangeBoundary RangeBoundary::UpperBound() const { |
2090 if (IsConstant()) return *this; | 2098 if (IsConstant()) return *this; |
2091 if (symbol()->range() == NULL) return MaxSmi(); | 2099 if (symbol()->range() == NULL) return MaxSmi(); |
2092 return Add(symbol()->range()->max().UpperBound(), | 2100 return Add(symbol()->range()->max().UpperBound(), |
2093 RangeBoundary::FromConstant(offset_), | 2101 RangeBoundary::FromConstant(offset_), |
2094 MaxSmi()); | 2102 MaxSmi()); |
2095 } | 2103 } |
2096 | 2104 |
2097 | 2105 |
| 2106 // Returns true if two range boundaries refer to the same symbol. |
| 2107 static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) { |
| 2108 if (!a.IsSymbol() || !b.IsSymbol()) return false; |
| 2109 if (a.symbol() == b.symbol()) return true; |
| 2110 |
| 2111 return !a.symbol()->AffectedBySideEffect() && |
| 2112 a.symbol()->Equals(b.symbol()); |
| 2113 } |
| 2114 |
| 2115 |
| 2116 // Returns true if range has a least specific minimum value. |
| 2117 static bool IsMinSmi(Range* range) { |
| 2118 return (range == NULL) || |
| 2119 (range->min().IsConstant() && |
| 2120 (range->min().value() <= Smi::kMinValue)); |
| 2121 } |
| 2122 |
| 2123 |
| 2124 // Returns true if range has a least specific maximium value. |
| 2125 static bool IsMaxSmi(Range* range) { |
| 2126 return (range == NULL) || |
| 2127 (range->max().IsConstant() && |
| 2128 (range->max().value() >= Smi::kMaxValue)); |
| 2129 } |
| 2130 |
| 2131 |
| 2132 // Returns true if two range boundaries can be proven to be equal. |
| 2133 static bool IsEqual(const RangeBoundary& a, const RangeBoundary& b) { |
| 2134 if (a.IsConstant() && b.IsConstant()) { |
| 2135 return a.value() == b.value(); |
| 2136 } else if (a.IsSymbol() && b.IsSymbol()) { |
| 2137 return (a.offset() == b.offset()) && DependOnSameSymbol(a, b); |
| 2138 } else { |
| 2139 return false; |
| 2140 } |
| 2141 } |
| 2142 |
| 2143 |
| 2144 static RangeBoundary CanonicalizeBoundary(const RangeBoundary& a, |
| 2145 const RangeBoundary& overflow) { |
| 2146 if (a.IsConstant()) return a; |
| 2147 |
| 2148 intptr_t offset = a.offset(); |
| 2149 Definition* symbol = a.symbol(); |
| 2150 |
| 2151 bool changed; |
| 2152 do { |
| 2153 changed = false; |
| 2154 if (symbol->IsConstraint()) { |
| 2155 symbol = symbol->AsConstraint()->value()->definition(); |
| 2156 changed = true; |
| 2157 } else if (symbol->IsBinarySmiOp()) { |
| 2158 BinarySmiOpInstr* op = symbol->AsBinarySmiOp(); |
| 2159 Definition* left = op->left()->definition(); |
| 2160 Definition* right = op->right()->definition(); |
| 2161 switch (op->op_kind()) { |
| 2162 case Token::kADD: |
| 2163 if (right->IsConstant()) { |
| 2164 offset += Smi::Cast(right->AsConstant()->value()).Value(); |
| 2165 symbol = left; |
| 2166 changed = true; |
| 2167 } else if (left->IsConstant()) { |
| 2168 offset += Smi::Cast(left->AsConstant()->value()).Value(); |
| 2169 symbol = right; |
| 2170 changed = true; |
| 2171 } |
| 2172 break; |
| 2173 |
| 2174 case Token::kSUB: |
| 2175 if (right->IsConstant()) { |
| 2176 offset -= Smi::Cast(right->AsConstant()->value()).Value(); |
| 2177 symbol = left; |
| 2178 changed = true; |
| 2179 } |
| 2180 break; |
| 2181 |
| 2182 default: |
| 2183 break; |
| 2184 } |
| 2185 } |
| 2186 |
| 2187 if (!Smi::IsValid(offset)) return overflow; |
| 2188 } while (changed); |
| 2189 |
| 2190 return RangeBoundary::FromDefinition(symbol, offset); |
| 2191 } |
| 2192 |
| 2193 |
| 2194 static bool CanonicalizeMaxBoundary(RangeBoundary* a) { |
| 2195 if (!a->IsSymbol()) return false; |
| 2196 |
| 2197 Range* range = a->symbol()->range(); |
| 2198 if ((range == NULL) || !range->max().IsSymbol()) return false; |
| 2199 |
| 2200 const intptr_t offset = range->max().offset() + a->offset(); |
| 2201 |
| 2202 if (!Smi::IsValid(offset)) { |
| 2203 *a = RangeBoundary::OverflowedMaxSmi(); |
| 2204 return true; |
| 2205 } |
| 2206 |
| 2207 *a = CanonicalizeBoundary( |
| 2208 RangeBoundary::FromDefinition(range->max().symbol(), offset), |
| 2209 RangeBoundary::OverflowedMaxSmi()); |
| 2210 |
| 2211 return true; |
| 2212 } |
| 2213 |
| 2214 |
| 2215 static bool CanonicalizeMinBoundary(RangeBoundary* a) { |
| 2216 if (!a->IsSymbol()) return false; |
| 2217 |
| 2218 Range* range = a->symbol()->range(); |
| 2219 if ((range == NULL) || !range->min().IsSymbol()) return false; |
| 2220 |
| 2221 const intptr_t offset = range->min().offset() + a->offset(); |
| 2222 if (!Smi::IsValid(offset)) { |
| 2223 *a = RangeBoundary::OverflowedMinSmi(); |
| 2224 return true; |
| 2225 } |
| 2226 |
| 2227 *a = CanonicalizeBoundary( |
| 2228 RangeBoundary::FromDefinition(range->min().symbol(), offset), |
| 2229 RangeBoundary::OverflowedMinSmi()); |
| 2230 |
| 2231 return true; |
| 2232 } |
| 2233 |
| 2234 |
| 2235 RangeBoundary RangeBoundary::Min(RangeBoundary a, RangeBoundary b) { |
| 2236 if (DependOnSameSymbol(a, b)) { |
| 2237 return (a.offset() <= b.offset()) ? a : b; |
| 2238 } |
| 2239 |
| 2240 const intptr_t min_a = a.LowerBound().value(); |
| 2241 const intptr_t min_b = b.LowerBound().value(); |
| 2242 |
| 2243 return RangeBoundary::FromConstant(Utils::Minimum(min_a, min_b)); |
| 2244 } |
| 2245 |
| 2246 |
| 2247 RangeBoundary RangeBoundary::Max(RangeBoundary a, RangeBoundary b) { |
| 2248 if (DependOnSameSymbol(a, b)) { |
| 2249 return (a.offset() >= b.offset()) ? a : b; |
| 2250 } |
| 2251 |
| 2252 const intptr_t max_a = a.UpperBound().value(); |
| 2253 const intptr_t max_b = b.UpperBound().value(); |
| 2254 |
| 2255 return RangeBoundary::FromConstant(Utils::Maximum(max_a, max_b)); |
| 2256 } |
| 2257 |
| 2258 |
2098 void Definition::InferRange() { | 2259 void Definition::InferRange() { |
2099 ASSERT(GetPropagatedCid() == kSmiCid); // Has meaning only for smis. | 2260 ASSERT(GetPropagatedCid() == kSmiCid); // Has meaning only for smis. |
2100 if (range_ == NULL) { | 2261 if (range_ == NULL) { |
2101 range_ = Range::Unknown(); | 2262 range_ = Range::Unknown(); |
2102 } | 2263 } |
2103 } | 2264 } |
2104 | 2265 |
2105 | 2266 |
2106 void ConstantInstr::InferRange() { | 2267 void ConstantInstr::InferRange() { |
2107 ASSERT(value_.IsSmi()); | 2268 ASSERT(value_.IsSmi()); |
2108 if (range_ == NULL) { | 2269 if (range_ == NULL) { |
2109 intptr_t value = Smi::Cast(value_).Value(); | 2270 intptr_t value = Smi::Cast(value_).Value(); |
2110 range_ = new Range(RangeBoundary::FromConstant(value), | 2271 range_ = new Range(RangeBoundary::FromConstant(value), |
2111 RangeBoundary::FromConstant(value)); | 2272 RangeBoundary::FromConstant(value)); |
2112 } | 2273 } |
2113 } | 2274 } |
2114 | 2275 |
2115 | 2276 |
2116 void ConstraintInstr::InferRange() { | 2277 void ConstraintInstr::InferRange() { |
2117 Range* value_range = value()->definition()->range(); | 2278 Range* value_range = value()->definition()->range(); |
2118 | 2279 |
2119 // Compute intersection of constraint and value ranges. | 2280 RangeBoundary min; |
2120 range_ = new Range( | 2281 RangeBoundary max; |
2121 RangeBoundary::Max(Range::ConstantMin(value_range), | 2282 |
2122 Range::ConstantMin(constraint())), | 2283 if (IsMinSmi(value_range) && !IsMinSmi(constraint())) { |
2123 RangeBoundary::Min(Range::ConstantMax(value_range), | 2284 min = constraint()->min(); |
2124 Range::ConstantMax(constraint()))); | 2285 } else if (IsMinSmi(constraint()) && !IsMinSmi(value_range)) { |
| 2286 min = value_range->min(); |
| 2287 } else if ((value_range != NULL) && |
| 2288 IsEqual(constraint()->min(), value_range->min())) { |
| 2289 min = constraint()->min(); |
| 2290 } else { |
| 2291 if (value_range != NULL) { |
| 2292 RangeBoundary canonical_a = |
| 2293 CanonicalizeBoundary(constraint()->min(), |
| 2294 RangeBoundary::OverflowedMinSmi()); |
| 2295 RangeBoundary canonical_b = |
| 2296 CanonicalizeBoundary(value_range->min(), |
| 2297 RangeBoundary::OverflowedMinSmi()); |
| 2298 |
| 2299 do { |
| 2300 if (DependOnSameSymbol(canonical_a, canonical_b)) { |
| 2301 min = (canonical_a.offset() <= canonical_b.offset()) ? canonical_b |
| 2302 : canonical_a; |
| 2303 } |
| 2304 } while (CanonicalizeMinBoundary(&canonical_a) || |
| 2305 CanonicalizeMinBoundary(&canonical_b)); |
| 2306 } |
| 2307 |
| 2308 if (min.IsUnknown()) { |
| 2309 min = RangeBoundary::Max(Range::ConstantMin(value_range), |
| 2310 Range::ConstantMin(constraint())); |
| 2311 } |
| 2312 } |
| 2313 |
| 2314 if (IsMaxSmi(value_range) && !IsMaxSmi(constraint())) { |
| 2315 max = constraint()->max(); |
| 2316 } else if (IsMaxSmi(constraint()) && !IsMaxSmi(value_range)) { |
| 2317 max = value_range->max(); |
| 2318 } else if ((value_range != NULL) && |
| 2319 IsEqual(constraint()->max(), value_range->max())) { |
| 2320 max = constraint()->max(); |
| 2321 } else { |
| 2322 if (value_range != NULL) { |
| 2323 RangeBoundary canonical_b = |
| 2324 CanonicalizeBoundary(value_range->max(), |
| 2325 RangeBoundary::OverflowedMaxSmi()); |
| 2326 RangeBoundary canonical_a = |
| 2327 CanonicalizeBoundary(constraint()->max(), |
| 2328 RangeBoundary::OverflowedMaxSmi()); |
| 2329 |
| 2330 do { |
| 2331 if (DependOnSameSymbol(canonical_a, canonical_b)) { |
| 2332 max = (canonical_a.offset() <= canonical_b.offset()) ? canonical_a |
| 2333 : canonical_b; |
| 2334 break; |
| 2335 } |
| 2336 } while (CanonicalizeMaxBoundary(&canonical_a) || |
| 2337 CanonicalizeMaxBoundary(&canonical_b)); |
| 2338 } |
| 2339 |
| 2340 if (max.IsUnknown()) { |
| 2341 max = RangeBoundary::Min(Range::ConstantMax(value_range), |
| 2342 Range::ConstantMax(constraint())); |
| 2343 } |
| 2344 } |
| 2345 |
| 2346 range_ = new Range(min, max); |
2125 } | 2347 } |
2126 | 2348 |
2127 | 2349 |
| 2350 void LoadFieldInstr::InferRange() { |
| 2351 if ((range_ == NULL) && |
| 2352 ((recognized_kind() == MethodRecognizer::kObjectArrayLength) || |
| 2353 (recognized_kind() == MethodRecognizer::kImmutableArrayLength))) { |
| 2354 range_ = new Range(RangeBoundary::FromConstant(0), |
| 2355 RangeBoundary::FromConstant(Array::kMaxElements)); |
| 2356 return; |
| 2357 } |
| 2358 Definition::InferRange(); |
| 2359 } |
| 2360 |
| 2361 |
2128 void PhiInstr::InferRange() { | 2362 void PhiInstr::InferRange() { |
2129 RangeBoundary new_min; | 2363 RangeBoundary new_min; |
2130 RangeBoundary new_max; | 2364 RangeBoundary new_max; |
2131 | 2365 |
2132 for (intptr_t i = 0; i < InputCount(); i++) { | 2366 for (intptr_t i = 0; i < InputCount(); i++) { |
2133 Range* input_range = InputAt(i)->definition()->range(); | 2367 Range* input_range = InputAt(i)->definition()->range(); |
2134 if (input_range == NULL) { | 2368 if (input_range == NULL) { |
2135 range_ = Range::Unknown(); | 2369 range_ = Range::Unknown(); |
2136 return; | 2370 return; |
2137 } | 2371 } |
(...skipping 14 matching lines...) Expand all Loading... |
2152 ASSERT(new_min.IsUnknown() == new_max.IsUnknown()); | 2386 ASSERT(new_min.IsUnknown() == new_max.IsUnknown()); |
2153 if (new_min.IsUnknown()) { | 2387 if (new_min.IsUnknown()) { |
2154 range_ = Range::Unknown(); | 2388 range_ = Range::Unknown(); |
2155 return; | 2389 return; |
2156 } | 2390 } |
2157 | 2391 |
2158 range_ = new Range(new_min, new_max); | 2392 range_ = new Range(new_min, new_max); |
2159 } | 2393 } |
2160 | 2394 |
2161 | 2395 |
| 2396 static bool SymbolicSub(const RangeBoundary& a, |
| 2397 const RangeBoundary& b, |
| 2398 RangeBoundary* result) { |
| 2399 if (a.IsSymbol() && b.IsConstant() && !b.Overflowed()) { |
| 2400 const intptr_t offset = a.offset() - b.value(); |
| 2401 if (!Smi::IsValid(offset)) return false; |
| 2402 |
| 2403 *result = RangeBoundary::FromDefinition(a.symbol(), offset); |
| 2404 return true; |
| 2405 } |
| 2406 return false; |
| 2407 } |
| 2408 |
| 2409 |
| 2410 static bool SymbolicAdd(const RangeBoundary& a, |
| 2411 const RangeBoundary& b, |
| 2412 RangeBoundary* result) { |
| 2413 if (a.IsSymbol() && b.IsConstant() && !b.Overflowed()) { |
| 2414 const intptr_t offset = a.offset() + b.value(); |
| 2415 if (!Smi::IsValid(offset)) return false; |
| 2416 |
| 2417 *result = RangeBoundary::FromDefinition(a.symbol(), offset); |
| 2418 return true; |
| 2419 } else if (b.IsSymbol() && a.IsConstant() && !a.Overflowed()) { |
| 2420 const intptr_t offset = b.offset() + a.value(); |
| 2421 if (!Smi::IsValid(offset)) return false; |
| 2422 |
| 2423 *result = RangeBoundary::FromDefinition(b.symbol(), offset); |
| 2424 return true; |
| 2425 } |
| 2426 return false; |
| 2427 } |
| 2428 |
| 2429 |
| 2430 static bool IsArrayLength(Definition* defn) { |
| 2431 LoadFieldInstr* load = defn->AsLoadField(); |
| 2432 return (load != NULL) && |
| 2433 ((load->recognized_kind() == MethodRecognizer::kObjectArrayLength) || |
| 2434 (load->recognized_kind() == MethodRecognizer::kImmutableArrayLength)); |
| 2435 } |
| 2436 |
| 2437 |
| 2438 static bool IsLengthOf(Definition* defn, Definition* array) { |
| 2439 return IsArrayLength(defn) && |
| 2440 (defn->AsLoadField()->value()->definition() == array); |
| 2441 } |
| 2442 |
| 2443 |
2162 void BinarySmiOpInstr::InferRange() { | 2444 void BinarySmiOpInstr::InferRange() { |
2163 Range* left_range = left()->definition()->range(); | 2445 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the |
| 2446 // right and a non-constant on the left. |
| 2447 Definition* left_defn = left()->definition(); |
| 2448 |
| 2449 Range* left_range = left_defn->range(); |
2164 Range* right_range = right()->definition()->range(); | 2450 Range* right_range = right()->definition()->range(); |
2165 | 2451 |
2166 if ((left_range == NULL) || (right_range == NULL)) { | 2452 if ((left_range == NULL) || (right_range == NULL)) { |
2167 range_ = new Range(RangeBoundary::MinSmi(), RangeBoundary::MaxSmi()); | 2453 range_ = new Range(RangeBoundary::MinSmi(), RangeBoundary::MaxSmi()); |
2168 return; | 2454 return; |
2169 } | 2455 } |
2170 | 2456 |
2171 RangeBoundary new_min; | 2457 |
2172 RangeBoundary new_max; | 2458 // If left is a l |
| 2459 RangeBoundary left_min = |
| 2460 IsArrayLength(left_defn) ? |
| 2461 RangeBoundary::FromDefinition(left_defn) : left_range->min(); |
| 2462 |
| 2463 RangeBoundary left_max = |
| 2464 IsArrayLength(left_defn) ? |
| 2465 RangeBoundary::FromDefinition(left_defn) : left_range->max(); |
| 2466 |
| 2467 RangeBoundary min; |
| 2468 RangeBoundary max; |
2173 switch (op_kind()) { | 2469 switch (op_kind()) { |
2174 case Token::kADD: | 2470 case Token::kADD: |
2175 new_min = | 2471 if (!SymbolicAdd(left_min, right_range->min(), &min)) { |
2176 RangeBoundary::Add(Range::ConstantMin(left_range), | 2472 min = |
2177 Range::ConstantMin(right_range), | 2473 RangeBoundary::Add(Range::ConstantMin(left_range), |
2178 RangeBoundary::OverflowedMinSmi()); | 2474 Range::ConstantMin(right_range), |
2179 new_max = | 2475 RangeBoundary::OverflowedMinSmi()); |
2180 RangeBoundary::Add(Range::ConstantMax(left_range), | 2476 } |
2181 Range::ConstantMax(right_range), | 2477 |
2182 RangeBoundary::OverflowedMaxSmi()); | 2478 if (!SymbolicAdd(left_max, right_range->max(), &max)) { |
| 2479 max = |
| 2480 RangeBoundary::Add(Range::ConstantMax(right_range), |
| 2481 Range::ConstantMax(left_range), |
| 2482 RangeBoundary::OverflowedMaxSmi()); |
| 2483 } |
2183 break; | 2484 break; |
2184 | 2485 |
2185 case Token::kSUB: | 2486 case Token::kSUB: |
2186 new_min = | 2487 if (!SymbolicSub(left_min, right_range->max(), &min)) { |
2187 RangeBoundary::Sub(Range::ConstantMin(left_range), | 2488 min = |
2188 Range::ConstantMax(right_range), | 2489 RangeBoundary::Sub(Range::ConstantMin(left_range), |
2189 RangeBoundary::OverflowedMinSmi()); | 2490 Range::ConstantMax(right_range), |
2190 new_max = | 2491 RangeBoundary::OverflowedMinSmi()); |
2191 RangeBoundary::Sub(Range::ConstantMax(left_range), | 2492 } |
2192 Range::ConstantMin(right_range), | 2493 |
2193 RangeBoundary::OverflowedMaxSmi()); | 2494 if (!SymbolicSub(left_max, right_range->min(), &max)) { |
| 2495 max = |
| 2496 RangeBoundary::Sub(Range::ConstantMax(left_range), |
| 2497 Range::ConstantMin(right_range), |
| 2498 RangeBoundary::OverflowedMaxSmi()); |
| 2499 } |
2194 break; | 2500 break; |
2195 | 2501 |
2196 default: | 2502 default: |
2197 if (range_ == NULL) { | 2503 if (range_ == NULL) { |
2198 range_ = Range::Unknown(); | 2504 range_ = Range::Unknown(); |
2199 } | 2505 } |
2200 return; | 2506 return; |
2201 } | 2507 } |
2202 | 2508 |
2203 ASSERT(!new_min.IsUnknown() && !new_max.IsUnknown()); | 2509 ASSERT(!min.IsUnknown() && !max.IsUnknown()); |
2204 set_overflow(new_min.Overflowed() || new_max.Overflowed()); | 2510 set_overflow(min.LowerBound().Overflowed() || max.UpperBound().Overflowed()); |
2205 | 2511 |
2206 range_ = new Range(new_min.Clamp(), new_max.Clamp()); | 2512 if (min.IsConstant()) min.Clamp(); |
| 2513 if (max.IsConstant()) max.Clamp(); |
| 2514 |
| 2515 range_ = new Range(min, max); |
2207 } | 2516 } |
2208 | 2517 |
2209 | 2518 |
| 2519 bool CheckArrayBoundInstr::IsRedundant() { |
| 2520 // Check that array has an immutable length. |
| 2521 if ((array_type() != kArrayCid) && (array_type() != kImmutableArrayCid)) { |
| 2522 return false; |
| 2523 } |
| 2524 |
| 2525 Range* index_range = index()->definition()->range(); |
| 2526 |
| 2527 // Range of the index is unknown can't decide if the check is redundant. |
| 2528 if (index_range == NULL) return false; |
| 2529 |
| 2530 // Range of the index is not positive. Check can't be redundant. |
| 2531 if (Range::ConstantMin(index_range).value() < 0) return false; |
| 2532 |
| 2533 RangeBoundary max = CanonicalizeBoundary(index_range->max(), |
| 2534 RangeBoundary::OverflowedMaxSmi()); |
| 2535 do { |
| 2536 if (max.IsSymbol() && |
| 2537 (max.offset() < 0) && |
| 2538 IsLengthOf(max.symbol(), array()->definition())) { |
| 2539 return true; |
| 2540 } |
| 2541 } while (CanonicalizeMaxBoundary(&max)); |
| 2542 |
| 2543 // Failed to prove that maximum is bounded with array length. |
| 2544 return false; |
| 2545 } |
| 2546 |
| 2547 |
2210 #undef __ | 2548 #undef __ |
2211 | 2549 |
2212 } // namespace dart | 2550 } // namespace dart |
OLD | NEW |