| 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 part of type_graph_inferrer; | 5 library compiler.src.inferrer.closure_tracer; |
| 6 |
| 7 import '../types/types.dart' show TypeMask; |
| 8 import '../common/names.dart' show Names; |
| 9 import '../elements/elements.dart'; |
| 10 import '../universe/selector.dart' show Selector; |
| 11 import 'node_tracer.dart'; |
| 12 import 'type_graph_nodes.dart'; |
| 13 import 'debug.dart' as debug; |
| 14 |
| 6 | 15 |
| 7 class ClosureTracerVisitor extends TracerVisitor<ApplyableTypeInformation> { | 16 class ClosureTracerVisitor extends TracerVisitor<ApplyableTypeInformation> { |
| 8 final Iterable<FunctionElement> tracedElements; | 17 final Iterable<FunctionElement> tracedElements; |
| 9 final List<CallSiteTypeInformation> callsToAnalyze = | 18 final List<CallSiteTypeInformation> _callsToAnalyze = |
| 10 new List<CallSiteTypeInformation>(); | 19 new List<CallSiteTypeInformation>(); |
| 11 | 20 |
| 12 ClosureTracerVisitor(this.tracedElements, tracedType, inferrer) | 21 ClosureTracerVisitor(this.tracedElements, tracedType, inferrer) |
| 13 : super(tracedType, inferrer); | 22 : super(tracedType, inferrer); |
| 14 | 23 |
| 15 void run() { | 24 void run() { |
| 16 analyze(); | 25 analyze(); |
| 17 if (!continueAnalyzing) return; | 26 if (!continueAnalyzing) return; |
| 18 callsToAnalyze.forEach(analyzeCall); | 27 _callsToAnalyze.forEach(_analyzeCall); |
| 19 for(FunctionElement e in tracedElements) { | 28 for(FunctionElement e in tracedElements) { |
| 20 e.functionSignature.forEachParameter((Element parameter) { | 29 e.functionSignature.forEachParameter((Element parameter) { |
| 21 ElementTypeInformation info = | 30 ElementTypeInformation info = |
| 22 inferrer.types.getInferredTypeOf(parameter); | 31 inferrer.types.getInferredTypeOf(parameter); |
| 23 info.disableInferenceForClosures = false; | 32 info.disableInferenceForClosures = false; |
| 24 }); | 33 }); |
| 25 } | 34 } |
| 26 } | 35 } |
| 27 | 36 |
| 28 void tagAsFunctionApplyTarget([String reason]) { | 37 void _tagAsFunctionApplyTarget([String reason]) { |
| 29 tracedType.mightBePassedToFunctionApply = true; | 38 tracedType.mightBePassedToFunctionApply = true; |
| 30 if (_VERBOSE) { | 39 if (debug.VERBOSE) { |
| 31 print("Closure $tracedType might be passed to apply: $reason"); | 40 print("Closure $tracedType might be passed to apply: $reason"); |
| 32 } | 41 } |
| 33 } | 42 } |
| 34 | 43 |
| 35 void registerCallForLaterAnalysis(CallSiteTypeInformation info) { | 44 void _registerCallForLaterAnalysis(CallSiteTypeInformation info) { |
| 36 callsToAnalyze.add(info); | 45 _callsToAnalyze.add(info); |
| 37 } | 46 } |
| 38 | 47 |
| 39 void analyzeCall(CallSiteTypeInformation info) { | 48 void _analyzeCall(CallSiteTypeInformation info) { |
| 40 Selector selector = info.selector; | 49 Selector selector = info.selector; |
| 41 TypeMask mask = info.mask; | 50 TypeMask mask = info.mask; |
| 42 tracedElements.forEach((FunctionElement functionElement) { | 51 tracedElements.forEach((FunctionElement functionElement) { |
| 43 if (!selector.signatureApplies(functionElement)) return; | 52 if (!selector.signatureApplies(functionElement)) return; |
| 44 inferrer.updateParameterAssignments(info, functionElement, info.arguments, | 53 inferrer.updateParameterAssignments(info, functionElement, info.arguments, |
| 45 selector, mask, remove: false, addToQueue: false); | 54 selector, mask, remove: false, addToQueue: false); |
| 46 }); | 55 }); |
| 47 } | 56 } |
| 48 | 57 |
| 58 @override |
| 49 visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) { | 59 visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) { |
| 50 super.visitClosureCallSiteTypeInformation(info); | 60 super.visitClosureCallSiteTypeInformation(info); |
| 51 if (info.closure == currentUser) { | 61 if (info.closure == currentUser) { |
| 52 registerCallForLaterAnalysis(info); | 62 _registerCallForLaterAnalysis(info); |
| 53 } else { | 63 } else { |
| 54 bailout('Passed to a closure'); | 64 bailout('Passed to a closure'); |
| 55 } | 65 } |
| 56 } | 66 } |
| 57 | 67 |
| 68 @override |
| 58 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) { | 69 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) { |
| 59 super.visitStaticCallSiteTypeInformation(info); | 70 super.visitStaticCallSiteTypeInformation(info); |
| 60 Element called = info.calledElement; | 71 Element called = info.calledElement; |
| 61 if (compiler.backend.isForeign(called)) { | 72 if (compiler.backend.isForeign(called)) { |
| 62 String name = called.name; | 73 String name = called.name; |
| 63 if (name == 'JS' || name == 'DART_CLOSURE_TO_JS') { | 74 if (name == 'JS' || name == 'DART_CLOSURE_TO_JS') { |
| 64 bailout('Used in JS ${info.call}'); | 75 bailout('Used in JS ${info.call}'); |
| 65 } | 76 } |
| 66 } | 77 } |
| 67 if (called.isGetter | 78 if (called.isGetter |
| 68 && info.selector != null | 79 && info.selector != null |
| 69 && info.selector.isCall | 80 && info.selector.isCall |
| 70 && inferrer.types.getInferredTypeOf(called) == currentUser) { | 81 && inferrer.types.getInferredTypeOf(called) == currentUser) { |
| 71 // This node can be a closure call as well. For example, `foo()` | 82 // This node can be a closure call as well. For example, `foo()` |
| 72 // where `foo` is a getter. | 83 // where `foo` is a getter. |
| 73 registerCallForLaterAnalysis(info); | 84 _registerCallForLaterAnalysis(info); |
| 74 } | 85 } |
| 75 if (checkIfFunctionApply(called) && | 86 if (_checkIfFunctionApply(called) && |
| 76 info.arguments != null && | 87 info.arguments != null && |
| 77 info.arguments.contains(currentUser)) { | 88 info.arguments.contains(currentUser)) { |
| 78 tagAsFunctionApplyTarget("static call"); | 89 _tagAsFunctionApplyTarget("static call"); |
| 79 } | 90 } |
| 80 } | 91 } |
| 81 | 92 |
| 82 bool checkIfCurrentUser(element) { | 93 bool _checkIfCurrentUser(element) => |
| 83 return inferrer.types.getInferredTypeOf(element) == currentUser; | 94 inferrer.types.getInferredTypeOf(element) == currentUser; |
| 84 } | |
| 85 | 95 |
| 86 bool checkIfFunctionApply(element) { | 96 bool _checkIfFunctionApply(element) => |
| 87 return compiler.functionApplyMethod == element; | 97 compiler.functionApplyMethod == element; |
| 88 } | |
| 89 | 98 |
| 99 @override |
| 90 visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) { | 100 visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) { |
| 91 super.visitDynamicCallSiteTypeInformation(info); | 101 super.visitDynamicCallSiteTypeInformation(info); |
| 92 if (info.selector.isCall) { | 102 if (info.selector.isCall) { |
| 93 if (info.arguments.contains(currentUser)) { | 103 if (info.arguments.contains(currentUser)) { |
| 94 if (!info.targets.every((element) => element.isFunction)) { | 104 if (!info.targets.every((element) => element.isFunction)) { |
| 95 bailout('Passed to a closure'); | 105 bailout('Passed to a closure'); |
| 96 } | 106 } |
| 97 if (info.targets.any(checkIfFunctionApply)) { | 107 if (info.targets.any(_checkIfFunctionApply)) { |
| 98 tagAsFunctionApplyTarget("dynamic call"); | 108 _tagAsFunctionApplyTarget("dynamic call"); |
| 99 } | 109 } |
| 100 } else if (info.targets.any((element) => checkIfCurrentUser(element))) { | 110 } else if (info.targets.any((element) => _checkIfCurrentUser(element))) { |
| 101 registerCallForLaterAnalysis(info); | 111 _registerCallForLaterAnalysis(info); |
| 102 } | 112 } |
| 103 } else if (info.selector.isGetter && | 113 } else if (info.selector.isGetter && |
| 104 info.selector.memberName == Names.call) { | 114 info.selector.memberName == Names.call) { |
| 105 // We are potentially tearing off ourself here | 115 // We are potentially tearing off ourself here |
| 106 addNewEscapeInformation(info); | 116 addNewEscapeInformation(info); |
| 107 } | 117 } |
| 108 } | 118 } |
| 109 } | 119 } |
| 110 | 120 |
| 111 class StaticTearOffClosureTracerVisitor extends ClosureTracerVisitor { | 121 class StaticTearOffClosureTracerVisitor extends ClosureTracerVisitor { |
| 112 StaticTearOffClosureTracerVisitor(tracedElement, tracedType, inferrer) | 122 StaticTearOffClosureTracerVisitor(tracedElement, tracedType, inferrer) |
| 113 : super([tracedElement], tracedType, inferrer); | 123 : super([tracedElement], tracedType, inferrer); |
| 114 | 124 |
| 125 @override |
| 115 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) { | 126 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) { |
| 116 super.visitStaticCallSiteTypeInformation(info); | 127 super.visitStaticCallSiteTypeInformation(info); |
| 117 if (info.calledElement == tracedElements.first | 128 if (info.calledElement == tracedElements.first |
| 118 && info.selector != null | 129 && info.selector != null |
| 119 && info.selector.isGetter) { | 130 && info.selector.isGetter) { |
| 120 addNewEscapeInformation(info); | 131 addNewEscapeInformation(info); |
| 121 } | 132 } |
| 122 } | 133 } |
| 123 } | 134 } |
| OLD | NEW |