| 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/aot_optimizer.h" | 5 #include "vm/aot_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/branch_optimizer.h" | 8 #include "vm/branch_optimizer.h" |
| 9 #include "vm/cha.h" | 9 #include "vm/cha.h" |
| 10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| (...skipping 1931 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1942 InstanceCallInstr* call, | 1942 InstanceCallInstr* call, |
| 1943 MethodRecognizer::Kind recognized_kind) { | 1943 MethodRecognizer::Kind recognized_kind) { |
| 1944 // Cannot handle unboxed instructions. | 1944 // Cannot handle unboxed instructions. |
| 1945 return false; | 1945 return false; |
| 1946 } | 1946 } |
| 1947 | 1947 |
| 1948 | 1948 |
| 1949 // If type tests specified by 'ic_data' do not depend on type arguments, | 1949 // If type tests specified by 'ic_data' do not depend on type arguments, |
| 1950 // return mapping cid->result in 'results' (i : cid; i + 1: result). | 1950 // return mapping cid->result in 'results' (i : cid; i + 1: result). |
| 1951 // If all tests yield the same result, return it otherwise return Bool::null. | 1951 // If all tests yield the same result, return it otherwise return Bool::null. |
| 1952 // If no mapping is possible, 'results' is empty. | 1952 // If no mapping is possible, 'results' has less than |
| 1953 // (ic_data.NumberOfChecks() * 2) entries |
| 1953 // An instance-of test returning all same results can be converted to a class | 1954 // An instance-of test returning all same results can be converted to a class |
| 1954 // check. | 1955 // check. |
| 1955 RawBool* AotOptimizer::InstanceOfAsBool( | 1956 RawBool* AotOptimizer::InstanceOfAsBool( |
| 1956 const ICData& ic_data, | 1957 const ICData& ic_data, |
| 1957 const AbstractType& type, | 1958 const AbstractType& type, |
| 1958 ZoneGrowableArray<intptr_t>* results) const { | 1959 ZoneGrowableArray<intptr_t>* results) const { |
| 1959 ASSERT(results->is_empty()); | 1960 ASSERT(results->is_empty()); |
| 1960 ASSERT(ic_data.NumArgsTested() == 1); // Unary checks only. | 1961 ASSERT(ic_data.NumArgsTested() == 1); // Unary checks only. |
| 1961 if (type.IsFunctionType() || type.IsDartFunctionType() || | 1962 if (type.IsFunctionType() || type.IsDartFunctionType() || |
| 1962 !type.IsInstantiated() || type.IsMalformedOrMalbounded()) { | 1963 !type.IsInstantiated() || type.IsMalformedOrMalbounded()) { |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2071 results->Add(result); | 2072 results->Add(result); |
| 2072 } | 2073 } |
| 2073 } | 2074 } |
| 2074 | 2075 |
| 2075 | 2076 |
| 2076 // Tries to add cid tests to 'results' so that no deoptimization is | 2077 // Tries to add cid tests to 'results' so that no deoptimization is |
| 2077 // necessary. | 2078 // necessary. |
| 2078 // TODO(srdjan): Do also for other than 'int' type. | 2079 // TODO(srdjan): Do also for other than 'int' type. |
| 2079 static bool TryExpandTestCidsResult(ZoneGrowableArray<intptr_t>* results, | 2080 static bool TryExpandTestCidsResult(ZoneGrowableArray<intptr_t>* results, |
| 2080 const AbstractType& type) { | 2081 const AbstractType& type) { |
| 2081 ASSERT(results->length() >= 2); // At least on eentry. | 2082 ASSERT(results->length() >= 2); // At least on entry. |
| 2082 const ClassTable& class_table = *Isolate::Current()->class_table(); | 2083 const ClassTable& class_table = *Isolate::Current()->class_table(); |
| 2083 if ((*results)[0] != kSmiCid) { | 2084 if ((*results)[0] != kSmiCid) { |
| 2084 const Class& cls = Class::Handle(class_table.At(kSmiCid)); | 2085 const Class& cls = Class::Handle(class_table.At(kSmiCid)); |
| 2085 const Class& type_class = Class::Handle(type.type_class()); | 2086 const Class& type_class = Class::Handle(type.type_class()); |
| 2086 const bool smi_is_subtype = cls.IsSubtypeOf(TypeArguments::Handle(), | 2087 const bool smi_is_subtype = cls.IsSubtypeOf(TypeArguments::Handle(), |
| 2087 type_class, | 2088 type_class, |
| 2088 TypeArguments::Handle(), | 2089 TypeArguments::Handle(), |
| 2089 NULL, | 2090 NULL, |
| 2090 NULL, | 2091 NULL, |
| 2091 Heap::kOld); | 2092 Heap::kOld); |
| 2092 results->Add((*results)[results->length() - 2]); | 2093 results->Add((*results)[results->length() - 2]); |
| 2093 results->Add((*results)[results->length() - 2]); | 2094 results->Add((*results)[results->length() - 2]); |
| 2094 for (intptr_t i = results->length() - 3; i > 1; --i) { | 2095 for (intptr_t i = results->length() - 3; i > 1; --i) { |
| 2095 (*results)[i] = (*results)[i - 2]; | 2096 (*results)[i] = (*results)[i - 2]; |
| 2096 } | 2097 } |
| 2097 (*results)[0] = kSmiCid; | 2098 (*results)[0] = kSmiCid; |
| 2098 (*results)[1] = smi_is_subtype; | 2099 (*results)[1] = smi_is_subtype; |
| 2099 } | 2100 } |
| 2100 | 2101 |
| 2101 ASSERT(type.IsInstantiated() && !type.IsMalformedOrMalbounded()); | 2102 ASSERT(type.IsInstantiated() && !type.IsMalformedOrMalbounded()); |
| 2102 ASSERT(results->length() >= 2); | 2103 ASSERT(results->length() >= 2); |
| 2103 if (type.IsIntType()) { | 2104 if (type.IsSmiType()) { |
| 2105 ASSERT((*results)[0] == kSmiCid); |
| 2106 return false; |
| 2107 } else if (type.IsIntType()) { |
| 2104 ASSERT((*results)[0] == kSmiCid); | 2108 ASSERT((*results)[0] == kSmiCid); |
| 2105 TryAddTest(results, kMintCid, true); | 2109 TryAddTest(results, kMintCid, true); |
| 2106 TryAddTest(results, kBigintCid, true); | 2110 TryAddTest(results, kBigintCid, true); |
| 2107 // Cannot deoptimize since all tests returning true have been added. | 2111 // Cannot deoptimize since all tests returning true have been added. |
| 2108 return false; | 2112 return false; |
| 2113 } else if (type.IsNumberType()) { |
| 2114 ASSERT((*results)[0] == kSmiCid); |
| 2115 TryAddTest(results, kMintCid, true); |
| 2116 TryAddTest(results, kBigintCid, true); |
| 2117 TryAddTest(results, kDoubleCid, true); |
| 2118 return false; |
| 2119 } else if (type.IsDoubleType()) { |
| 2120 ASSERT((*results)[0] == kSmiCid); |
| 2121 TryAddTest(results, kDoubleCid, true); |
| 2122 return false; |
| 2109 } | 2123 } |
| 2110 | |
| 2111 return true; // May deoptimize since we have not identified all 'true' tests. | 2124 return true; // May deoptimize since we have not identified all 'true' tests. |
| 2112 } | 2125 } |
| 2113 | 2126 |
| 2114 | 2127 |
| 2115 // TODO(srdjan): Use ICData to check if always true or false. | 2128 // TODO(srdjan): Use ICData to check if always true or false. |
| 2116 void AotOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { | 2129 void AotOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { |
| 2117 ASSERT(Token::IsTypeTestOperator(call->token_kind())); | 2130 ASSERT(Token::IsTypeTestOperator(call->token_kind())); |
| 2118 // Guard against repeated speculative inlining. | |
| 2119 if (!use_speculative_inlining_ || | |
| 2120 IsBlackListedForInlining(call->deopt_id())) { | |
| 2121 return; | |
| 2122 } | |
| 2123 Definition* left = call->ArgumentAt(0); | 2131 Definition* left = call->ArgumentAt(0); |
| 2124 Definition* type_args = NULL; | 2132 Definition* type_args = NULL; |
| 2125 AbstractType& type = AbstractType::ZoneHandle(Z); | 2133 AbstractType& type = AbstractType::ZoneHandle(Z); |
| 2126 bool negate = false; | 2134 bool negate = false; |
| 2127 if (call->ArgumentCount() == 2) { | 2135 if (call->ArgumentCount() == 2) { |
| 2128 type_args = flow_graph()->constant_null(); | 2136 type_args = flow_graph()->constant_null(); |
| 2129 if (call->function_name().raw() == | 2137 if (call->function_name().raw() == |
| 2130 Library::PrivateCoreLibName(Symbols::_instanceOfNum()).raw()) { | 2138 Library::PrivateCoreLibName(Symbols::_instanceOfNum()).raw()) { |
| 2131 type = Type::Number(); | 2139 type = Type::Number(); |
| 2132 } else if (call->function_name().raw() == | 2140 } else if (call->function_name().raw() == |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2145 UNIMPLEMENTED(); | 2153 UNIMPLEMENTED(); |
| 2146 } | 2154 } |
| 2147 negate = Bool::Cast(call->ArgumentAt(1)->OriginalDefinition() | 2155 negate = Bool::Cast(call->ArgumentAt(1)->OriginalDefinition() |
| 2148 ->AsConstant()->value()).value(); | 2156 ->AsConstant()->value()).value(); |
| 2149 } else { | 2157 } else { |
| 2150 type_args = call->ArgumentAt(1); | 2158 type_args = call->ArgumentAt(1); |
| 2151 type = AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()).raw(); | 2159 type = AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()).raw(); |
| 2152 negate = Bool::Cast(call->ArgumentAt(3)->OriginalDefinition() | 2160 negate = Bool::Cast(call->ArgumentAt(3)->OriginalDefinition() |
| 2153 ->AsConstant()->value()).value(); | 2161 ->AsConstant()->value()).value(); |
| 2154 } | 2162 } |
| 2155 const ICData& unary_checks = | |
| 2156 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); | |
| 2157 if ((unary_checks.NumberOfChecks() > 0) && | |
| 2158 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { | |
| 2159 ZoneGrowableArray<intptr_t>* results = | |
| 2160 new(Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2); | |
| 2161 Bool& as_bool = | |
| 2162 Bool::ZoneHandle(Z, InstanceOfAsBool(unary_checks, type, results)); | |
| 2163 if (as_bool.IsNull()) { | |
| 2164 if (results->length() == unary_checks.NumberOfChecks() * 2) { | |
| 2165 const bool can_deopt = TryExpandTestCidsResult(results, type); | |
| 2166 TestCidsInstr* test_cids = new(Z) TestCidsInstr( | |
| 2167 call->token_pos(), | |
| 2168 negate ? Token::kISNOT : Token::kIS, | |
| 2169 new(Z) Value(left), | |
| 2170 *results, | |
| 2171 can_deopt ? call->deopt_id() : Thread::kNoDeoptId); | |
| 2172 // Remove type. | |
| 2173 ReplaceCall(call, test_cids); | |
| 2174 return; | |
| 2175 } | |
| 2176 } else { | |
| 2177 // TODO(srdjan): Use TestCidsInstr also for this case. | |
| 2178 // One result only. | |
| 2179 AddReceiverCheck(call); | |
| 2180 if (negate) { | |
| 2181 as_bool = Bool::Get(!as_bool.value()).raw(); | |
| 2182 } | |
| 2183 ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool); | |
| 2184 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | |
| 2185 PushArgumentInstr* push = call->PushArgumentAt(i); | |
| 2186 push->ReplaceUsesWith(push->value()->definition()); | |
| 2187 push->RemoveFromGraph(); | |
| 2188 } | |
| 2189 call->ReplaceUsesWith(bool_const); | |
| 2190 ASSERT(current_iterator()->Current() == call); | |
| 2191 current_iterator()->RemoveCurrentFromGraph(); | |
| 2192 return; | |
| 2193 } | |
| 2194 } | |
| 2195 | 2163 |
| 2196 if (TypeCheckAsClassEquality(type)) { | 2164 if (TypeCheckAsClassEquality(type)) { |
| 2197 LoadClassIdInstr* left_cid = new(Z) LoadClassIdInstr(new(Z) Value(left)); | 2165 LoadClassIdInstr* left_cid = new(Z) LoadClassIdInstr(new(Z) Value(left)); |
| 2198 InsertBefore(call, | 2166 InsertBefore(call, |
| 2199 left_cid, | 2167 left_cid, |
| 2200 NULL, | 2168 NULL, |
| 2201 FlowGraph::kValue); | 2169 FlowGraph::kValue); |
| 2202 const intptr_t type_cid = Class::Handle(Z, type.type_class()).id(); | 2170 const intptr_t type_cid = Class::Handle(Z, type.type_class()).id(); |
| 2203 ConstantInstr* cid = | 2171 ConstantInstr* cid = |
| 2204 flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(type_cid))); | 2172 flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(type_cid))); |
| 2205 | 2173 |
| 2206 StrictCompareInstr* check_cid = | 2174 StrictCompareInstr* check_cid = |
| 2207 new(Z) StrictCompareInstr( | 2175 new(Z) StrictCompareInstr( |
| 2208 call->token_pos(), | 2176 call->token_pos(), |
| 2209 negate ? Token::kNE_STRICT : Token::kEQ_STRICT, | 2177 negate ? Token::kNE_STRICT : Token::kEQ_STRICT, |
| 2210 new(Z) Value(left_cid), | 2178 new(Z) Value(left_cid), |
| 2211 new(Z) Value(cid), | 2179 new(Z) Value(cid), |
| 2212 false); // No number check. | 2180 false); // No number check. |
| 2213 ReplaceCall(call, check_cid); | 2181 ReplaceCall(call, check_cid); |
| 2214 return; | 2182 return; |
| 2215 } | 2183 } |
| 2216 | 2184 |
| 2185 const ICData& unary_checks = |
| 2186 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); |
| 2187 if ((unary_checks.NumberOfChecks() > 0) && |
| 2188 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { |
| 2189 ZoneGrowableArray<intptr_t>* results = |
| 2190 new(Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2); |
| 2191 InstanceOfAsBool(unary_checks, type, results); |
| 2192 if (results->length() == unary_checks.NumberOfChecks() * 2) { |
| 2193 const bool can_deopt = TryExpandTestCidsResult(results, type); |
| 2194 if (can_deopt && !IsAllowedForInlining(call->deopt_id())) { |
| 2195 // Guard against repeated speculative inlining. |
| 2196 return; |
| 2197 } |
| 2198 TestCidsInstr* test_cids = new(Z) TestCidsInstr( |
| 2199 call->token_pos(), |
| 2200 negate ? Token::kISNOT : Token::kIS, |
| 2201 new(Z) Value(left), |
| 2202 *results, |
| 2203 can_deopt ? call->deopt_id() : Thread::kNoDeoptId); |
| 2204 // Remove type. |
| 2205 ReplaceCall(call, test_cids); |
| 2206 return; |
| 2207 } |
| 2208 } |
| 2209 |
| 2217 InstanceOfInstr* instance_of = | 2210 InstanceOfInstr* instance_of = |
| 2218 new(Z) InstanceOfInstr(call->token_pos(), | 2211 new(Z) InstanceOfInstr(call->token_pos(), |
| 2219 new(Z) Value(left), | 2212 new(Z) Value(left), |
| 2220 new(Z) Value(type_args), | 2213 new(Z) Value(type_args), |
| 2221 type, | 2214 type, |
| 2222 negate, | 2215 negate, |
| 2223 call->deopt_id()); | 2216 call->deopt_id()); |
| 2224 ReplaceCall(call, instance_of); | 2217 ReplaceCall(call, instance_of); |
| 2225 } | 2218 } |
| 2226 | 2219 |
| 2227 | 2220 |
| 2228 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). | 2221 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). |
| 2229 void AotOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { | 2222 void AotOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { |
| 2230 ASSERT(Token::IsTypeCastOperator(call->token_kind())); | 2223 ASSERT(Token::IsTypeCastOperator(call->token_kind())); |
| 2231 // Guard against repeated speculative inlining. | |
| 2232 if (!use_speculative_inlining_ || | |
| 2233 IsBlackListedForInlining(call->deopt_id())) { | |
| 2234 return; | |
| 2235 } | |
| 2236 Definition* left = call->ArgumentAt(0); | 2224 Definition* left = call->ArgumentAt(0); |
| 2237 Definition* type_args = call->ArgumentAt(1); | 2225 Definition* type_args = call->ArgumentAt(1); |
| 2238 const AbstractType& type = | 2226 const AbstractType& type = |
| 2239 AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()); | 2227 AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()); |
| 2240 ASSERT(!type.IsMalformedOrMalbounded()); | 2228 ASSERT(!type.IsMalformedOrMalbounded()); |
| 2241 const ICData& unary_checks = | 2229 const ICData& unary_checks = |
| 2242 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); | 2230 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); |
| 2243 if ((unary_checks.NumberOfChecks() > 0) && | 2231 if ((unary_checks.NumberOfChecks() > 0) && |
| 2244 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { | 2232 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { |
| 2245 ZoneGrowableArray<intptr_t>* results = | 2233 ZoneGrowableArray<intptr_t>* results = |
| 2246 new(Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2); | 2234 new(Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2); |
| 2247 const Bool& as_bool = Bool::ZoneHandle(Z, | 2235 const Bool& as_bool = Bool::ZoneHandle(Z, |
| 2248 InstanceOfAsBool(unary_checks, type, results)); | 2236 InstanceOfAsBool(unary_checks, type, results)); |
| 2249 if (as_bool.raw() == Bool::True().raw()) { | 2237 if (as_bool.raw() == Bool::True().raw()) { |
| 2238 // Guard against repeated speculative inlining. |
| 2239 if (!IsAllowedForInlining(call->deopt_id())) { |
| 2240 return; |
| 2241 } |
| 2250 AddReceiverCheck(call); | 2242 AddReceiverCheck(call); |
| 2251 // Remove the original push arguments. | 2243 // Remove the original push arguments. |
| 2252 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 2244 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 2253 PushArgumentInstr* push = call->PushArgumentAt(i); | 2245 PushArgumentInstr* push = call->PushArgumentAt(i); |
| 2254 push->ReplaceUsesWith(push->value()->definition()); | 2246 push->ReplaceUsesWith(push->value()->definition()); |
| 2255 push->RemoveFromGraph(); | 2247 push->RemoveFromGraph(); |
| 2256 } | 2248 } |
| 2257 // Remove call, replace it with 'left'. | 2249 // Remove call, replace it with 'left'. |
| 2258 call->ReplaceUsesWith(left); | 2250 call->ReplaceUsesWith(left); |
| 2259 ASSERT(current_iterator()->Current() == call); | 2251 ASSERT(current_iterator()->Current() == call); |
| 2260 current_iterator()->RemoveCurrentFromGraph(); | 2252 current_iterator()->RemoveCurrentFromGraph(); |
| 2261 return; | 2253 return; |
| 2262 } | 2254 } |
| 2263 } | 2255 } |
| 2264 AssertAssignableInstr* assert_as = | 2256 AssertAssignableInstr* assert_as = |
| 2265 new(Z) AssertAssignableInstr(call->token_pos(), | 2257 new(Z) AssertAssignableInstr(call->token_pos(), |
| 2266 new(Z) Value(left), | 2258 new(Z) Value(left), |
| 2267 new(Z) Value(type_args), | 2259 new(Z) Value(type_args), |
| 2268 type, | 2260 type, |
| 2269 Symbols::InTypeCast(), | 2261 Symbols::InTypeCast(), |
| 2270 call->deopt_id()); | 2262 call->deopt_id()); |
| 2271 ReplaceCall(call, assert_as); | 2263 ReplaceCall(call, assert_as); |
| 2272 } | 2264 } |
| 2273 | 2265 |
| 2274 | 2266 |
| 2275 bool AotOptimizer::IsBlackListedForInlining(intptr_t call_deopt_id) { | 2267 bool AotOptimizer::IsAllowedForInlining(intptr_t call_deopt_id) { |
| 2268 if (!use_speculative_inlining_) return false; |
| 2276 for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) { | 2269 for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) { |
| 2277 if ((*inlining_black_list_)[i] == call_deopt_id) return true; | 2270 if ((*inlining_black_list_)[i] == call_deopt_id) return false; |
| 2278 } | 2271 } |
| 2279 return false; | 2272 return true; |
| 2280 } | 2273 } |
| 2281 | 2274 |
| 2282 | 2275 |
| 2283 static bool HasLikelySmiOperand(InstanceCallInstr* instr) { | 2276 static bool HasLikelySmiOperand(InstanceCallInstr* instr) { |
| 2284 // Phis with at least one known smi are // guessed to be likely smi as well. | 2277 // Phis with at least one known smi are // guessed to be likely smi as well. |
| 2285 for (intptr_t i = 0; i < instr->ArgumentCount(); ++i) { | 2278 for (intptr_t i = 0; i < instr->ArgumentCount(); ++i) { |
| 2286 PhiInstr* phi = instr->ArgumentAt(i)->AsPhi(); | 2279 PhiInstr* phi = instr->ArgumentAt(i)->AsPhi(); |
| 2287 if (phi != NULL) { | 2280 if (phi != NULL) { |
| 2288 for (intptr_t j = 0; j < phi->InputCount(); ++j) { | 2281 for (intptr_t j = 0; j < phi->InputCount(); ++j) { |
| 2289 if (phi->InputAt(j)->Type()->ToCid() == kSmiCid) return true; | 2282 if (phi->InputAt(j)->Type()->ToCid() == kSmiCid) return true; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2322 return; | 2315 return; |
| 2323 } | 2316 } |
| 2324 const ICData& unary_checks = | 2317 const ICData& unary_checks = |
| 2325 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); | 2318 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); |
| 2326 if ((unary_checks.NumberOfChecks() > 0) && | 2319 if ((unary_checks.NumberOfChecks() > 0) && |
| 2327 (op_kind == Token::kSET) && | 2320 (op_kind == Token::kSET) && |
| 2328 TryInlineInstanceSetter(instr, unary_checks)) { | 2321 TryInlineInstanceSetter(instr, unary_checks)) { |
| 2329 return; | 2322 return; |
| 2330 } | 2323 } |
| 2331 | 2324 |
| 2332 if (use_speculative_inlining_ && | 2325 if (IsAllowedForInlining(instr->deopt_id()) && |
| 2333 !IsBlackListedForInlining(instr->deopt_id()) && | |
| 2334 (unary_checks.NumberOfChecks() > 0)) { | 2326 (unary_checks.NumberOfChecks() > 0)) { |
| 2335 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) { | 2327 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) { |
| 2336 return; | 2328 return; |
| 2337 } | 2329 } |
| 2338 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) { | 2330 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) { |
| 2339 return; | 2331 return; |
| 2340 } | 2332 } |
| 2341 if ((op_kind == Token::kEQ) && TryReplaceWithEqualityOp(instr, op_kind)) { | 2333 if ((op_kind == Token::kEQ) && TryReplaceWithEqualityOp(instr, op_kind)) { |
| 2342 return; | 2334 return; |
| 2343 } | 2335 } |
| (...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2800 | 2792 |
| 2801 // Discard the environment from the original instruction because the store | 2793 // Discard the environment from the original instruction because the store |
| 2802 // can't deoptimize. | 2794 // can't deoptimize. |
| 2803 instr->RemoveEnvironment(); | 2795 instr->RemoveEnvironment(); |
| 2804 ReplaceCall(instr, store); | 2796 ReplaceCall(instr, store); |
| 2805 return true; | 2797 return true; |
| 2806 } | 2798 } |
| 2807 | 2799 |
| 2808 | 2800 |
| 2809 } // namespace dart | 2801 } // namespace dart |
| OLD | NEW |