| 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 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 dartReceiver == null ? null : abstractType(dartReceiver); | 373 dartReceiver == null ? null : abstractType(dartReceiver); |
| 374 List<TypeMask> abstractArguments = | 374 List<TypeMask> abstractArguments = |
| 375 invoke.arguments.map(abstractType).toList(); | 375 invoke.arguments.map(abstractType).toList(); |
| 376 var cachedResult = _inliner.cache.get(target, callStructure, | 376 var cachedResult = _inliner.cache.get(target, callStructure, |
| 377 abstractReceiver, | 377 abstractReceiver, |
| 378 abstractArguments); | 378 abstractArguments); |
| 379 | 379 |
| 380 // Negative inlining result in the cache. | 380 // Negative inlining result in the cache. |
| 381 if (cachedResult == InliningCache.NO_INLINE) return null; | 381 if (cachedResult == InliningCache.NO_INLINE) return null; |
| 382 | 382 |
| 383 // Positive inlining result in the cache. | 383 Primitive finish(FunctionDefinition function) { |
| 384 if (cachedResult is FunctionDefinition) { | |
| 385 FunctionDefinition function = cachedResult; | |
| 386 _fragment = new CpsFragment(invoke.sourceInformation); | 384 _fragment = new CpsFragment(invoke.sourceInformation); |
| 387 Primitive receiver = invoke.receiver?.definition; | 385 Primitive receiver = invoke.receiver?.definition; |
| 388 List<Primitive> arguments = | 386 List<Primitive> arguments = |
| 389 invoke.arguments.map((Reference ref) => ref.definition).toList(); | 387 invoke.arguments.map((Reference ref) => ref.definition).toList(); |
| 390 // Add a null check to the inlined function body if necessary. The | 388 // Add a null check to the inlined function body if necessary. The |
| 391 // cached function body does not contain the null check. | 389 // cached function body does not contain the null check. |
| 392 if (dartReceiver != null && abstractReceiver.isNullable) { | 390 if (dartReceiver != null && abstractReceiver.isNullable) { |
| 393 Primitive check = nullReceiverGuard( | 391 Primitive check = nullReceiverGuard( |
| 394 invoke, _fragment, dartReceiver.definition, abstractReceiver); | 392 invoke, _fragment, dartReceiver.definition, abstractReceiver); |
| 395 if (invoke.callingConvention == CallingConvention.Intercepted) { | 393 if (invoke.callingConvention == CallingConvention.Intercepted) { |
| 396 arguments[0] = check; | 394 arguments[0] = check; |
| 397 } else { | 395 } else { |
| 398 receiver = check; | 396 receiver = check; |
| 399 } | 397 } |
| 400 } | 398 } |
| 401 return _fragment.inlineFunction(function, receiver, arguments, | 399 return _fragment.inlineFunction(function, receiver, arguments, |
| 402 hint: invoke.hint); | 400 hint: invoke.hint); |
| 403 } | 401 } |
| 404 | 402 |
| 403 // Positive inlining result in the cache. |
| 404 if (cachedResult is FunctionDefinition) { |
| 405 return finish(cachedResult); |
| 406 } |
| 407 |
| 405 // We have not seen this combination of target and abstract arguments | 408 // We have not seen this combination of target and abstract arguments |
| 406 // before. Make an inlining decision. | 409 // before. Make an inlining decision. |
| 407 assert(cachedResult == InliningCache.ABSENT); | 410 assert(cachedResult == InliningCache.ABSENT); |
| 408 Primitive doNotInline() { | 411 Primitive doNotInline() { |
| 409 _inliner.cache.putNegative(target, callStructure, abstractReceiver, | 412 _inliner.cache.putNegative(target, callStructure, abstractReceiver, |
| 410 abstractArguments); | 413 abstractArguments); |
| 411 return null; | 414 return null; |
| 412 } | 415 } |
| 413 if (backend.annotations.noInline(target)) return doNotInline(); | 416 if (backend.annotations.noInline(target)) return doNotInline(); |
| 414 if (isRecursive(target, callStructure)) return doNotInline(); | 417 if (isRecursive(target, callStructure)) return doNotInline(); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 438 // Inline calls in the body. | 441 // Inline calls in the body. |
| 439 _inliner.rewrite(function, callStructure); | 442 _inliner.rewrite(function, callStructure); |
| 440 | 443 |
| 441 // Compute the size. | 444 // Compute the size. |
| 442 // TODO(kmillikin): Tune the size bound. | 445 // TODO(kmillikin): Tune the size bound. |
| 443 int size = SizeVisitor.sizeOf(invoke, function); | 446 int size = SizeVisitor.sizeOf(invoke, function); |
| 444 if (!_inliner.isCalledOnce(target) && size > 11) return doNotInline(); | 447 if (!_inliner.isCalledOnce(target) && size > 11) return doNotInline(); |
| 445 | 448 |
| 446 _inliner.cache.putPositive(target, callStructure, abstractReceiver, | 449 _inliner.cache.putPositive(target, callStructure, abstractReceiver, |
| 447 abstractArguments, function); | 450 abstractArguments, function); |
| 448 _fragment = new CpsFragment(invoke.sourceInformation); | 451 return finish(function); |
| 449 Primitive receiver = invoke.receiver?.definition; | |
| 450 List<Primitive> arguments = | |
| 451 invoke.arguments.map((Reference ref) => ref.definition).toList(); | |
| 452 if (dartReceiver != null && abstractReceiver.isNullable) { | |
| 453 Primitive check = | |
| 454 _fragment.letPrim(new NullCheck(dartReceiver.definition, | |
| 455 invoke.sourceInformation)); | |
| 456 check.type = abstractReceiver.nonNullable(); | |
| 457 if (invoke.callingConvention == CallingConvention.Intercepted) { | |
| 458 arguments[0] = check; | |
| 459 } else { | |
| 460 receiver = check; | |
| 461 } | |
| 462 } | |
| 463 return _fragment.inlineFunction(function, receiver, arguments, | |
| 464 hint: invoke.hint); | |
| 465 } | 452 } |
| 466 | 453 |
| 467 Primitive nullReceiverGuard(InvocationPrimitive invoke, | 454 Primitive nullReceiverGuard(InvocationPrimitive invoke, |
| 468 CpsFragment fragment, | 455 CpsFragment fragment, |
| 469 Primitive dartReceiver, | 456 Primitive dartReceiver, |
| 470 TypeMask abstractReceiver) { | 457 TypeMask abstractReceiver) { |
| 471 Selector selector = invoke is InvokeMethod ? invoke.selector : null; | 458 Selector selector = invoke is InvokeMethod ? invoke.selector : null; |
| 472 if (typeSystem.isDefinitelyNum(abstractReceiver, allowNull: true)) { | 459 if (typeSystem.isDefinitelyNum(abstractReceiver, allowNull: true)) { |
| 473 Primitive condition = _fragment.letPrim( | 460 Primitive condition = _fragment.letPrim( |
| 474 new ApplyBuiltinOperator(BuiltinOperator.IsNotNumber, | 461 new ApplyBuiltinOperator(BuiltinOperator.IsNotNumber, |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 520 // We cannot inline a constructor invocation containing type arguments | 507 // We cannot inline a constructor invocation containing type arguments |
| 521 // because CreateInstance in the body does not know the type arguments. | 508 // because CreateInstance in the body does not know the type arguments. |
| 522 // We would incorrectly instantiate a class like A instead of A<B>. | 509 // We would incorrectly instantiate a class like A instead of A<B>. |
| 523 // TODO(kmillikin): try to fix this. | 510 // TODO(kmillikin): try to fix this. |
| 524 GenericType generic = node.dartType; | 511 GenericType generic = node.dartType; |
| 525 if (generic.typeArguments.any((DartType t) => !t.isDynamic)) return null; | 512 if (generic.typeArguments.any((DartType t) => !t.isDynamic)) return null; |
| 526 } | 513 } |
| 527 return tryInlining(node, node.target, null); | 514 return tryInlining(node, node.target, null); |
| 528 } | 515 } |
| 529 } | 516 } |
| OLD | NEW |