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()); | |
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 static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) { | |
2107 if (!a.IsSymbol() || !b.IsSymbol()) return false; | |
2108 if (a.symbol() == b.symbol()) return true; | |
2109 | |
2110 return !a.symbol()->AffectedBySideEffect() && | |
2111 !b.symbol()->AffectedBySideEffect() && | |
2112 a.symbol()->Equals(b.symbol()); | |
Florian Schneider
2012/10/26 11:10:07
I think !a->AffecteedBySideEffect() &&a->Equals(b)
Vyacheslav Egorov (Google)
2012/10/26 14:23:29
Done.
| |
2113 } | |
2114 | |
2115 | |
2116 static bool IsMinSmi(Range* range) { | |
2117 return (range == NULL) || | |
2118 (range->min().IsConstant() && | |
2119 (range->min().value() <= Smi::kMinValue)); | |
2120 } | |
2121 | |
2122 | |
2123 static bool IsMaxSmi(Range* range) { | |
2124 return (range == NULL) || | |
2125 (range->max().IsConstant() && | |
2126 (range->max().value() >= Smi::kMaxValue)); | |
2127 } | |
2128 | |
2129 | |
2130 static bool IsEqual(const RangeBoundary& a, const RangeBoundary& b) { | |
2131 if (a.IsConstant() && b.IsConstant()) { | |
2132 return a.value() == b.value(); | |
2133 } else if (a.IsSymbol() && b.IsSymbol()) { | |
2134 return (a.offset() == b.offset()) && DependOnSameSymbol(a, b); | |
2135 } else { | |
2136 return false; | |
2137 } | |
2138 } | |
2139 | |
2140 static RangeBoundary CanonicalizeBoundary(const RangeBoundary& a) { | |
2141 if (a.IsConstant()) return a; | |
2142 | |
2143 intptr_t offset = a.offset(); | |
2144 Definition* symbol = a.symbol(); | |
2145 | |
2146 bool changed; | |
2147 do { | |
2148 changed = false; | |
2149 if (symbol->IsConstraint()) { | |
2150 symbol = symbol->AsConstraint()->value()->definition(); | |
2151 changed = true; | |
2152 } else if (symbol->IsBinarySmiOp()) { | |
2153 BinarySmiOpInstr* op = symbol->AsBinarySmiOp(); | |
2154 Definition* left = op->left()->definition(); | |
2155 Definition* right = op->right()->definition(); | |
2156 switch (op->op_kind()) { | |
2157 case Token::kADD: | |
2158 if (right->IsConstant()) { | |
2159 offset += Smi::Cast(right->AsConstant()->value()).Value(); | |
2160 symbol = left; | |
2161 changed = true; | |
2162 } else if (left->IsConstant()) { | |
2163 offset += Smi::Cast(left->AsConstant()->value()).Value(); | |
2164 symbol = right; | |
2165 changed = true; | |
2166 } | |
2167 break; | |
2168 | |
2169 | |
srdjan
2012/10/25 20:51:36
Remove one empty line
Vyacheslav Egorov (Google)
2012/10/26 14:23:29
Done.
| |
2170 case Token::kSUB: | |
2171 if (right->IsConstant()) { | |
2172 offset -= Smi::Cast(right->AsConstant()->value()).Value(); | |
2173 symbol = left; | |
2174 changed = true; | |
2175 } | |
2176 break; | |
2177 | |
2178 default: | |
2179 break; | |
2180 } | |
2181 } | |
2182 } while (changed); | |
2183 | |
2184 return RangeBoundary::FromDefinition(symbol, offset); | |
2185 } | |
2186 | |
2187 | |
2188 static bool CanonicalizeMaxBoundary(RangeBoundary* a) { | |
2189 if (!a->IsSymbol()) return false; | |
2190 | |
2191 Range* range = a->symbol()->range(); | |
2192 if ((range == NULL) || !range->max().IsSymbol()) return false; | |
2193 | |
2194 *a = CanonicalizeBoundary( | |
2195 RangeBoundary::FromDefinition(range->max().symbol(), | |
2196 range->max().offset() + a->offset())); | |
2197 | |
2198 return true; | |
2199 } | |
2200 | |
2201 | |
2202 static bool CanonicalizeMinBoundary(RangeBoundary* a) { | |
2203 if (!a->IsSymbol()) return false; | |
2204 | |
2205 Range* range = a->symbol()->range(); | |
2206 if ((range == NULL) || !range->min().IsSymbol()) return false; | |
2207 | |
2208 *a = CanonicalizeBoundary( | |
2209 RangeBoundary::FromDefinition(range->min().symbol(), | |
2210 range->min().offset() + a->offset())); | |
2211 | |
2212 return true; | |
2213 } | |
2214 | |
2215 | |
2216 #if 0 | |
2217 static bool KnownToBeLessEqual(const RangeBoundary& a, const RangeBoundary& b) { | |
2218 RangeBoundary canonical_a = CanonicalizeBoundary(a); | |
2219 RangeBoundary canonical_b = CanonicalizeBoundary(b); | |
2220 | |
2221 do { | |
2222 if (DependOnSameSymbol(canonical_a, canonical_b)) { | |
2223 return (canonical_a.offset() <= canonical_b.offset()); | |
2224 } | |
2225 } while (CanonicalizeMaxBoundary(&canonical_a) || | |
2226 CanonicalizeMinBoundary(&canonical_b)); | |
2227 | |
2228 return a.UpperBound().value() <= b.LowerBound().value(); | |
2229 } | |
srdjan
2012/10/25 20:51:36
Remove the code above
Vyacheslav Egorov (Google)
2012/10/26 14:23:29
Done.
| |
2230 #endif | |
2231 | |
2232 | |
2233 RangeBoundary RangeBoundary::Min(RangeBoundary a, RangeBoundary b) { | |
2234 if (DependOnSameSymbol(a, b)) { | |
2235 return (a.offset() <= b.offset()) ? a : b; | |
2236 } | |
2237 | |
2238 const intptr_t min_a = a.LowerBound().value(); | |
2239 const intptr_t min_b = b.LowerBound().value(); | |
2240 | |
2241 return RangeBoundary::FromConstant(Utils::Minimum(min_a, min_b)); | |
2242 } | |
2243 | |
2244 | |
2245 RangeBoundary RangeBoundary::Max(RangeBoundary a, RangeBoundary b) { | |
2246 if (DependOnSameSymbol(a, b)) { | |
2247 return (a.offset() >= b.offset()) ? a : b; | |
2248 } | |
2249 | |
2250 const intptr_t max_a = a.UpperBound().value(); | |
2251 const intptr_t max_b = b.UpperBound().value(); | |
2252 | |
2253 return RangeBoundary::FromConstant(Utils::Maximum(max_a, max_b)); | |
2254 } | |
2255 | |
2256 | |
2098 void Definition::InferRange() { | 2257 void Definition::InferRange() { |
2099 ASSERT(GetPropagatedCid() == kSmiCid); // Has meaning only for smis. | 2258 ASSERT(GetPropagatedCid() == kSmiCid); // Has meaning only for smis. |
2100 if (range_ == NULL) { | 2259 if (range_ == NULL) { |
2101 range_ = Range::Unknown(); | 2260 range_ = Range::Unknown(); |
2102 } | 2261 } |
2103 } | 2262 } |
2104 | 2263 |
2105 | 2264 |
2106 void ConstantInstr::InferRange() { | 2265 void ConstantInstr::InferRange() { |
2107 ASSERT(value_.IsSmi()); | 2266 ASSERT(value_.IsSmi()); |
2108 if (range_ == NULL) { | 2267 if (range_ == NULL) { |
2109 intptr_t value = Smi::Cast(value_).Value(); | 2268 intptr_t value = Smi::Cast(value_).Value(); |
2110 range_ = new Range(RangeBoundary::FromConstant(value), | 2269 range_ = new Range(RangeBoundary::FromConstant(value), |
2111 RangeBoundary::FromConstant(value)); | 2270 RangeBoundary::FromConstant(value)); |
2112 } | 2271 } |
2113 } | 2272 } |
2114 | 2273 |
2115 | 2274 |
2116 void ConstraintInstr::InferRange() { | 2275 void ConstraintInstr::InferRange() { |
2117 Range* value_range = value()->definition()->range(); | 2276 Range* value_range = value()->definition()->range(); |
2118 | 2277 |
2119 // Compute intersection of constraint and value ranges. | 2278 RangeBoundary min; |
2120 range_ = new Range( | 2279 RangeBoundary max; |
2121 RangeBoundary::Max(Range::ConstantMin(value_range), | 2280 |
2122 Range::ConstantMin(constraint())), | 2281 if (IsMinSmi(value_range) && !IsMinSmi(constraint())) { |
2123 RangeBoundary::Min(Range::ConstantMax(value_range), | 2282 min = constraint()->min(); |
2124 Range::ConstantMax(constraint()))); | 2283 } else if (IsMinSmi(constraint()) && !IsMinSmi(value_range)) { |
2284 min = value_range->min(); | |
2285 } else if ((value_range != NULL) && | |
2286 IsEqual(constraint()->min(), value_range->min())) { | |
2287 min = constraint()->min(); | |
2288 } else { | |
2289 if (value_range != NULL) { | |
2290 RangeBoundary canonical_a = CanonicalizeBoundary(constraint()->min()); | |
2291 RangeBoundary canonical_b = CanonicalizeBoundary(value_range->min()); | |
2292 | |
2293 do { | |
2294 if (DependOnSameSymbol(canonical_a, canonical_b)) { | |
2295 min = (canonical_a.offset() <= canonical_b.offset()) ? canonical_b | |
2296 : canonical_a; | |
2297 } | |
2298 } while (CanonicalizeMinBoundary(&canonical_a) || | |
2299 CanonicalizeMinBoundary(&canonical_b)); | |
2300 } | |
2301 | |
2302 if (min.IsUnknown()) { | |
2303 min = RangeBoundary::Max(Range::ConstantMin(value_range), | |
2304 Range::ConstantMin(constraint())); | |
2305 } | |
2306 } | |
2307 | |
2308 if (IsMaxSmi(value_range) && !IsMaxSmi(constraint())) { | |
2309 max = constraint()->max(); | |
2310 } else if (IsMaxSmi(constraint()) && !IsMaxSmi(value_range)) { | |
2311 max = value_range->max(); | |
2312 } else if ((value_range != NULL) && | |
2313 IsEqual(constraint()->max(), value_range->max())) { | |
2314 max = constraint()->max(); | |
2315 } else { | |
2316 if (value_range != NULL) { | |
2317 RangeBoundary canonical_b = CanonicalizeBoundary(value_range->max()); | |
2318 RangeBoundary canonical_a = CanonicalizeBoundary(constraint()->max()); | |
2319 | |
2320 do { | |
2321 if (DependOnSameSymbol(canonical_a, canonical_b)) { | |
2322 max = (canonical_a.offset() <= canonical_b.offset()) ? canonical_a | |
2323 : canonical_b; | |
2324 break; | |
2325 } | |
2326 } while (CanonicalizeMaxBoundary(&canonical_a) || | |
2327 CanonicalizeMaxBoundary(&canonical_b)); | |
2328 } | |
2329 | |
2330 if (max.IsUnknown()) { | |
2331 max = RangeBoundary::Min(Range::ConstantMax(value_range), | |
2332 Range::ConstantMax(constraint())); | |
Florian Schneider
2012/10/26 11:10:07
Indentation.
Vyacheslav Egorov (Google)
2012/10/26 14:23:29
Done.
| |
2333 } | |
2334 } | |
2335 | |
2336 range_ = new Range(min, max); | |
2125 } | 2337 } |
2126 | 2338 |
2127 | 2339 |
2340 void LoadFieldInstr::InferRange() { | |
2341 if ((range_ == NULL) && | |
2342 ((recognized_kind() == MethodRecognizer::kObjectArrayLength) || | |
2343 (recognized_kind() == MethodRecognizer::kImmutableArrayLength))) { | |
2344 range_ = new Range(RangeBoundary::FromConstant(0), | |
2345 RangeBoundary::FromConstant(Array::kMaxElements)); | |
2346 return; | |
2347 } | |
2348 Definition::InferRange(); | |
2349 } | |
2350 | |
2351 | |
2128 void PhiInstr::InferRange() { | 2352 void PhiInstr::InferRange() { |
2129 RangeBoundary new_min; | 2353 RangeBoundary new_min; |
2130 RangeBoundary new_max; | 2354 RangeBoundary new_max; |
2131 | 2355 |
2132 for (intptr_t i = 0; i < InputCount(); i++) { | 2356 for (intptr_t i = 0; i < InputCount(); i++) { |
2133 Range* input_range = InputAt(i)->definition()->range(); | 2357 Range* input_range = InputAt(i)->definition()->range(); |
2134 if (input_range == NULL) { | 2358 if (input_range == NULL) { |
2135 range_ = Range::Unknown(); | 2359 range_ = Range::Unknown(); |
2136 return; | 2360 return; |
2137 } | 2361 } |
(...skipping 14 matching lines...) Expand all Loading... | |
2152 ASSERT(new_min.IsUnknown() == new_max.IsUnknown()); | 2376 ASSERT(new_min.IsUnknown() == new_max.IsUnknown()); |
2153 if (new_min.IsUnknown()) { | 2377 if (new_min.IsUnknown()) { |
2154 range_ = Range::Unknown(); | 2378 range_ = Range::Unknown(); |
2155 return; | 2379 return; |
2156 } | 2380 } |
2157 | 2381 |
2158 range_ = new Range(new_min, new_max); | 2382 range_ = new Range(new_min, new_max); |
2159 } | 2383 } |
2160 | 2384 |
2161 | 2385 |
2386 static bool SymbolicSub(const RangeBoundary& a, | |
2387 const RangeBoundary& b, | |
2388 RangeBoundary* result) { | |
2389 if (a.IsSymbol() && | |
2390 b.IsConstant() && | |
2391 ((b.value() > Smi::kMinValue) && (b.value() < Smi::kMaxValue))) { | |
2392 *result = RangeBoundary::FromDefinition(a.symbol(), a.offset() - b.value()); | |
Florian Schneider
2012/10/26 11:10:07
Guard against smi-overflow here.
Vyacheslav Egorov (Google)
2012/10/26 14:23:29
Done.
| |
2393 return true; | |
2394 } | |
2395 return false; | |
2396 } | |
2397 | |
2398 | |
2399 static bool SymbolicAdd(const RangeBoundary& a, | |
2400 const RangeBoundary& b, | |
2401 RangeBoundary* result) { | |
2402 if (a.IsSymbol() && | |
2403 b.IsConstant() && | |
2404 ((b.value() > Smi::kMinValue) && (b.value() < Smi::kMaxValue))) { | |
2405 *result = RangeBoundary::FromDefinition(a.symbol(), a.offset() + b.value()); | |
Florian Schneider
2012/10/26 11:10:07
Guard against overflow here, so that the result of
Vyacheslav Egorov (Google)
2012/10/26 14:23:29
Done.
| |
2406 return true; | |
2407 } else if (b.IsSymbol() && | |
2408 a.IsConstant() && | |
2409 ((a.value() > Smi::kMinValue) && (a.value() < Smi::kMaxValue))) { | |
2410 *result = RangeBoundary::FromDefinition(b.symbol(), b.offset() + a.value()); | |
Florian Schneider
2012/10/26 11:10:07
Guard against smi-overflow here as well.
Vyacheslav Egorov (Google)
2012/10/26 14:23:29
Done.
| |
2411 return true; | |
2412 } | |
2413 return false; | |
2414 } | |
2415 | |
2416 | |
2162 void BinarySmiOpInstr::InferRange() { | 2417 void BinarySmiOpInstr::InferRange() { |
2163 Range* left_range = left()->definition()->range(); | 2418 Definition* left_defn = left()->definition(); |
2419 | |
2420 Range* left_range = left_defn->range(); | |
2164 Range* right_range = right()->definition()->range(); | 2421 Range* right_range = right()->definition()->range(); |
2165 | 2422 |
2166 if ((left_range == NULL) || (right_range == NULL)) { | 2423 if ((left_range == NULL) || (right_range == NULL)) { |
2167 range_ = new Range(RangeBoundary::MinSmi(), RangeBoundary::MaxSmi()); | 2424 range_ = new Range(RangeBoundary::MinSmi(), RangeBoundary::MaxSmi()); |
2168 return; | 2425 return; |
2169 } | 2426 } |
2170 | 2427 |
2171 RangeBoundary new_min; | 2428 RangeBoundary left_min = |
2172 RangeBoundary new_max; | 2429 left_defn->IsLoadField() ? |
Florian Schneider
2012/10/26 11:10:07
Does this need to be for every LoadField, or only
Vyacheslav Egorov (Google)
2012/10/26 14:23:29
Narrowed symbolic computation to length.
| |
2430 RangeBoundary::FromDefinition(left_defn) : left_range->min(); | |
2431 | |
2432 RangeBoundary left_max = | |
2433 left_defn->IsLoadField() ? | |
2434 RangeBoundary::FromDefinition(left_defn) : left_range->max(); | |
Florian Schneider
2012/10/26 11:10:07
Maybe add a TODO to support the case where right()
Vyacheslav Egorov (Google)
2012/10/26 14:23:29
Done.
| |
2435 | |
2436 RangeBoundary min; | |
2437 RangeBoundary max; | |
2173 switch (op_kind()) { | 2438 switch (op_kind()) { |
2174 case Token::kADD: | 2439 case Token::kADD: |
2175 new_min = | 2440 if (!SymbolicAdd(left_min, right_range->min(), &min)) { |
2176 RangeBoundary::Add(Range::ConstantMin(left_range), | 2441 min = |
2177 Range::ConstantMin(right_range), | 2442 RangeBoundary::Add(Range::ConstantMin(left_range), |
2178 RangeBoundary::OverflowedMinSmi()); | 2443 Range::ConstantMin(right_range), |
2179 new_max = | 2444 RangeBoundary::OverflowedMinSmi()); |
2180 RangeBoundary::Add(Range::ConstantMax(left_range), | 2445 } |
2181 Range::ConstantMax(right_range), | 2446 |
2182 RangeBoundary::OverflowedMaxSmi()); | 2447 if (!SymbolicAdd(left_max, right_range->max(), &max)) { |
2448 max = | |
2449 RangeBoundary::Add(Range::ConstantMax(right_range), | |
2450 Range::ConstantMax(left_range), | |
2451 RangeBoundary::OverflowedMaxSmi()); | |
2452 } | |
2183 break; | 2453 break; |
2184 | 2454 |
2185 case Token::kSUB: | 2455 case Token::kSUB: |
2186 new_min = | 2456 if (!SymbolicSub(left_min, right_range->max(), &min)) { |
2187 RangeBoundary::Sub(Range::ConstantMin(left_range), | 2457 min = |
2188 Range::ConstantMax(right_range), | 2458 RangeBoundary::Sub(Range::ConstantMin(left_range), |
2189 RangeBoundary::OverflowedMinSmi()); | 2459 Range::ConstantMax(right_range), |
2190 new_max = | 2460 RangeBoundary::OverflowedMinSmi()); |
2191 RangeBoundary::Sub(Range::ConstantMax(left_range), | 2461 } |
2192 Range::ConstantMin(right_range), | 2462 |
2193 RangeBoundary::OverflowedMaxSmi()); | 2463 if (!SymbolicSub(left_max, right_range->min(), &max)) { |
2464 max = | |
2465 RangeBoundary::Sub(Range::ConstantMax(left_range), | |
2466 Range::ConstantMin(right_range), | |
2467 RangeBoundary::OverflowedMaxSmi()); | |
2468 } | |
2194 break; | 2469 break; |
2195 | 2470 |
2196 default: | 2471 default: |
2197 if (range_ == NULL) { | 2472 if (range_ == NULL) { |
2198 range_ = Range::Unknown(); | 2473 range_ = Range::Unknown(); |
2199 } | 2474 } |
2200 return; | 2475 return; |
2201 } | 2476 } |
2202 | 2477 |
2203 ASSERT(!new_min.IsUnknown() && !new_max.IsUnknown()); | 2478 ASSERT(!min.IsUnknown() && !max.IsUnknown()); |
2204 set_overflow(new_min.Overflowed() || new_max.Overflowed()); | 2479 set_overflow(min.LowerBound().Overflowed() || max.UpperBound().Overflowed()); |
2205 | 2480 |
2206 range_ = new Range(new_min.Clamp(), new_max.Clamp()); | 2481 if (min.IsConstant()) min.Clamp(); |
2482 if (max.IsConstant()) max.Clamp(); | |
2483 | |
2484 range_ = new Range(min, max); | |
2207 } | 2485 } |
2208 | 2486 |
2209 | 2487 |
2488 static bool IsArrayLength(Definition* defn, Definition* array) { | |
2489 LoadFieldInstr* load = defn->AsLoadField(); | |
2490 return (load != NULL) && (load->value()->definition() == array) && | |
2491 ((load->recognized_kind() == MethodRecognizer::kObjectArrayLength) || | |
2492 (load->recognized_kind() == MethodRecognizer::kImmutableArrayLength)); | |
2493 } | |
2494 | |
2495 | |
2496 bool CheckArrayBoundInstr::IsRedundant() { | |
2497 // Check that array has an immutable length. | |
2498 if ((array_type() != kArrayCid) && (array_type() != kImmutableArrayCid)) { | |
2499 return false; | |
2500 } | |
2501 | |
2502 Range* index_range = index()->definition()->range(); | |
2503 | |
2504 // Range of the index is unknown can't decide if the check is redundant. | |
2505 if (index_range == NULL) return false; | |
2506 | |
2507 // Range of the index is not positive. Check can't be redundant. | |
2508 if (Range::ConstantMin(index_range).value() < 0) return false; | |
2509 | |
2510 RangeBoundary max = CanonicalizeBoundary(index_range->max()); | |
2511 do { | |
2512 if (max.IsSymbol() && | |
2513 (max.offset() < 0) && | |
2514 IsArrayLength(max.symbol(), array()->definition())) { | |
2515 return true; | |
2516 } | |
2517 } while (CanonicalizeMaxBoundary(&max)); | |
2518 | |
2519 // Failed to prove that maximum is bounded with array length. | |
2520 return false; | |
2521 } | |
2522 | |
2523 | |
2210 #undef __ | 2524 #undef __ |
2211 | 2525 |
2212 } // namespace dart | 2526 } // namespace dart |
OLD | NEW |