Chromium Code Reviews| 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 |