| 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 library compiler.src.inferrer.closure_tracer; | 5 library compiler.src.inferrer.closure_tracer; |
| 6 | 6 |
| 7 import '../common/names.dart' show Names; | 7 import '../common/names.dart' show Names; |
| 8 import '../elements/elements.dart'; | 8 import '../elements/elements.dart'; |
| 9 import '../elements/entities.dart'; |
| 9 import '../js_backend/backend.dart' show JavaScriptBackend; | 10 import '../js_backend/backend.dart' show JavaScriptBackend; |
| 10 import '../types/types.dart' show TypeMask; | 11 import '../types/types.dart' show TypeMask; |
| 11 import '../universe/selector.dart' show Selector; | 12 import '../universe/selector.dart' show Selector; |
| 12 import 'debug.dart' as debug; | 13 import 'debug.dart' as debug; |
| 13 import 'inferrer_engine.dart'; | 14 import 'inferrer_engine.dart'; |
| 14 import 'node_tracer.dart'; | 15 import 'node_tracer.dart'; |
| 15 import 'type_graph_nodes.dart'; | 16 import 'type_graph_nodes.dart'; |
| 16 | 17 |
| 17 class ClosureTracerVisitor extends TracerVisitor { | 18 class ClosureTracerVisitor extends TracerVisitor { |
| 18 final Iterable<MethodElement> tracedElements; | 19 final Iterable<FunctionEntity> tracedElements; |
| 19 final List<CallSiteTypeInformation> _callsToAnalyze = | 20 final List<CallSiteTypeInformation> _callsToAnalyze = |
| 20 new List<CallSiteTypeInformation>(); | 21 new List<CallSiteTypeInformation>(); |
| 21 | 22 |
| 22 ClosureTracerVisitor(this.tracedElements, ApplyableTypeInformation tracedType, | 23 ClosureTracerVisitor(this.tracedElements, ApplyableTypeInformation tracedType, |
| 23 InferrerEngine inferrer) | 24 InferrerEngine inferrer) |
| 24 : super(tracedType, inferrer); | 25 : super(tracedType, inferrer); |
| 25 | 26 |
| 26 ApplyableTypeInformation get tracedType => super.tracedType; | 27 ApplyableTypeInformation get tracedType => super.tracedType; |
| 27 | 28 |
| 28 void run() { | 29 void run() { |
| 29 analyze(); | 30 analyze(); |
| 30 if (!continueAnalyzing) return; | 31 if (!continueAnalyzing) return; |
| 31 _callsToAnalyze.forEach(_analyzeCall); | 32 _callsToAnalyze.forEach(_analyzeCall); |
| 32 for (MethodElement e in tracedElements) { | 33 for (MethodElement element in tracedElements) { |
| 33 e.functionSignature.forEachParameter((Element parameter) { | 34 MethodElement implementation = element.implementation; |
| 35 implementation.functionSignature.forEachParameter((Element parameter) { |
| 34 ElementTypeInformation info = | 36 ElementTypeInformation info = |
| 35 inferrer.types.getInferredTypeOfParameter(parameter); | 37 inferrer.types.getInferredTypeOfParameter(parameter); |
| 36 info.disableInferenceForClosures = false; | 38 info.disableInferenceForClosures = false; |
| 37 }); | 39 }); |
| 38 } | 40 } |
| 39 } | 41 } |
| 40 | 42 |
| 41 void _tagAsFunctionApplyTarget([String reason]) { | 43 void _tagAsFunctionApplyTarget([String reason]) { |
| 42 tracedType.mightBePassedToFunctionApply = true; | 44 tracedType.mightBePassedToFunctionApply = true; |
| 43 if (debug.VERBOSE) { | 45 if (debug.VERBOSE) { |
| 44 print("Closure $tracedType might be passed to apply: $reason"); | 46 print("Closure $tracedType might be passed to apply: $reason"); |
| 45 } | 47 } |
| 46 } | 48 } |
| 47 | 49 |
| 48 void _registerCallForLaterAnalysis(CallSiteTypeInformation info) { | 50 void _registerCallForLaterAnalysis(CallSiteTypeInformation info) { |
| 49 _callsToAnalyze.add(info); | 51 _callsToAnalyze.add(info); |
| 50 } | 52 } |
| 51 | 53 |
| 52 void _analyzeCall(CallSiteTypeInformation info) { | 54 void _analyzeCall(CallSiteTypeInformation info) { |
| 53 Selector selector = info.selector; | 55 Selector selector = info.selector; |
| 54 TypeMask mask = info.mask; | 56 TypeMask mask = info.mask; |
| 55 tracedElements.forEach((MethodElement functionElement) { | 57 tracedElements.forEach((FunctionEntity functionElement) { |
| 56 if (!selector.callStructure | 58 if (!selector.callStructure |
| 57 .signatureApplies(functionElement.parameterStructure)) { | 59 .signatureApplies(functionElement.parameterStructure)) { |
| 58 return; | 60 return; |
| 59 } | 61 } |
| 60 inferrer.updateParameterAssignments( | 62 inferrer.updateParameterAssignments( |
| 61 info, functionElement, info.arguments, selector, mask, | 63 info, functionElement, info.arguments, selector, mask, |
| 62 remove: false, addToQueue: false); | 64 remove: false, addToQueue: false); |
| 63 }); | 65 }); |
| 64 } | 66 } |
| 65 | 67 |
| 66 @override | 68 @override |
| 67 visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) { | 69 visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) { |
| 68 super.visitClosureCallSiteTypeInformation(info); | 70 super.visitClosureCallSiteTypeInformation(info); |
| 69 if (info.closure == currentUser) { | 71 if (info.closure == currentUser) { |
| 70 _registerCallForLaterAnalysis(info); | 72 _registerCallForLaterAnalysis(info); |
| 71 } else { | 73 } else { |
| 72 bailout('Passed to a closure'); | 74 bailout('Passed to a closure'); |
| 73 } | 75 } |
| 74 } | 76 } |
| 75 | 77 |
| 76 @override | 78 @override |
| 77 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) { | 79 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) { |
| 78 super.visitStaticCallSiteTypeInformation(info); | 80 super.visitStaticCallSiteTypeInformation(info); |
| 79 Element called = info.calledElement; | 81 MemberEntity called = info.calledElement; |
| 80 if (compiler.backend | 82 if (inferrer.closedWorld.commonElements.isForeign(called)) { |
| 81 .isForeign(inferrer.closedWorld.commonElements, called)) { | |
| 82 String name = called.name; | 83 String name = called.name; |
| 83 if (name == JavaScriptBackend.JS || name == 'DART_CLOSURE_TO_JS') { | 84 if (name == JavaScriptBackend.JS || name == 'DART_CLOSURE_TO_JS') { |
| 84 bailout('Used in JS ${info.call}'); | 85 bailout('Used in JS ${info.call}'); |
| 85 } | 86 } |
| 86 } | 87 } |
| 87 if (called.isGetter && | 88 if (called.isGetter && |
| 88 info.selector != null && | 89 info.selector != null && |
| 89 info.selector.isCall && | 90 info.selector.isCall && |
| 90 inferrer.types.getInferredTypeOfMember(called) == currentUser) { | 91 inferrer.types.getInferredTypeOfMember(called) == currentUser) { |
| 91 // This node can be a closure call as well. For example, `foo()` | 92 // This node can be a closure call as well. For example, `foo()` |
| 92 // where `foo` is a getter. | 93 // where `foo` is a getter. |
| 93 _registerCallForLaterAnalysis(info); | 94 _registerCallForLaterAnalysis(info); |
| 94 } | 95 } |
| 95 if (called is MemberElement && | 96 if (_checkIfFunctionApply(called) && |
| 96 _checkIfFunctionApply(called) && | |
| 97 info.arguments != null && | 97 info.arguments != null && |
| 98 info.arguments.contains(currentUser)) { | 98 info.arguments.contains(currentUser)) { |
| 99 _tagAsFunctionApplyTarget("static call"); | 99 _tagAsFunctionApplyTarget("static call"); |
| 100 } | 100 } |
| 101 } | 101 } |
| 102 | 102 |
| 103 bool _checkIfCurrentUser(MemberElement element) => | 103 bool _checkIfCurrentUser(MemberEntity element) => |
| 104 inferrer.types.getInferredTypeOfMember(element) == currentUser; | 104 inferrer.types.getInferredTypeOfMember(element) == currentUser; |
| 105 | 105 |
| 106 bool _checkIfFunctionApply(MemberElement element) { | 106 bool _checkIfFunctionApply(MemberEntity element) { |
| 107 return inferrer.closedWorld.commonElements.isFunctionApplyMethod(element); | 107 return inferrer.closedWorld.commonElements.isFunctionApplyMethod(element); |
| 108 } | 108 } |
| 109 | 109 |
| 110 @override | 110 @override |
| 111 visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) { | 111 visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) { |
| 112 super.visitDynamicCallSiteTypeInformation(info); | 112 super.visitDynamicCallSiteTypeInformation(info); |
| 113 if (info.selector.isCall) { | 113 if (info.selector.isCall) { |
| 114 if (info.arguments.contains(currentUser)) { | 114 if (info.arguments.contains(currentUser)) { |
| 115 if (!info.targets.every((element) => element.isFunction)) { | 115 if (!info.targets.every((element) => element.isFunction)) { |
| 116 bailout('Passed to a closure'); | 116 bailout('Passed to a closure'); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 137 @override | 137 @override |
| 138 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) { | 138 visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) { |
| 139 super.visitStaticCallSiteTypeInformation(info); | 139 super.visitStaticCallSiteTypeInformation(info); |
| 140 if (info.calledElement == tracedElements.first && | 140 if (info.calledElement == tracedElements.first && |
| 141 info.selector != null && | 141 info.selector != null && |
| 142 info.selector.isGetter) { | 142 info.selector.isGetter) { |
| 143 addNewEscapeInformation(info); | 143 addNewEscapeInformation(info); |
| 144 } | 144 } |
| 145 } | 145 } |
| 146 } | 146 } |
| OLD | NEW |