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

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: 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
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 4059 matching lines...) Expand 10 before | Expand all | Expand 10 after
4302 dst_name, 4301 dst_name,
4303 call->deopt_id()); 4302 call->deopt_id());
4304 ReplaceCall(call, assert_as); 4303 ReplaceCall(call, assert_as);
4305 } 4304 }
4306 4305
4307 4306
4308 // Special optimizations when running in --noopt mode. 4307 // Special optimizations when running in --noopt mode.
4309 void FlowGraphOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) { 4308 void FlowGraphOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) {
4310 // TODO(srdjan): Investigate other attempts, as they are not allowed to 4309 // TODO(srdjan): Investigate other attempts, as they are not allowed to
4311 // deoptimize. 4310 // deoptimize.
4312 const Token::Kind op_kind = instr->token_kind();
4313 if ((op_kind == Token::kGET) &&
4314 TryInlineInstanceGetter(instr, false /* no checks allowed */)) {
4315 return;
4316 }
4317 const ICData& unary_checks =
4318 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
4319 if ((instr->ic_data()->NumberOfChecks() > 0) &&
4320 (op_kind == Token::kSET) &&
4321 TryInlineInstanceSetter(instr, unary_checks, false /* no checks */)) {
4322 return;
4323 }
4324 if (instr->HasICData() && (instr->ic_data()->NumberOfUsedChecks() > 0)) {
4325 ASSERT(!FLAG_polymorphic_with_deopt);
4326 // OK to use checks with PolymorphicInstanceCallInstr since no
4327 // deoptimization is allowed.
4328 PolymorphicInstanceCallInstr* call =
4329 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
4330 true /* call_with_checks */);
4331 instr->ReplaceWith(call, current_iterator());
4332 return;
4333 }
4334 4311
4335 // Type test is special as it always gets converted into inlined code. 4312 // Type test is special as it always gets converted into inlined code.
4313 const Token::Kind op_kind = instr->token_kind();
4336 if (Token::IsTypeTestOperator(op_kind)) { 4314 if (Token::IsTypeTestOperator(op_kind)) {
4337 ReplaceWithInstanceOf(instr); 4315 ReplaceWithInstanceOf(instr);
4338 return; 4316 return;
4339 } 4317 }
4340 if (Token::IsTypeCastOperator(op_kind)) { 4318 if (Token::IsTypeCastOperator(op_kind)) {
4341 ReplaceWithTypeCast(instr); 4319 ReplaceWithTypeCast(instr);
4342 return; 4320 return;
4343 } 4321 }
4322
4323 if ((op_kind == Token::kGET) &&
4324 TryInlineInstanceGetter(instr, false /* no checks allowed */)) {
4325 return;
4326 }
4327 const ICData& unary_checks =
4328 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
4329 if ((unary_checks.NumberOfChecks() > 0) &&
4330 (op_kind == Token::kSET) &&
4331 TryInlineInstanceSetter(instr, unary_checks, false /* no checks */)) {
4332 return;
4333 }
4334
4335 bool has_one_target =
4336 (unary_checks.NumberOfChecks() > 0) && unary_checks.HasOneTarget();
4337 if (has_one_target) {
4338 // Check if the single target is a polymorphic target, if it is,
4339 // we don't have one target.
4340 const Function& target =
4341 Function::Handle(Z, unary_checks.GetTargetAt(0));
4342 const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target);
4343 has_one_target = !polymorphic_target;
4344 }
4345
4346 if (has_one_target) {
4347 RawFunction::Kind function_kind =
4348 Function::Handle(Z, unary_checks.GetTargetAt(0)).kind();
4349 if (!InstanceCallNeedsClassCheck(instr, function_kind)) {
4350 PolymorphicInstanceCallInstr* call =
4351 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
4352 /* with_checks = */ false);
4353 instr->ReplaceWith(call, current_iterator());
4354 return;
4355 }
4356 }
4357
4358 // More than one targets. Generate generic polymorphic call without
4359 // deoptimization.
4360 if (instr->ic_data()->NumberOfUsedChecks() > 0) {
4361 ASSERT(!FLAG_polymorphic_with_deopt);
4362 // OK to use checks with PolymorphicInstanceCallInstr since no
4363 // deoptimization is allowed.
4364 PolymorphicInstanceCallInstr* call =
4365 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
4366 /* with_checks = */ true);
4367 instr->ReplaceWith(call, current_iterator());
4368 return;
4369 }
4370
4371 // No IC data checks. Try resolve target using the propagated type.
4372 // If the propagated type has a method with the target name and there are
4373 // no overrides with that name according to CHA, call the method directly.
4374 const AbstractType* receiver_type =
4375 instr->PushArgumentAt(0)->value()->Type()->ToAbstractType();
4376 if (receiver_type->IsDynamicType()) return;
4377 if (receiver_type->HasResolvedTypeClass()) {
4378 const Class& receiver_class = Class::Handle(Z,
4379 receiver_type->type_class());
4380 const Array& args_desc_array = Array::Handle(Z,
4381 ArgumentsDescriptor::New(instr->ArgumentCount(),
4382 instr->argument_names()));
4383 ArgumentsDescriptor args_desc(args_desc_array);
4384 const Function& function = Function::Handle(Z,
4385 Resolver::ResolveDynamicForReceiverClass(
4386 receiver_class,
4387 instr->function_name(),
4388 args_desc));
4389 if (function.IsNull()) {
4390 return;
4391 }
4392 if (!thread()->cha()->HasOverride(receiver_class, instr->function_name())) {
4393 if (FLAG_trace_cha) {
4394 THR_Print(" **(CHA) Instance call needs no check, "
4395 "no overrides of '%s' '%s'\n",
4396 instr->function_name().ToCString(), receiver_class.ToCString());
4397 }
4398 thread()->cha()->AddToLeafClasses(receiver_class);
4399
4400 // Create fake IC data with the resolved target.
4401 const ICData& ic_data = ICData::Handle(
4402 ICData::New(flow_graph_->function(),
4403 instr->function_name(),
4404 args_desc_array,
4405 Thread::kNoDeoptId,
4406 1));
rmacnak 2015/10/21 18:00:30 1 /* args_tested */
Florian Schneider 2015/10/22 13:59:25 Done.
4407 ic_data.AddReceiverCheck(receiver_class.id(), function);
4408 PolymorphicInstanceCallInstr* call =
4409 new(Z) PolymorphicInstanceCallInstr(instr, ic_data,
4410 /* with_checks = */ false);
4411 instr->ReplaceWith(call, current_iterator());
4412 return;
4413 }
4414 }
4344 } 4415 }
4345 4416
4346 4417
4347 // Tries to optimize instance call by replacing it with a faster instruction 4418 // Tries to optimize instance call by replacing it with a faster instruction
4348 // (e.g, binary op, field load, ..). 4419 // (e.g, binary op, field load, ..).
4349 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { 4420 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
4350 if (Compiler::always_optimize()) { 4421 if (Compiler::always_optimize()) {
4351 InstanceCallNoopt(instr); 4422 InstanceCallNoopt(instr);
4352 return; 4423 return;
4353 } 4424 }
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
4424 const Function& target = 4495 const Function& target =
4425 Function::Handle(Z, unary_checks.GetTargetAt(0)); 4496 Function::Handle(Z, unary_checks.GetTargetAt(0));
4426 const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target); 4497 const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target);
4427 has_one_target = !polymorphic_target; 4498 has_one_target = !polymorphic_target;
4428 } 4499 }
4429 4500
4430 if (has_one_target) { 4501 if (has_one_target) {
4431 RawFunction::Kind function_kind = 4502 RawFunction::Kind function_kind =
4432 Function::Handle(Z, unary_checks.GetTargetAt(0)).kind(); 4503 Function::Handle(Z, unary_checks.GetTargetAt(0)).kind();
4433 if (!InstanceCallNeedsClassCheck(instr, function_kind)) { 4504 if (!InstanceCallNeedsClassCheck(instr, function_kind)) {
4434 const bool call_with_checks = false;
4435 PolymorphicInstanceCallInstr* call = 4505 PolymorphicInstanceCallInstr* call =
4436 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, 4506 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
4437 call_with_checks); 4507 /* call_with_checks = */ false);
4438 instr->ReplaceWith(call, current_iterator()); 4508 instr->ReplaceWith(call, current_iterator());
4439 return; 4509 return;
4440 } 4510 }
4441 } 4511 }
4442 4512
4443 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { 4513 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) {
4444 bool call_with_checks; 4514 bool call_with_checks;
4445 if (has_one_target && FLAG_polymorphic_with_deopt) { 4515 if (has_one_target && FLAG_polymorphic_with_deopt) {
4446 // Type propagation has not run yet, we cannot eliminate the check. 4516 // Type propagation has not run yet, we cannot eliminate the check.
4447 AddReceiverCheck(instr); 4517 AddReceiverCheck(instr);
(...skipping 4367 matching lines...) Expand 10 before | Expand all | Expand 10 after
8815 8885
8816 // Insert materializations at environment uses. 8886 // Insert materializations at environment uses.
8817 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { 8887 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) {
8818 CreateMaterializationAt( 8888 CreateMaterializationAt(
8819 exits_collector_.exits()[i], alloc, *slots); 8889 exits_collector_.exits()[i], alloc, *slots);
8820 } 8890 }
8821 } 8891 }
8822 8892
8823 8893
8824 } // namespace dart 8894 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698