| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 dart2js.js_emitter.program_builder; | 5 part of dart2js.js_emitter.program_builder; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * Generates the code for all used classes in the program. Static fields (even | 8 * Generates the code for all used classes in the program. Static fields (even |
| 9 * in classes) are ignored, since they can be treated as non-class elements. | 9 * in classes) are ignored, since they can be treated as non-class elements. |
| 10 * | 10 * |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 69 if (backend.isTreeShakingDisabled) return (ClassElement cls) => true; | 69 if (backend.isTreeShakingDisabled) return (ClassElement cls) => true; |
| 70 | 70 |
| 71 Set<ClassElement> unneededClasses = new Set<ClassElement>(); | 71 Set<ClassElement> unneededClasses = new Set<ClassElement>(); |
| 72 // The [Bool] class is not marked as abstract, but has a factory | 72 // The [Bool] class is not marked as abstract, but has a factory |
| 73 // constructor that always throws. We never need to emit it. | 73 // constructor that always throws. We never need to emit it. |
| 74 unneededClasses.add(coreClasses.boolClass); | 74 unneededClasses.add(coreClasses.boolClass); |
| 75 | 75 |
| 76 // Go over specialized interceptors and then constants to know which | 76 // Go over specialized interceptors and then constants to know which |
| 77 // interceptors are needed. | 77 // interceptors are needed. |
| 78 Set<ClassElement> needed = new Set<ClassElement>(); | 78 Set<ClassElement> needed = new Set<ClassElement>(); |
| 79 backend.specializedGetInterceptors.forEach( | 79 backend.specializedGetInterceptors |
| 80 (_, Iterable<ClassElement> elements) { | 80 .forEach((_, Iterable<ClassElement> elements) { |
| 81 needed.addAll(elements); | 81 needed.addAll(elements); |
| 82 } | 82 }); |
| 83 ); | |
| 84 | 83 |
| 85 // Add interceptors referenced by constants. | 84 // Add interceptors referenced by constants. |
| 86 needed.addAll(computeInterceptorsReferencedFromConstants()); | 85 needed.addAll(computeInterceptorsReferencedFromConstants()); |
| 87 | 86 |
| 88 // Add unneeded interceptors to the [unneededClasses] set. | 87 // Add unneeded interceptors to the [unneededClasses] set. |
| 89 for (ClassElement interceptor in backend.interceptedClasses) { | 88 for (ClassElement interceptor in backend.interceptedClasses) { |
| 90 if (!needed.contains(interceptor) | 89 if (!needed.contains(interceptor) && |
| 91 && interceptor != coreClasses.objectClass) { | 90 interceptor != coreClasses.objectClass) { |
| 92 unneededClasses.add(interceptor); | 91 unneededClasses.add(interceptor); |
| 93 } | 92 } |
| 94 } | 93 } |
| 95 | 94 |
| 96 // These classes are just helpers for the backend's type system. | 95 // These classes are just helpers for the backend's type system. |
| 97 unneededClasses.add(helpers.jsMutableArrayClass); | 96 unneededClasses.add(helpers.jsMutableArrayClass); |
| 98 unneededClasses.add(helpers.jsFixedArrayClass); | 97 unneededClasses.add(helpers.jsFixedArrayClass); |
| 99 unneededClasses.add(helpers.jsExtendableArrayClass); | 98 unneededClasses.add(helpers.jsExtendableArrayClass); |
| 100 unneededClasses.add(helpers.jsUInt32Class); | 99 unneededClasses.add(helpers.jsUInt32Class); |
| 101 unneededClasses.add(helpers.jsUInt31Class); | 100 unneededClasses.add(helpers.jsUInt31Class); |
| 102 unneededClasses.add(helpers.jsPositiveIntClass); | 101 unneededClasses.add(helpers.jsPositiveIntClass); |
| 103 | 102 |
| 104 return (ClassElement cls) => !unneededClasses.contains(cls); | 103 return (ClassElement cls) => !unneededClasses.contains(cls); |
| 105 } | 104 } |
| 106 | 105 |
| 107 /** | 106 /** |
| 108 * Compute all the constants that must be emitted. | 107 * Compute all the constants that must be emitted. |
| 109 */ | 108 */ |
| 110 void computeNeededConstants() { | 109 void computeNeededConstants() { |
| 111 // Make sure we retain all metadata of all elements. This could add new | 110 // Make sure we retain all metadata of all elements. This could add new |
| 112 // constants to the handler. | 111 // constants to the handler. |
| 113 if (backend.mustRetainMetadata) { | 112 if (backend.mustRetainMetadata) { |
| 114 // TODO(floitsch): verify that we don't run through the same elements | 113 // TODO(floitsch): verify that we don't run through the same elements |
| 115 // multiple times. | 114 // multiple times. |
| 116 for (Element element in backend.generatedCode.keys) { | 115 for (Element element in backend.generatedCode.keys) { |
| 117 if (backend.isAccessibleByReflection(element)) { | 116 if (backend.isAccessibleByReflection(element)) { |
| 118 bool shouldRetainMetadata = backend.retainMetadataOf(element); | 117 bool shouldRetainMetadata = backend.retainMetadataOf(element); |
| 119 if (shouldRetainMetadata && | 118 if (shouldRetainMetadata && |
| 120 (element.isFunction || element.isConstructor || | 119 (element.isFunction || |
| 121 element.isSetter)) { | 120 element.isConstructor || |
| 121 element.isSetter)) { |
| 122 FunctionElement function = element; | 122 FunctionElement function = element; |
| 123 function.functionSignature.forEachParameter( | 123 function.functionSignature |
| 124 backend.retainMetadataOf); | 124 .forEachParameter(backend.retainMetadataOf); |
| 125 } | 125 } |
| 126 } | 126 } |
| 127 } | 127 } |
| 128 for (ClassElement cls in neededClasses) { | 128 for (ClassElement cls in neededClasses) { |
| 129 final onlyForRti = classesOnlyNeededForRti.contains(cls); | 129 final onlyForRti = classesOnlyNeededForRti.contains(cls); |
| 130 if (!onlyForRti) { | 130 if (!onlyForRti) { |
| 131 backend.retainMetadataOf(cls); | 131 backend.retainMetadataOf(cls); |
| 132 new FieldVisitor(compiler, namer).visitFields(cls, false, | 132 new FieldVisitor(compiler, namer).visitFields(cls, false, |
| 133 (Element member, | 133 (Element member, js.Name name, js.Name accessorName, |
| 134 js.Name name, | 134 bool needsGetter, bool needsSetter, bool needsCheckedSetter) { |
| 135 js.Name accessorName, | |
| 136 bool needsGetter, | |
| 137 bool needsSetter, | |
| 138 bool needsCheckedSetter) { | |
| 139 bool needsAccessor = needsGetter || needsSetter; | 135 bool needsAccessor = needsGetter || needsSetter; |
| 140 if (needsAccessor && backend.isAccessibleByReflection(member)) { | 136 if (needsAccessor && backend.isAccessibleByReflection(member)) { |
| 141 backend.retainMetadataOf(member); | 137 backend.retainMetadataOf(member); |
| 142 } | 138 } |
| 143 }); | 139 }); |
| 144 } | 140 } |
| 145 } | 141 } |
| 146 typedefsNeededForReflection.forEach(backend.retainMetadataOf); | 142 typedefsNeededForReflection.forEach(backend.retainMetadataOf); |
| 147 } | 143 } |
| 148 | 144 |
| 149 JavaScriptConstantCompiler handler = backend.constants; | 145 JavaScriptConstantCompiler handler = backend.constants; |
| 150 List<ConstantValue> constants = handler.getConstantsForEmission( | 146 List<ConstantValue> constants = handler.getConstantsForEmission(compiler |
| 151 compiler.options.hasIncrementalSupport ? null | 147 .options.hasIncrementalSupport ? null : emitter.compareConstants); |
| 152 : emitter.compareConstants); | |
| 153 for (ConstantValue constant in constants) { | 148 for (ConstantValue constant in constants) { |
| 154 if (emitter.isConstantInlinedOrAlreadyEmitted(constant)) continue; | 149 if (emitter.isConstantInlinedOrAlreadyEmitted(constant)) continue; |
| 155 | 150 |
| 156 if (constant.isList) outputContainsConstantList = true; | 151 if (constant.isList) outputContainsConstantList = true; |
| 157 | 152 |
| 158 OutputUnit constantUnit = | 153 OutputUnit constantUnit = |
| 159 compiler.deferredLoadTask.outputUnitForConstant(constant); | 154 compiler.deferredLoadTask.outputUnitForConstant(constant); |
| 160 if (constantUnit == null) { | 155 if (constantUnit == null) { |
| 161 // The back-end introduces some constants, like "InterceptorConstant" or | 156 // The back-end introduces some constants, like "InterceptorConstant" or |
| 162 // some list constants. They are emitted in the main output-unit. | 157 // some list constants. They are emitted in the main output-unit. |
| 163 // TODO(sigurdm): We should track those constants. | 158 // TODO(sigurdm): We should track those constants. |
| 164 constantUnit = compiler.deferredLoadTask.mainOutputUnit; | 159 constantUnit = compiler.deferredLoadTask.mainOutputUnit; |
| 165 } | 160 } |
| 166 outputConstantLists.putIfAbsent( | 161 outputConstantLists |
| 167 constantUnit, () => new List<ConstantValue>()).add(constant); | 162 .putIfAbsent(constantUnit, () => new List<ConstantValue>()) |
| 163 .add(constant); |
| 168 } | 164 } |
| 169 } | 165 } |
| 170 | 166 |
| 171 /// Compute all the classes and typedefs that must be emitted. | 167 /// Compute all the classes and typedefs that must be emitted. |
| 172 void computeNeededDeclarations() { | 168 void computeNeededDeclarations() { |
| 173 // Compute needed typedefs. | 169 // Compute needed typedefs. |
| 174 typedefsNeededForReflection = Elements.sortedByPosition( | 170 typedefsNeededForReflection = Elements.sortedByPosition(compiler |
| 175 compiler.world.allTypedefs | 171 .world.allTypedefs |
| 176 .where(backend.isAccessibleByReflection) | 172 .where(backend.isAccessibleByReflection) |
| 177 .toList()); | 173 .toList()); |
| 178 | 174 |
| 179 // Compute needed classes. | 175 // Compute needed classes. |
| 180 Set<ClassElement> instantiatedClasses = | 176 Set<ClassElement> instantiatedClasses = compiler |
| 181 compiler.codegenWorld.directlyInstantiatedClasses | 177 .codegenWorld.directlyInstantiatedClasses |
| 182 .where(computeClassFilter()).toSet(); | 178 .where(computeClassFilter()) |
| 179 .toSet(); |
| 183 | 180 |
| 184 void addClassWithSuperclasses(ClassElement cls) { | 181 void addClassWithSuperclasses(ClassElement cls) { |
| 185 neededClasses.add(cls); | 182 neededClasses.add(cls); |
| 186 for (ClassElement superclass = cls.superclass; | 183 for (ClassElement superclass = cls.superclass; |
| 187 superclass != null; | 184 superclass != null; |
| 188 superclass = superclass.superclass) { | 185 superclass = superclass.superclass) { |
| 189 neededClasses.add(superclass); | 186 neededClasses.add(superclass); |
| 190 } | 187 } |
| 191 } | 188 } |
| 192 | 189 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 238 } | 235 } |
| 239 | 236 |
| 240 // 4. Finally, sort the classes. | 237 // 4. Finally, sort the classes. |
| 241 List<ClassElement> sortedClasses = Elements.sortedByPosition(neededClasses); | 238 List<ClassElement> sortedClasses = Elements.sortedByPosition(neededClasses); |
| 242 | 239 |
| 243 for (ClassElement element in sortedClasses) { | 240 for (ClassElement element in sortedClasses) { |
| 244 if (backend.isNativeOrExtendsNative(element) && | 241 if (backend.isNativeOrExtendsNative(element) && |
| 245 !classesOnlyNeededForRti.contains(element)) { | 242 !classesOnlyNeededForRti.contains(element)) { |
| 246 // For now, native classes and related classes cannot be deferred. | 243 // For now, native classes and related classes cannot be deferred. |
| 247 nativeClassesAndSubclasses.add(element); | 244 nativeClassesAndSubclasses.add(element); |
| 248 assert(invariant(element, | 245 assert( |
| 249 !compiler.deferredLoadTask.isDeferred(element))); | 246 invariant(element, !compiler.deferredLoadTask.isDeferred(element))); |
| 250 outputClassLists.putIfAbsent(compiler.deferredLoadTask.mainOutputUnit, | 247 outputClassLists |
| 251 () => new List<ClassElement>()).add(element); | 248 .putIfAbsent(compiler.deferredLoadTask.mainOutputUnit, |
| 249 () => new List<ClassElement>()) |
| 250 .add(element); |
| 252 } else { | 251 } else { |
| 253 outputClassLists.putIfAbsent( | 252 outputClassLists |
| 254 compiler.deferredLoadTask.outputUnitForElement(element), | 253 .putIfAbsent( |
| 255 () => new List<ClassElement>()) | 254 compiler.deferredLoadTask.outputUnitForElement(element), |
| 255 () => new List<ClassElement>()) |
| 256 .add(element); | 256 .add(element); |
| 257 } | 257 } |
| 258 } | 258 } |
| 259 } | 259 } |
| 260 | 260 |
| 261 void computeNeededStatics() { | 261 void computeNeededStatics() { |
| 262 bool isStaticFunction(Element element) => | 262 bool isStaticFunction(Element element) => |
| 263 !element.isInstanceMember && !element.isField; | 263 !element.isInstanceMember && !element.isField; |
| 264 | 264 |
| 265 Iterable<Element> elements = | 265 Iterable<Element> elements = |
| 266 backend.generatedCode.keys.where(isStaticFunction); | 266 backend.generatedCode.keys.where(isStaticFunction); |
| 267 | 267 |
| 268 for (Element element in Elements.sortedByPosition(elements)) { | 268 for (Element element in Elements.sortedByPosition(elements)) { |
| 269 List<Element> list = outputStaticLists.putIfAbsent( | 269 List<Element> list = outputStaticLists.putIfAbsent( |
| 270 compiler.deferredLoadTask.outputUnitForElement(element), | 270 compiler.deferredLoadTask.outputUnitForElement(element), |
| 271 () => new List<Element>()); | 271 () => new List<Element>()); |
| 272 list.add(element); | 272 list.add(element); |
| 273 } | 273 } |
| 274 } | 274 } |
| 275 | 275 |
| 276 void computeNeededStaticNonFinalFields() { | 276 void computeNeededStaticNonFinalFields() { |
| 277 JavaScriptConstantCompiler handler = backend.constants; | 277 JavaScriptConstantCompiler handler = backend.constants; |
| 278 addToOutputUnit(Element element) { | 278 addToOutputUnit(Element element) { |
| 279 List<VariableElement> list = outputStaticNonFinalFieldLists.putIfAbsent( | 279 List<VariableElement> list = outputStaticNonFinalFieldLists.putIfAbsent( |
| 280 compiler.deferredLoadTask.outputUnitForElement(element), | 280 compiler.deferredLoadTask.outputUnitForElement(element), |
| 281 () => new List<VariableElement>()); | 281 () => new List<VariableElement>()); |
| 282 list.add(element); | 282 list.add(element); |
| 283 } | 283 } |
| 284 | 284 |
| 285 Iterable<VariableElement> staticNonFinalFields = handler | 285 Iterable<VariableElement> staticNonFinalFields = handler |
| 286 .getStaticNonFinalFieldsForEmission() | 286 .getStaticNonFinalFieldsForEmission() |
| 287 .where(compiler.codegenWorld.allReferencedStaticFields.contains); | 287 .where(compiler.codegenWorld.allReferencedStaticFields.contains); |
| 288 | 288 |
| 289 Elements.sortedByPosition(staticNonFinalFields).forEach(addToOutputUnit); | 289 Elements.sortedByPosition(staticNonFinalFields).forEach(addToOutputUnit); |
| 290 | 290 |
| 291 // We also need to emit static const fields if they are available for | 291 // We also need to emit static const fields if they are available for |
| 292 // reflection. | 292 // reflection. |
| 293 compiler.codegenWorld.allReferencedStaticFields | 293 compiler.codegenWorld.allReferencedStaticFields |
| 294 .where((FieldElement field) => field.isConst) | 294 .where((FieldElement field) => field.isConst) |
| 295 .where(backend.isAccessibleByReflection) | 295 .where(backend.isAccessibleByReflection) |
| 296 .forEach(addToOutputUnit); | 296 .forEach(addToOutputUnit); |
| 297 } | 297 } |
| 298 | 298 |
| 299 void computeNeededLibraries() { | 299 void computeNeededLibraries() { |
| 300 void addSurroundingLibraryToSet(Element element) { | 300 void addSurroundingLibraryToSet(Element element) { |
| 301 OutputUnit unit = compiler.deferredLoadTask.outputUnitForElement(element); | 301 OutputUnit unit = compiler.deferredLoadTask.outputUnitForElement(element); |
| 302 LibraryElement library = element.library; | 302 LibraryElement library = element.library; |
| 303 outputLibraryLists.putIfAbsent(unit, () => new Set<LibraryElement>()) | 303 outputLibraryLists |
| 304 .putIfAbsent(unit, () => new Set<LibraryElement>()) |
| 304 .add(library); | 305 .add(library); |
| 305 } | 306 } |
| 306 | 307 |
| 307 backend.generatedCode.keys.forEach(addSurroundingLibraryToSet); | 308 backend.generatedCode.keys.forEach(addSurroundingLibraryToSet); |
| 308 neededClasses.forEach(addSurroundingLibraryToSet); | 309 neededClasses.forEach(addSurroundingLibraryToSet); |
| 309 } | 310 } |
| 310 | 311 |
| 311 void collect() { | 312 void collect() { |
| 312 computeNeededDeclarations(); | 313 computeNeededDeclarations(); |
| 313 computeNeededConstants(); | 314 computeNeededConstants(); |
| 314 computeNeededStatics(); | 315 computeNeededStatics(); |
| 315 computeNeededStaticNonFinalFields(); | 316 computeNeededStaticNonFinalFields(); |
| 316 computeNeededLibraries(); | 317 computeNeededLibraries(); |
| 317 } | 318 } |
| 318 } | 319 } |
| OLD | NEW |