| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 library cps_ir.optimization.inline; | 5 library cps_ir.optimization.inline; |
| 6 | 6 |
| 7 import 'cps_fragment.dart'; | 7 import 'cps_fragment.dart'; |
| 8 import 'cps_ir_builder.dart' show ThisParameterLocal; | 8 import 'cps_ir_builder.dart' show ThisParameterLocal; |
| 9 import 'cps_ir_nodes.dart'; | 9 import 'cps_ir_nodes.dart'; |
| 10 import 'optimizers.dart'; | 10 import 'optimizers.dart'; |
| (...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 364 // V8 does not optimize functions containing a try statement. Inlining | 364 // V8 does not optimize functions containing a try statement. Inlining |
| 365 // code containing a try statement will make the optimizable calling code | 365 // code containing a try statement will make the optimizable calling code |
| 366 // become unoptimizable. | 366 // become unoptimizable. |
| 367 if (target.resolvedAst.elements.containsTryStatement) { | 367 if (target.resolvedAst.elements.containsTryStatement) { |
| 368 return null; | 368 return null; |
| 369 } | 369 } |
| 370 | 370 |
| 371 Reference<Primitive> dartReceiver = invoke.dartReceiverReference; | 371 Reference<Primitive> dartReceiver = invoke.dartReceiverReference; |
| 372 TypeMask abstractReceiver = | 372 TypeMask abstractReceiver = |
| 373 dartReceiver == null ? null : abstractType(dartReceiver); | 373 dartReceiver == null ? null : abstractType(dartReceiver); |
| 374 // The receiver is non-null in a method body, unless the receiver is known |
| 375 // to be `null` (isEmpty covers `null` and unreachable). |
| 376 TypeMask abstractReceiverInMethod = abstractReceiver == null |
| 377 ? null |
| 378 : abstractReceiver.isEmpty |
| 379 ? abstractReceiver |
| 380 : abstractReceiver.nonNullable(); |
| 374 List<TypeMask> abstractArguments = | 381 List<TypeMask> abstractArguments = |
| 375 invoke.arguments.map(abstractType).toList(); | 382 invoke.arguments.map(abstractType).toList(); |
| 376 var cachedResult = _inliner.cache.get(target, callStructure, | 383 var cachedResult = _inliner.cache.get(target, callStructure, |
| 377 abstractReceiver, | 384 abstractReceiverInMethod, |
| 378 abstractArguments); | 385 abstractArguments); |
| 379 | 386 |
| 380 // Negative inlining result in the cache. | 387 // Negative inlining result in the cache. |
| 381 if (cachedResult == InliningCache.NO_INLINE) return null; | 388 if (cachedResult == InliningCache.NO_INLINE) return null; |
| 382 | 389 |
| 383 Primitive finish(FunctionDefinition function) { | 390 Primitive finish(FunctionDefinition function) { |
| 384 _fragment = new CpsFragment(invoke.sourceInformation); | 391 _fragment = new CpsFragment(invoke.sourceInformation); |
| 385 Primitive receiver = invoke.receiver?.definition; | 392 Primitive receiver = invoke.receiver?.definition; |
| 386 List<Primitive> arguments = | 393 List<Primitive> arguments = |
| 387 invoke.arguments.map((Reference ref) => ref.definition).toList(); | 394 invoke.arguments.map((Reference ref) => ref.definition).toList(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 402 | 409 |
| 403 // Positive inlining result in the cache. | 410 // Positive inlining result in the cache. |
| 404 if (cachedResult is FunctionDefinition) { | 411 if (cachedResult is FunctionDefinition) { |
| 405 return finish(cachedResult); | 412 return finish(cachedResult); |
| 406 } | 413 } |
| 407 | 414 |
| 408 // We have not seen this combination of target and abstract arguments | 415 // We have not seen this combination of target and abstract arguments |
| 409 // before. Make an inlining decision. | 416 // before. Make an inlining decision. |
| 410 assert(cachedResult == InliningCache.ABSENT); | 417 assert(cachedResult == InliningCache.ABSENT); |
| 411 Primitive doNotInline() { | 418 Primitive doNotInline() { |
| 412 _inliner.cache.putNegative(target, callStructure, abstractReceiver, | 419 _inliner.cache.putNegative( |
| 413 abstractArguments); | 420 target, callStructure, abstractReceiverInMethod, abstractArguments); |
| 414 return null; | 421 return null; |
| 415 } | 422 } |
| 416 if (backend.annotations.noInline(target)) return doNotInline(); | 423 if (backend.annotations.noInline(target)) return doNotInline(); |
| 417 if (isRecursive(target, callStructure)) return doNotInline(); | 424 if (isRecursive(target, callStructure)) return doNotInline(); |
| 418 | 425 |
| 419 FunctionDefinition function; | 426 FunctionDefinition function; |
| 420 if (callStructure != null && | 427 if (callStructure != null && |
| 421 target.functionSignature.parameterCount != | 428 target.functionSignature.parameterCount != |
| 422 callStructure.argumentCount) { | 429 callStructure.argumentCount) { |
| 423 // The argument count at the call site does not match the target's | 430 // The argument count at the call site does not match the target's |
| 424 // formal parameter count. Build the IR term for an adapter function | 431 // formal parameter count. Build the IR term for an adapter function |
| 425 // body. | 432 // body. |
| 426 function = buildAdapter(invoke, target); | 433 function = buildAdapter(invoke, target); |
| 427 } else { | 434 } else { |
| 428 function = _inliner.functionCompiler.compileToCpsIr(target); | 435 function = _inliner.functionCompiler.compileToCpsIr(target); |
| 429 void setValue(Variable variable, Reference<Primitive> value) { | 436 void setValue(Variable variable, Reference<Primitive> value) { |
| 430 variable.type = value.definition.type; | 437 variable.type = value.definition.type; |
| 431 } | 438 } |
| 432 if (invoke.receiver != null) { | 439 if (invoke.callingConvention == CallingConvention.Intercepted) { |
| 433 setValue(function.thisParameter, invoke.receiver); | 440 setValue(function.thisParameter, invoke.receiver); |
| 434 } | 441 function.parameters[0].type = abstractReceiverInMethod; |
| 435 for (int i = 0; i < invoke.arguments.length; ++i) { | 442 for (int i = 1; i < invoke.arguments.length; ++i) { |
| 436 setValue(function.parameters[i], invoke.arguments[i]); | 443 setValue(function.parameters[i], invoke.arguments[i]); |
| 444 } |
| 445 } else { |
| 446 if (invoke.receiver != null) { |
| 447 function.thisParameter.type = abstractReceiverInMethod; |
| 448 } |
| 449 for (int i = 0; i < invoke.arguments.length; ++i) { |
| 450 setValue(function.parameters[i], invoke.arguments[i]); |
| 451 } |
| 437 } | 452 } |
| 438 optimizeBeforeInlining(function); | 453 optimizeBeforeInlining(function); |
| 439 } | 454 } |
| 440 | 455 |
| 441 // Inline calls in the body. | 456 // Inline calls in the body. |
| 442 _inliner.rewrite(function, callStructure); | 457 _inliner.rewrite(function, callStructure); |
| 443 | 458 |
| 444 // Compute the size. | 459 // Compute the size. |
| 445 // TODO(kmillikin): Tune the size bound. | 460 // TODO(kmillikin): Tune the size bound. |
| 446 int size = SizeVisitor.sizeOf(invoke, function); | 461 int size = SizeVisitor.sizeOf(invoke, function); |
| 447 if (!_inliner.isCalledOnce(target) && size > 11) return doNotInline(); | 462 if (!_inliner.isCalledOnce(target) && size > 11) return doNotInline(); |
| 448 | 463 |
| 449 _inliner.cache.putPositive(target, callStructure, abstractReceiver, | 464 _inliner.cache.putPositive(target, callStructure, abstractReceiverInMethod, |
| 450 abstractArguments, function); | 465 abstractArguments, function); |
| 451 return finish(function); | 466 return finish(function); |
| 452 } | 467 } |
| 453 | 468 |
| 454 Primitive nullReceiverGuard(InvocationPrimitive invoke, | 469 Primitive nullReceiverGuard(InvocationPrimitive invoke, |
| 455 CpsFragment fragment, | 470 CpsFragment fragment, |
| 456 Primitive dartReceiver, | 471 Primitive dartReceiver, |
| 457 TypeMask abstractReceiver) { | 472 TypeMask abstractReceiver) { |
| 458 Selector selector = invoke is InvokeMethod ? invoke.selector : null; | 473 Selector selector = invoke is InvokeMethod ? invoke.selector : null; |
| 459 if (typeSystem.isDefinitelyNum(abstractReceiver, allowNull: true)) { | 474 if (typeSystem.isDefinitelyNum(abstractReceiver, allowNull: true)) { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 507 // We cannot inline a constructor invocation containing type arguments | 522 // We cannot inline a constructor invocation containing type arguments |
| 508 // because CreateInstance in the body does not know the type arguments. | 523 // because CreateInstance in the body does not know the type arguments. |
| 509 // We would incorrectly instantiate a class like A instead of A<B>. | 524 // We would incorrectly instantiate a class like A instead of A<B>. |
| 510 // TODO(kmillikin): try to fix this. | 525 // TODO(kmillikin): try to fix this. |
| 511 GenericType generic = node.dartType; | 526 GenericType generic = node.dartType; |
| 512 if (generic.typeArguments.any((DartType t) => !t.isDynamic)) return null; | 527 if (generic.typeArguments.any((DartType t) => !t.isDynamic)) return null; |
| 513 } | 528 } |
| 514 return tryInlining(node, node.target, null); | 529 return tryInlining(node, node.target, null); |
| 515 } | 530 } |
| 516 } | 531 } |
| OLD | NEW |