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

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

Issue 1410733006: More general CHA-based inlining and devirtualization for precompiled code. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: addressed comments, fixed type propagation assertion failure Created 5 years, 2 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
« no previous file with comments | « runtime/vm/flow_graph_inliner.cc ('k') | runtime/vm/flow_graph_type_propagator.cc » ('j') | no next file with comments »
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/compiler.h" 9 #include "vm/compiler.h"
10 #include "vm/cpu.h" 10 #include "vm/cpu.h"
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 // TryCreateICData is only invoked if the ic_data target has not been called 180 // TryCreateICData is only invoked if the ic_data target has not been called
181 // yet, so no warning can possibly have been issued. 181 // yet, so no warning can possibly have been issued.
182 ASSERT(!call->ic_data()->IssuedJSWarning()); 182 ASSERT(!call->ic_data()->IssuedJSWarning());
183 if (call->ic_data()->MayCheckForJSWarning()) { 183 if (call->ic_data()->MayCheckForJSWarning()) {
184 return false; 184 return false;
185 } 185 }
186 } 186 }
187 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); 187 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested());
188 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount()); 188 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount());
189 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) { 189 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) {
190 const intptr_t cid = call->PushArgumentAt(i)->value()->Type()->ToCid(); 190 class_ids.Add(call->PushArgumentAt(i)->value()->Type()->ToCid());
191 class_ids.Add(cid);
192 } 191 }
193 192
194 const Token::Kind op_kind = call->token_kind(); 193 const Token::Kind op_kind = call->token_kind();
195 if (Token::IsRelationalOperator(op_kind) || 194 if (Token::IsRelationalOperator(op_kind) ||
196 Token::IsEqualityOperator(op_kind) || 195 Token::IsEqualityOperator(op_kind) ||
197 Token::IsBinaryOperator(op_kind)) { 196 Token::IsBinaryOperator(op_kind)) {
198 // Guess cid: if one of the inputs is a number assume that the other 197 // Guess cid: if one of the inputs is a number assume that the other
199 // is a number of same type. 198 // is a number of same type.
200 if (FLAG_guess_other_cid) { 199 if (FLAG_guess_other_cid) {
201 const intptr_t cid_0 = class_ids[0]; 200 const intptr_t cid_0 = class_ids[0];
202 const intptr_t cid_1 = class_ids[1]; 201 const intptr_t cid_1 = class_ids[1];
203 if ((cid_0 == kDynamicCid) && (IsNumberCid(cid_1))) { 202 if ((cid_0 == kDynamicCid) && (IsNumberCid(cid_1))) {
204 class_ids[0] = cid_1; 203 class_ids[0] = cid_1;
205 } else if (IsNumberCid(cid_0) && (cid_1 == kDynamicCid)) { 204 } else if (IsNumberCid(cid_0) && (cid_1 == kDynamicCid)) {
206 class_ids[1] = cid_0; 205 class_ids[1] = cid_0;
207 } 206 }
208 } 207 }
209 } 208 }
210 209
211 bool all_cids_known = true; 210 bool all_cids_known = true;
212 for (intptr_t i = 0; i < class_ids.length(); i++) { 211 for (intptr_t i = 0; i < class_ids.length(); i++) {
213 if (class_ids[i] == kDynamicCid) { 212 if (class_ids[i] == kDynamicCid) {
214 // Not all cid-s known. 213 // Not all cid-s known.
215 all_cids_known = false; 214 all_cids_known = false;
216 break; 215 break;
217 } 216 }
218 } 217 }
219 218
220 if (all_cids_known) { 219 if (all_cids_known) {
221 const Array& args_desc_array = Array::Handle(Z,
222 ArgumentsDescriptor::New(call->ArgumentCount(),
223 call->argument_names()));
224 ArgumentsDescriptor args_desc(args_desc_array);
225 const Class& receiver_class = Class::Handle(Z, 220 const Class& receiver_class = Class::Handle(Z,
226 isolate()->class_table()->At(class_ids[0])); 221 isolate()->class_table()->At(class_ids[0]));
227 if (!receiver_class.is_finalized()) { 222 if (!receiver_class.is_finalized()) {
228 // Do not eagerly finalize classes. ResolveDynamicForReceiverClass can 223 // Do not eagerly finalize classes. ResolveDynamicForReceiverClass can
229 // cause class finalization, since callee's receiver class may not be 224 // cause class finalization, since callee's receiver class may not be
230 // finalized yet. 225 // finalized yet.
231 return false; 226 return false;
232 } 227 }
228 const Array& args_desc_array = Array::Handle(Z,
229 ArgumentsDescriptor::New(call->ArgumentCount(),
230 call->argument_names()));
231 ArgumentsDescriptor args_desc(args_desc_array);
233 const Function& function = Function::Handle(Z, 232 const Function& function = Function::Handle(Z,
234 Resolver::ResolveDynamicForReceiverClass( 233 Resolver::ResolveDynamicForReceiverClass(
235 receiver_class, 234 receiver_class,
236 call->function_name(), 235 call->function_name(),
237 args_desc)); 236 args_desc));
238 if (function.IsNull()) { 237 if (function.IsNull()) {
239 return false; 238 return false;
240 } 239 }
241 240
242 // Create new ICData, do not modify the one attached to the instruction 241 // Create new ICData, do not modify the one attached to the instruction
(...skipping 3960 matching lines...) Expand 10 before | Expand all | Expand 10 after
4203 dst_name, 4202 dst_name,
4204 call->deopt_id()); 4203 call->deopt_id());
4205 ReplaceCall(call, assert_as); 4204 ReplaceCall(call, assert_as);
4206 } 4205 }
4207 4206
4208 4207
4209 // Special optimizations when running in --noopt mode. 4208 // Special optimizations when running in --noopt mode.
4210 void FlowGraphOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) { 4209 void FlowGraphOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) {
4211 // TODO(srdjan): Investigate other attempts, as they are not allowed to 4210 // TODO(srdjan): Investigate other attempts, as they are not allowed to
4212 // deoptimize. 4211 // deoptimize.
4213 const Token::Kind op_kind = instr->token_kind();
4214 if ((op_kind == Token::kGET) &&
4215 TryInlineInstanceGetter(instr, false /* no checks allowed */)) {
4216 return;
4217 }
4218 const ICData& unary_checks =
4219 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
4220 if ((instr->ic_data()->NumberOfChecks() > 0) &&
4221 (op_kind == Token::kSET) &&
4222 TryInlineInstanceSetter(instr, unary_checks, false /* no checks */)) {
4223 return;
4224 }
4225 if (instr->HasICData() && (instr->ic_data()->NumberOfUsedChecks() > 0)) {
4226 ASSERT(!FLAG_polymorphic_with_deopt);
4227 // OK to use checks with PolymorphicInstanceCallInstr since no
4228 // deoptimization is allowed.
4229 PolymorphicInstanceCallInstr* call =
4230 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
4231 true /* call_with_checks */);
4232 instr->ReplaceWith(call, current_iterator());
4233 return;
4234 }
4235 4212
4236 // Type test is special as it always gets converted into inlined code. 4213 // Type test is special as it always gets converted into inlined code.
4214 const Token::Kind op_kind = instr->token_kind();
4237 if (Token::IsTypeTestOperator(op_kind)) { 4215 if (Token::IsTypeTestOperator(op_kind)) {
4238 ReplaceWithInstanceOf(instr); 4216 ReplaceWithInstanceOf(instr);
4239 return; 4217 return;
4240 } 4218 }
4241 if (Token::IsTypeCastOperator(op_kind)) { 4219 if (Token::IsTypeCastOperator(op_kind)) {
4242 ReplaceWithTypeCast(instr); 4220 ReplaceWithTypeCast(instr);
4243 return; 4221 return;
4244 } 4222 }
4223
4224 if ((op_kind == Token::kGET) &&
4225 TryInlineInstanceGetter(instr, false /* no checks allowed */)) {
4226 return;
4227 }
4228 const ICData& unary_checks =
4229 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
4230 if ((unary_checks.NumberOfChecks() > 0) &&
4231 (op_kind == Token::kSET) &&
4232 TryInlineInstanceSetter(instr, unary_checks, false /* no checks */)) {
4233 return;
4234 }
4235
4236 bool has_one_target =
4237 (unary_checks.NumberOfChecks() > 0) && unary_checks.HasOneTarget();
4238 if (has_one_target) {
4239 // Check if the single target is a polymorphic target, if it is,
4240 // we don't have one target.
4241 const Function& target =
4242 Function::Handle(Z, unary_checks.GetTargetAt(0));
4243 const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target);
4244 has_one_target = !polymorphic_target;
4245 }
4246
4247 if (has_one_target) {
4248 RawFunction::Kind function_kind =
4249 Function::Handle(Z, unary_checks.GetTargetAt(0)).kind();
4250 if (!InstanceCallNeedsClassCheck(instr, function_kind)) {
4251 PolymorphicInstanceCallInstr* call =
4252 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
4253 /* with_checks = */ false);
4254 instr->ReplaceWith(call, current_iterator());
4255 return;
4256 }
4257 }
4258
4259 // More than one targets. Generate generic polymorphic call without
4260 // deoptimization.
4261 if (instr->ic_data()->NumberOfUsedChecks() > 0) {
4262 ASSERT(!FLAG_polymorphic_with_deopt);
4263 // OK to use checks with PolymorphicInstanceCallInstr since no
4264 // deoptimization is allowed.
4265 PolymorphicInstanceCallInstr* call =
4266 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
4267 /* with_checks = */ true);
4268 instr->ReplaceWith(call, current_iterator());
4269 return;
4270 }
4271
4272 // No IC data checks. Try resolve target using the propagated type.
4273 // If the propagated type has a method with the target name and there are
4274 // no overrides with that name according to CHA, call the method directly.
4275 const AbstractType* receiver_type =
4276 instr->PushArgumentAt(0)->value()->Type()->ToAbstractType();
4277 if (receiver_type->IsDynamicType()) return;
4278 if (receiver_type->HasResolvedTypeClass()) {
4279 const Class& receiver_class = Class::Handle(Z,
4280 receiver_type->type_class());
4281 const Array& args_desc_array = Array::Handle(Z,
4282 ArgumentsDescriptor::New(instr->ArgumentCount(),
4283 instr->argument_names()));
4284 ArgumentsDescriptor args_desc(args_desc_array);
4285 const Function& function = Function::Handle(Z,
4286 Resolver::ResolveDynamicForReceiverClass(
4287 receiver_class,
4288 instr->function_name(),
4289 args_desc));
4290 if (function.IsNull()) {
4291 return;
4292 }
4293 if (!thread()->cha()->HasOverride(receiver_class, instr->function_name())) {
4294 if (FLAG_trace_cha) {
4295 THR_Print(" **(CHA) Instance call needs no check, "
4296 "no overrides of '%s' '%s'\n",
4297 instr->function_name().ToCString(), receiver_class.ToCString());
4298 }
4299 thread()->cha()->AddToLeafClasses(receiver_class);
4300
4301 // Create fake IC data with the resolved target.
4302 const ICData& ic_data = ICData::Handle(
4303 ICData::New(flow_graph_->function(),
4304 instr->function_name(),
4305 args_desc_array,
4306 Thread::kNoDeoptId,
4307 /* args_tested = */ 1));
4308 ic_data.AddReceiverCheck(receiver_class.id(), function);
4309 PolymorphicInstanceCallInstr* call =
4310 new(Z) PolymorphicInstanceCallInstr(instr, ic_data,
4311 /* with_checks = */ false);
4312 instr->ReplaceWith(call, current_iterator());
4313 return;
4314 }
4315 }
4245 } 4316 }
4246 4317
4247 4318
4248 // Tries to optimize instance call by replacing it with a faster instruction 4319 // Tries to optimize instance call by replacing it with a faster instruction
4249 // (e.g, binary op, field load, ..). 4320 // (e.g, binary op, field load, ..).
4250 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { 4321 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
4251 if (Compiler::always_optimize()) { 4322 if (Compiler::always_optimize()) {
4252 InstanceCallNoopt(instr); 4323 InstanceCallNoopt(instr);
4253 return; 4324 return;
4254 } 4325 }
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
4325 const Function& target = 4396 const Function& target =
4326 Function::Handle(Z, unary_checks.GetTargetAt(0)); 4397 Function::Handle(Z, unary_checks.GetTargetAt(0));
4327 const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target); 4398 const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target);
4328 has_one_target = !polymorphic_target; 4399 has_one_target = !polymorphic_target;
4329 } 4400 }
4330 4401
4331 if (has_one_target) { 4402 if (has_one_target) {
4332 RawFunction::Kind function_kind = 4403 RawFunction::Kind function_kind =
4333 Function::Handle(Z, unary_checks.GetTargetAt(0)).kind(); 4404 Function::Handle(Z, unary_checks.GetTargetAt(0)).kind();
4334 if (!InstanceCallNeedsClassCheck(instr, function_kind)) { 4405 if (!InstanceCallNeedsClassCheck(instr, function_kind)) {
4335 const bool call_with_checks = false;
4336 PolymorphicInstanceCallInstr* call = 4406 PolymorphicInstanceCallInstr* call =
4337 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, 4407 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
4338 call_with_checks); 4408 /* call_with_checks = */ false);
4339 instr->ReplaceWith(call, current_iterator()); 4409 instr->ReplaceWith(call, current_iterator());
4340 return; 4410 return;
4341 } 4411 }
4342 } 4412 }
4343 4413
4344 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { 4414 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) {
4345 bool call_with_checks; 4415 bool call_with_checks;
4346 if (has_one_target && FLAG_polymorphic_with_deopt) { 4416 if (has_one_target && FLAG_polymorphic_with_deopt) {
4347 // Type propagation has not run yet, we cannot eliminate the check. 4417 // Type propagation has not run yet, we cannot eliminate the check.
4348 AddReceiverCheck(instr); 4418 AddReceiverCheck(instr);
(...skipping 4367 matching lines...) Expand 10 before | Expand all | Expand 10 after
8716 8786
8717 // Insert materializations at environment uses. 8787 // Insert materializations at environment uses.
8718 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { 8788 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) {
8719 CreateMaterializationAt( 8789 CreateMaterializationAt(
8720 exits_collector_.exits()[i], alloc, *slots); 8790 exits_collector_.exits()[i], alloc, *slots);
8721 } 8791 }
8722 } 8792 }
8723 8793
8724 8794
8725 } // namespace dart 8795 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_inliner.cc ('k') | runtime/vm/flow_graph_type_propagator.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698