| 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 import '../common/resolution.dart'; | |
| 6 import '../common_elements.dart'; | 5 import '../common_elements.dart'; |
| 7 import '../constants/constant_system.dart'; | 6 import '../constants/constant_system.dart'; |
| 8 import '../constants/values.dart'; | 7 import '../constants/values.dart'; |
| 9 import '../elements/elements.dart'; | |
| 10 import '../elements/entities.dart'; | 8 import '../elements/entities.dart'; |
| 11 import '../elements/resolution_types.dart'; | 9 import '../elements/types.dart'; |
| 12 import '../universe/call_structure.dart'; | 10 import '../universe/call_structure.dart'; |
| 13 import '../universe/use.dart' show ConstantUse, StaticUse; | 11 import '../universe/use.dart' show ConstantUse, StaticUse; |
| 14 import '../universe/world_impact.dart' | 12 import '../universe/world_impact.dart' |
| 15 show WorldImpact, StagedWorldImpactBuilder; | 13 show WorldImpact, StagedWorldImpactBuilder; |
| 16 import 'backend_usage.dart' show BackendUsageBuilder; | 14 import 'backend_usage.dart' show BackendUsageBuilder; |
| 17 import 'native_data.dart'; | 15 import 'native_data.dart'; |
| 18 | 16 |
| 19 /** | 17 /** |
| 20 * Support for Custom Elements. | 18 * Support for Custom Elements. |
| 21 * | 19 * |
| (...skipping 26 matching lines...) Expand all Loading... |
| 48 * final tag; | 46 * final tag; |
| 49 * Component(this.tag); | 47 * Component(this.tag); |
| 50 * void register() => document.register(T, tag); | 48 * void register() => document.register(T, tag); |
| 51 * } | 49 * } |
| 52 * const Component<FancyButton>('x-fancy-button').register(); | 50 * const Component<FancyButton>('x-fancy-button').register(); |
| 53 * | 51 * |
| 54 * In these cases we conservatively generate all viable entries in the table. | 52 * In these cases we conservatively generate all viable entries in the table. |
| 55 */ | 53 */ |
| 56 abstract class CustomElementsAnalysisBase { | 54 abstract class CustomElementsAnalysisBase { |
| 57 final NativeBasicData _nativeData; | 55 final NativeBasicData _nativeData; |
| 58 final Resolution _resolution; | 56 final ElementEnvironment _elementEnvironment; |
| 59 final CommonElements _commonElements; | 57 final CommonElements _commonElements; |
| 60 | 58 |
| 61 CustomElementsAnalysisBase( | 59 CustomElementsAnalysisBase( |
| 62 this._resolution, this._commonElements, this._nativeData); | 60 this._elementEnvironment, this._commonElements, this._nativeData); |
| 63 | 61 |
| 64 CustomElementsAnalysisJoin get join; | 62 CustomElementsAnalysisJoin get join; |
| 65 | 63 |
| 66 void registerInstantiatedClass(ClassElement classElement) { | 64 void registerInstantiatedClass(ClassEntity cls) { |
| 67 classElement.ensureResolved(_resolution); | 65 if (!_nativeData.isNativeOrExtendsNative(cls)) return; |
| 68 if (!_nativeData.isNativeOrExtendsNative(classElement)) return; | 66 if (_elementEnvironment.isUnnamedMixinApplication(cls)) return; |
| 69 if (classElement.isMixinApplication) return; | 67 if (cls.isAbstract) return; |
| 70 if (classElement.isAbstract) return; | |
| 71 // JsInterop classes are opaque interfaces without a concrete | 68 // JsInterop classes are opaque interfaces without a concrete |
| 72 // implementation. | 69 // implementation. |
| 73 if (_nativeData.isJsInteropClass(classElement)) return; | 70 if (_nativeData.isJsInteropClass(cls)) return; |
| 74 join.instantiatedClasses.add(classElement); | 71 join.instantiatedClasses.add(cls); |
| 75 } | 72 } |
| 76 | 73 |
| 77 void registerStaticUse(MemberEntity element) { | 74 void registerStaticUse(MemberEntity element) { |
| 78 assert(element != null); | 75 assert(element != null); |
| 79 if (element == _commonElements.findIndexForNativeSubclassType) { | 76 if (element == _commonElements.findIndexForNativeSubclassType) { |
| 80 join.demanded = true; | 77 join.demanded = true; |
| 81 } | 78 } |
| 82 } | 79 } |
| 83 | 80 |
| 84 /// Computes the [WorldImpact] of the classes registered since last flush. | 81 /// Computes the [WorldImpact] of the classes registered since last flush. |
| 85 WorldImpact flush() => join.flush(); | 82 WorldImpact flush() => join.flush(); |
| 86 } | 83 } |
| 87 | 84 |
| 88 class CustomElementsResolutionAnalysis extends CustomElementsAnalysisBase { | 85 class CustomElementsResolutionAnalysis extends CustomElementsAnalysisBase { |
| 89 final CustomElementsAnalysisJoin join; | 86 final CustomElementsAnalysisJoin join; |
| 90 | 87 |
| 91 CustomElementsResolutionAnalysis( | 88 CustomElementsResolutionAnalysis( |
| 92 Resolution resolution, | |
| 93 ConstantSystem constantSystem, | 89 ConstantSystem constantSystem, |
| 90 ElementEnvironment elementEnvironment, |
| 94 CommonElements commonElements, | 91 CommonElements commonElements, |
| 95 NativeBasicData nativeData, | 92 NativeBasicData nativeData, |
| 96 BackendUsageBuilder backendUsageBuilder) | 93 BackendUsageBuilder backendUsageBuilder) |
| 97 : join = new CustomElementsAnalysisJoin( | 94 : join = new CustomElementsAnalysisJoin( |
| 98 resolution, constantSystem, commonElements, nativeData, | 95 constantSystem, elementEnvironment, commonElements, nativeData, |
| 99 backendUsageBuilder: backendUsageBuilder), | 96 backendUsageBuilder: backendUsageBuilder), |
| 100 super(resolution, commonElements, nativeData) { | 97 super(elementEnvironment, commonElements, nativeData) { |
| 101 // TODO(sra): Remove this work-around. We should mark allClassesSelected in | 98 // TODO(sra): Remove this work-around. We should mark allClassesSelected in |
| 102 // both joins only when we see a construct generating an unknown [Type] but | 99 // both joins only when we see a construct generating an unknown [Type] but |
| 103 // we can't currently recognize all cases. In particular, the work-around | 100 // we can't currently recognize all cases. In particular, the work-around |
| 104 // for the unimplemented `ClassMirror.reflectedType` is not recognizable. | 101 // for the unimplemented `ClassMirror.reflectedType` is not recognizable. |
| 105 // TODO(12607): Match on [ClassMirror.reflectedType] | 102 // TODO(12607): Match on [ClassMirror.reflectedType] |
| 106 join.allClassesSelected = true; | 103 join.allClassesSelected = true; |
| 107 } | 104 } |
| 108 | 105 |
| 109 void registerTypeLiteral(ResolutionDartType type) { | 106 void registerTypeLiteral(DartType type) { |
| 110 if (type.isInterfaceType) { | 107 if (type.isInterfaceType) { |
| 111 // TODO(sra): If we had a flow query from the type literal expression to | 108 // TODO(sra): If we had a flow query from the type literal expression to |
| 112 // the Type argument of the metadata lookup, we could tell if this type | 109 // the Type argument of the metadata lookup, we could tell if this type |
| 113 // literal is really a demand for the metadata. | 110 // literal is really a demand for the metadata. |
| 114 join.selectedClasses.add(type.element); | 111 InterfaceType interfaceType = type; |
| 112 join.selectedClasses.add(interfaceType.element); |
| 115 } else if (type.isTypeVariable) { | 113 } else if (type.isTypeVariable) { |
| 116 // This is a type parameter of a parameterized class. | 114 // This is a type parameter of a parameterized class. |
| 117 // TODO(sra): Is there a way to determine which types are bound to the | 115 // TODO(sra): Is there a way to determine which types are bound to the |
| 118 // parameter? | 116 // parameter? |
| 119 join.allClassesSelected = true; | 117 join.allClassesSelected = true; |
| 120 } | 118 } |
| 121 } | 119 } |
| 122 } | 120 } |
| 123 | 121 |
| 124 class CustomElementsCodegenAnalysis extends CustomElementsAnalysisBase { | 122 class CustomElementsCodegenAnalysis extends CustomElementsAnalysisBase { |
| 125 final CustomElementsAnalysisJoin join; | 123 final CustomElementsAnalysisJoin join; |
| 126 | 124 |
| 127 CustomElementsCodegenAnalysis( | 125 CustomElementsCodegenAnalysis( |
| 128 Resolution resolution, | |
| 129 ConstantSystem constantSystem, | 126 ConstantSystem constantSystem, |
| 130 CommonElements commonElements, | 127 CommonElements commonElements, |
| 128 ElementEnvironment elementEnvironment, |
| 131 NativeBasicData nativeData) | 129 NativeBasicData nativeData) |
| 132 : join = new CustomElementsAnalysisJoin( | 130 : join = new CustomElementsAnalysisJoin( |
| 133 resolution, constantSystem, commonElements, nativeData), | 131 constantSystem, elementEnvironment, commonElements, nativeData), |
| 134 super(resolution, commonElements, nativeData) { | 132 super(elementEnvironment, commonElements, nativeData) { |
| 135 // TODO(sra): Remove this work-around. We should mark allClassesSelected in | 133 // TODO(sra): Remove this work-around. We should mark allClassesSelected in |
| 136 // both joins only when we see a construct generating an unknown [Type] but | 134 // both joins only when we see a construct generating an unknown [Type] but |
| 137 // we can't currently recognize all cases. In particular, the work-around | 135 // we can't currently recognize all cases. In particular, the work-around |
| 138 // for the unimplemented `ClassMirror.reflectedType` is not recognizable. | 136 // for the unimplemented `ClassMirror.reflectedType` is not recognizable. |
| 139 // TODO(12607): Match on [ClassMirror.reflectedType] | 137 // TODO(12607): Match on [ClassMirror.reflectedType] |
| 140 join.allClassesSelected = true; | 138 join.allClassesSelected = true; |
| 141 } | 139 } |
| 142 | 140 |
| 143 void registerTypeConstant(ClassElement element) { | 141 void registerTypeConstant(ClassEntity cls) { |
| 144 assert(element.isClass); | 142 join.selectedClasses.add(cls); |
| 145 join.selectedClasses.add(element); | |
| 146 } | 143 } |
| 147 | 144 |
| 148 bool get needsTable => join.demanded; | 145 bool get needsTable => join.demanded; |
| 149 | 146 |
| 150 bool needsClass(ClassElement classElement) => | 147 bool needsClass(ClassEntity cls) => join.activeClasses.contains(cls); |
| 151 join.activeClasses.contains(classElement); | |
| 152 | 148 |
| 153 List<ConstructorElement> constructors(ClassElement classElement) => | 149 List<ConstructorEntity> constructors(ClassEntity cls) => |
| 154 join.computeEscapingConstructors(classElement); | 150 join.computeEscapingConstructors(cls); |
| 155 } | 151 } |
| 156 | 152 |
| 157 class CustomElementsAnalysisJoin { | 153 class CustomElementsAnalysisJoin { |
| 158 final Resolution _resolution; | |
| 159 final ConstantSystem _constantSystem; | 154 final ConstantSystem _constantSystem; |
| 155 final ElementEnvironment _elementEnvironment; |
| 160 final CommonElements _commonElements; | 156 final CommonElements _commonElements; |
| 161 final NativeBasicData _nativeData; | 157 final NativeBasicData _nativeData; |
| 162 final BackendUsageBuilder _backendUsageBuilder; | 158 final BackendUsageBuilder _backendUsageBuilder; |
| 163 | 159 |
| 164 final bool forResolution; | 160 final bool forResolution; |
| 165 | 161 |
| 166 final StagedWorldImpactBuilder impactBuilder = new StagedWorldImpactBuilder(); | 162 final StagedWorldImpactBuilder impactBuilder = new StagedWorldImpactBuilder(); |
| 167 | 163 |
| 168 // Classes that are candidates for needing constructors. Classes are moved to | 164 // Classes that are candidates for needing constructors. Classes are moved to |
| 169 // [activeClasses] when we know they need constructors. | 165 // [activeClasses] when we know they need constructors. |
| 170 final instantiatedClasses = new Set<ClassElement>(); | 166 final Set<ClassEntity> instantiatedClasses = new Set<ClassEntity>(); |
| 171 | 167 |
| 172 // Classes explicitly named. | 168 // Classes explicitly named. |
| 173 final selectedClasses = new Set<ClassElement>(); | 169 final Set<ClassEntity> selectedClasses = new Set<ClassEntity>(); |
| 174 | 170 |
| 175 // True if we must conservatively include all extension classes. | 171 // True if we must conservatively include all extension classes. |
| 176 bool allClassesSelected = false; | 172 bool allClassesSelected = false; |
| 177 | 173 |
| 178 // Did we see a demand for the data? | 174 // Did we see a demand for the data? |
| 179 bool demanded = false; | 175 bool demanded = false; |
| 180 | 176 |
| 181 // ClassesOutput: classes requiring metadata. | 177 // ClassesOutput: classes requiring metadata. |
| 182 final activeClasses = new Set<ClassElement>(); | 178 final Set<ClassEntity> activeClasses = new Set<ClassEntity>(); |
| 183 | 179 |
| 184 CustomElementsAnalysisJoin(this._resolution, this._constantSystem, | 180 CustomElementsAnalysisJoin(this._constantSystem, this._elementEnvironment, |
| 185 this._commonElements, this._nativeData, | 181 this._commonElements, this._nativeData, |
| 186 {BackendUsageBuilder backendUsageBuilder}) | 182 {BackendUsageBuilder backendUsageBuilder}) |
| 187 : this._backendUsageBuilder = backendUsageBuilder, | 183 : this._backendUsageBuilder = backendUsageBuilder, |
| 188 this.forResolution = backendUsageBuilder != null; | 184 this.forResolution = backendUsageBuilder != null; |
| 189 | 185 |
| 190 WorldImpact flush() { | 186 WorldImpact flush() { |
| 191 if (!demanded) return const WorldImpact(); | 187 if (!demanded) return const WorldImpact(); |
| 192 var newActiveClasses = new Set<ClassElement>(); | 188 var newActiveClasses = new Set<ClassEntity>(); |
| 193 for (ClassElement classElement in instantiatedClasses) { | 189 for (ClassEntity cls in instantiatedClasses) { |
| 194 bool isNative = _nativeData.isNativeClass(classElement); | 190 bool isNative = _nativeData.isNativeClass(cls); |
| 195 bool isExtension = | 191 bool isExtension = !isNative && _nativeData.isNativeOrExtendsNative(cls); |
| 196 !isNative && _nativeData.isNativeOrExtendsNative(classElement); | |
| 197 // Generate table entries for native classes that are explicitly named and | 192 // Generate table entries for native classes that are explicitly named and |
| 198 // extensions that fix our criteria. | 193 // extensions that fix our criteria. |
| 199 if ((isNative && selectedClasses.contains(classElement)) || | 194 if ((isNative && selectedClasses.contains(cls)) || |
| 200 (isExtension && | 195 (isExtension && |
| 201 (allClassesSelected || selectedClasses.contains(classElement)))) { | 196 (allClassesSelected || selectedClasses.contains(cls)))) { |
| 202 newActiveClasses.add(classElement); | 197 newActiveClasses.add(cls); |
| 203 Iterable<ConstructorElement> escapingConstructors = | 198 Iterable<ConstructorEntity> escapingConstructors = |
| 204 computeEscapingConstructors(classElement); | 199 computeEscapingConstructors(cls); |
| 205 for (ConstructorElement constructor in escapingConstructors) { | 200 for (ConstructorEntity constructor in escapingConstructors) { |
| 206 impactBuilder.registerStaticUse(new StaticUse.constructorInvoke( | 201 impactBuilder.registerStaticUse(new StaticUse.constructorInvoke( |
| 207 constructor, CallStructure.NO_ARGS)); | 202 constructor, CallStructure.NO_ARGS)); |
| 208 } | 203 } |
| 209 if (forResolution) { | 204 if (forResolution) { |
| 210 escapingConstructors | 205 escapingConstructors |
| 211 .forEach(_backendUsageBuilder.registerGlobalFunctionDependency); | 206 .forEach(_backendUsageBuilder.registerGlobalFunctionDependency); |
| 212 } | 207 } |
| 213 // Force the generaton of the type constant that is the key to an entry | 208 // Force the generaton of the type constant that is the key to an entry |
| 214 // in the generated table. | 209 // in the generated table. |
| 215 ConstantValue constant = _makeTypeConstant(classElement); | 210 ConstantValue constant = _makeTypeConstant(cls); |
| 216 impactBuilder | 211 impactBuilder |
| 217 .registerConstantUse(new ConstantUse.customElements(constant)); | 212 .registerConstantUse(new ConstantUse.customElements(constant)); |
| 218 } | 213 } |
| 219 } | 214 } |
| 220 activeClasses.addAll(newActiveClasses); | 215 activeClasses.addAll(newActiveClasses); |
| 221 instantiatedClasses.removeAll(newActiveClasses); | 216 instantiatedClasses.removeAll(newActiveClasses); |
| 222 return impactBuilder.flush(); | 217 return impactBuilder.flush(); |
| 223 } | 218 } |
| 224 | 219 |
| 225 TypeConstantValue _makeTypeConstant(ClassElement element) { | 220 TypeConstantValue _makeTypeConstant(ClassEntity cls) { |
| 226 ResolutionDartType elementType = element.rawType; | 221 DartType type = _elementEnvironment.getRawType(cls); |
| 227 return _constantSystem.createType(_commonElements, elementType); | 222 return _constantSystem.createType(_commonElements, type); |
| 228 } | 223 } |
| 229 | 224 |
| 230 List<ConstructorElement> computeEscapingConstructors( | 225 List<ConstructorEntity> computeEscapingConstructors(ClassEntity cls) { |
| 231 ClassElement classElement) { | 226 List<ConstructorEntity> result = <ConstructorEntity>[]; |
| 232 List<ConstructorElement> result = <ConstructorElement>[]; | |
| 233 // Only classes that extend native classes have constructors in the table. | 227 // Only classes that extend native classes have constructors in the table. |
| 234 // We could refine this to classes that extend Element, but that would break | 228 // We could refine this to classes that extend Element, but that would break |
| 235 // the tests and there is no sane reason to subclass other native classes. | 229 // the tests and there is no sane reason to subclass other native classes. |
| 236 if (_nativeData.isNativeClass(classElement)) return result; | 230 if (_nativeData.isNativeClass(cls)) return result; |
| 237 | 231 |
| 238 void selectGenerativeConstructors(ClassElement enclosing, Element member) { | 232 _elementEnvironment.forEachConstructor(cls, |
| 239 if (member.isGenerativeConstructor) { | 233 (ConstructorEntity constructor) { |
| 234 if (constructor.isGenerativeConstructor) { |
| 235 // Ensure that parameter structure has been computed by querying the |
| 236 // function type. |
| 237 _elementEnvironment.getFunctionType(constructor); |
| 240 // Ignore constructors that cannot be called with zero arguments. | 238 // Ignore constructors that cannot be called with zero arguments. |
| 241 ConstructorElement constructor = member; | 239 if (constructor.parameterStructure.requiredParameters == 0) { |
| 242 constructor.computeType(_resolution); | 240 result.add(constructor); |
| 243 FunctionSignature parameters = constructor.functionSignature; | |
| 244 if (parameters.requiredParameterCount == 0) { | |
| 245 result.add(member); | |
| 246 } | 241 } |
| 247 } | 242 } |
| 248 } | 243 }); |
| 249 | |
| 250 classElement.forEachMember(selectGenerativeConstructors, | |
| 251 includeBackendMembers: false, includeSuperAndInjectedMembers: false); | |
| 252 return result; | 244 return result; |
| 253 } | 245 } |
| 254 } | 246 } |
| OLD | NEW |