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