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