| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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; | 5 part of dart2js.js_emitter; |
| 6 | 6 |
| 7 const USE_LAZY_EMITTER = const bool.fromEnvironment("dart2js.use.lazy.emitter"); | 7 const USE_LAZY_EMITTER = const bool.fromEnvironment("dart2js.use.lazy.emitter"); |
| 8 | 8 |
| 9 /** | 9 /** |
| 10 * Generates the code for all used classes in the program. Static fields (even | 10 * Generates the code for all used classes in the program. Static fields (even |
| 11 * in classes) are ignored, since they can be treated as non-class elements. | 11 * in classes) are ignored, since they can be treated as non-class elements. |
| 12 * | 12 * |
| 13 * The code for the containing (used) methods must exist in the `universe`. | 13 * The code for the containing (used) methods must exist in the `universe`. |
| 14 */ | 14 */ |
| 15 class CodeEmitterTask extends CompilerTask { | 15 class CodeEmitterTask extends CompilerTask { |
| 16 // TODO(floitsch): the code-emitter task should not need a namer. | 16 // TODO(floitsch): the code-emitter task should not need a namer. |
| 17 final Namer namer; | 17 final Namer namer; |
| 18 final TypeTestRegistry typeTestRegistry; | 18 final TypeTestRegistry typeTestRegistry; |
| 19 NativeEmitter nativeEmitter; | 19 NativeEmitter nativeEmitter; |
| 20 MetadataCollector metadataCollector; | 20 MetadataCollector metadataCollector; |
| 21 OldEmitter oldEmitter; | 21 OldEmitter oldEmitter; |
| 22 Emitter emitter; | 22 Emitter emitter; |
| 23 | 23 |
| 24 final Set<ClassElement> neededClasses = new Set<ClassElement>(); | 24 final Set<ClassElement> neededClasses = new Set<ClassElement>(); |
| 25 Set<ClassElement> classesOnlyNeededForRti; |
| 25 final Map<OutputUnit, List<ClassElement>> outputClassLists = | 26 final Map<OutputUnit, List<ClassElement>> outputClassLists = |
| 26 new Map<OutputUnit, List<ClassElement>>(); | 27 new Map<OutputUnit, List<ClassElement>>(); |
| 27 final Map<OutputUnit, List<ConstantValue>> outputConstantLists = | 28 final Map<OutputUnit, List<ConstantValue>> outputConstantLists = |
| 28 new Map<OutputUnit, List<ConstantValue>>(); | 29 new Map<OutputUnit, List<ConstantValue>>(); |
| 29 final Map<OutputUnit, List<Element>> outputStaticLists = | 30 final Map<OutputUnit, List<Element>> outputStaticLists = |
| 30 new Map<OutputUnit, List<Element>>(); | 31 new Map<OutputUnit, List<Element>>(); |
| 31 final Map<OutputUnit, List<VariableElement>> outputStaticNonFinalFieldLists = | 32 final Map<OutputUnit, List<VariableElement>> outputStaticNonFinalFieldLists = |
| 32 new Map<OutputUnit, List<VariableElement>>(); | 33 new Map<OutputUnit, List<VariableElement>>(); |
| 33 final Map<OutputUnit, Set<LibraryElement>> outputLibraryLists = | 34 final Map<OutputUnit, Set<LibraryElement>> outputLibraryLists = |
| 34 new Map<OutputUnit, Set<LibraryElement>>(); | 35 new Map<OutputUnit, Set<LibraryElement>>(); |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 204 if (shouldRetainMetadata && | 205 if (shouldRetainMetadata && |
| 205 (element.isFunction || element.isConstructor || | 206 (element.isFunction || element.isConstructor || |
| 206 element.isSetter)) { | 207 element.isSetter)) { |
| 207 FunctionElement function = element; | 208 FunctionElement function = element; |
| 208 function.functionSignature.forEachParameter( | 209 function.functionSignature.forEachParameter( |
| 209 backend.retainMetadataOf); | 210 backend.retainMetadataOf); |
| 210 } | 211 } |
| 211 } | 212 } |
| 212 } | 213 } |
| 213 for (ClassElement cls in neededClasses) { | 214 for (ClassElement cls in neededClasses) { |
| 214 final onlyForRti = typeTestRegistry.rtiNeededClasses.contains(cls); | 215 final onlyForRti = classesOnlyNeededForRti.contains(cls); |
| 215 if (!onlyForRti) { | 216 if (!onlyForRti) { |
| 216 backend.retainMetadataOf(cls); | 217 backend.retainMetadataOf(cls); |
| 217 oldEmitter.classEmitter.visitFields(cls, false, | 218 oldEmitter.classEmitter.visitFields(cls, false, |
| 218 (Element member, | 219 (Element member, |
| 219 jsAst.Name name, | 220 jsAst.Name name, |
| 220 jsAst.Name accessorName, | 221 jsAst.Name accessorName, |
| 221 bool needsGetter, | 222 bool needsGetter, |
| 222 bool needsSetter, | 223 bool needsSetter, |
| 223 bool needsCheckedSetter) { | 224 bool needsCheckedSetter) { |
| 224 bool needsAccessor = needsGetter || needsSetter; | 225 bool needsAccessor = needsGetter || needsSetter; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 246 // some list constants. They are emitted in the main output-unit. | 247 // some list constants. They are emitted in the main output-unit. |
| 247 // TODO(sigurdm): We should track those constants. | 248 // TODO(sigurdm): We should track those constants. |
| 248 constantUnit = compiler.deferredLoadTask.mainOutputUnit; | 249 constantUnit = compiler.deferredLoadTask.mainOutputUnit; |
| 249 } | 250 } |
| 250 outputConstantLists.putIfAbsent( | 251 outputConstantLists.putIfAbsent( |
| 251 constantUnit, () => new List<ConstantValue>()).add(constant); | 252 constantUnit, () => new List<ConstantValue>()).add(constant); |
| 252 } | 253 } |
| 253 } | 254 } |
| 254 | 255 |
| 255 /// Compute all the classes and typedefs that must be emitted. | 256 /// Compute all the classes and typedefs that must be emitted. |
| 256 void computeNeededDeclarations() { | 257 void computeNeededDeclarations(Set<ClassElement> rtiNeededClasses) { |
| 257 // Compute needed typedefs. | 258 // Compute needed typedefs. |
| 258 typedefsNeededForReflection = Elements.sortedByPosition( | 259 typedefsNeededForReflection = Elements.sortedByPosition( |
| 259 compiler.world.allTypedefs | 260 compiler.world.allTypedefs |
| 260 .where(backend.isAccessibleByReflection) | 261 .where(backend.isAccessibleByReflection) |
| 261 .toList()); | 262 .toList()); |
| 262 | 263 |
| 263 // Compute needed classes. | 264 // Compute needed classes. |
| 264 Set<ClassElement> instantiatedClasses = | 265 Set<ClassElement> instantiatedClasses = |
| 265 compiler.codegenWorld.directlyInstantiatedClasses | 266 compiler.codegenWorld.directlyInstantiatedClasses |
| 266 .where(computeClassFilter()).toSet(); | 267 .where(computeClassFilter()).toSet(); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 290 .toSet(); | 291 .toSet(); |
| 291 neededClasses.addAll(mixinClasses); | 292 neededClasses.addAll(mixinClasses); |
| 292 | 293 |
| 293 // 3. Find all classes needed for rti. | 294 // 3. Find all classes needed for rti. |
| 294 // It is important that this is the penultimate step, at this point, | 295 // It is important that this is the penultimate step, at this point, |
| 295 // neededClasses must only contain classes that have been resolved and | 296 // neededClasses must only contain classes that have been resolved and |
| 296 // codegen'd. The rtiNeededClasses may contain additional classes, but | 297 // codegen'd. The rtiNeededClasses may contain additional classes, but |
| 297 // these are thought to not have been instantiated, so we neeed to be able | 298 // these are thought to not have been instantiated, so we neeed to be able |
| 298 // to identify them later and make sure we only emit "empty shells" without | 299 // to identify them later and make sure we only emit "empty shells" without |
| 299 // fields, etc. | 300 // fields, etc. |
| 300 typeTestRegistry.computeRtiNeededClasses(); | 301 classesOnlyNeededForRti = rtiNeededClasses.difference(neededClasses); |
| 301 | 302 |
| 302 // TODO(floitsch): either change the name, or get the rti-classes | 303 neededClasses.addAll(classesOnlyNeededForRti); |
| 303 // differently. | |
| 304 typeTestRegistry.rtiNeededClasses.removeAll(neededClasses); | |
| 305 // rtiNeededClasses now contains only the "empty shells". | |
| 306 neededClasses.addAll(typeTestRegistry.rtiNeededClasses); | |
| 307 | 304 |
| 308 // TODO(18175, floitsch): remove once issue 18175 is fixed. | 305 // TODO(18175, floitsch): remove once issue 18175 is fixed. |
| 309 if (neededClasses.contains(backend.jsIntClass)) { | 306 if (neededClasses.contains(backend.jsIntClass)) { |
| 310 neededClasses.add(compiler.intClass); | 307 neededClasses.add(compiler.intClass); |
| 311 } | 308 } |
| 312 if (neededClasses.contains(backend.jsDoubleClass)) { | 309 if (neededClasses.contains(backend.jsDoubleClass)) { |
| 313 neededClasses.add(compiler.doubleClass); | 310 neededClasses.add(compiler.doubleClass); |
| 314 } | 311 } |
| 315 if (neededClasses.contains(backend.jsNumberClass)) { | 312 if (neededClasses.contains(backend.jsNumberClass)) { |
| 316 neededClasses.add(compiler.numClass); | 313 neededClasses.add(compiler.numClass); |
| 317 } | 314 } |
| 318 if (neededClasses.contains(backend.jsStringClass)) { | 315 if (neededClasses.contains(backend.jsStringClass)) { |
| 319 neededClasses.add(compiler.stringClass); | 316 neededClasses.add(compiler.stringClass); |
| 320 } | 317 } |
| 321 if (neededClasses.contains(backend.jsBoolClass)) { | 318 if (neededClasses.contains(backend.jsBoolClass)) { |
| 322 neededClasses.add(compiler.boolClass); | 319 neededClasses.add(compiler.boolClass); |
| 323 } | 320 } |
| 324 if (neededClasses.contains(backend.jsArrayClass)) { | 321 if (neededClasses.contains(backend.jsArrayClass)) { |
| 325 neededClasses.add(compiler.listClass); | 322 neededClasses.add(compiler.listClass); |
| 326 } | 323 } |
| 327 | 324 |
| 328 // 4. Finally, sort the classes. | 325 // 4. Finally, sort the classes. |
| 329 List<ClassElement> sortedClasses = Elements.sortedByPosition(neededClasses); | 326 List<ClassElement> sortedClasses = Elements.sortedByPosition(neededClasses); |
| 330 | 327 |
| 331 for (ClassElement element in sortedClasses) { | 328 for (ClassElement element in sortedClasses) { |
| 332 if (Elements.isNativeOrExtendsNative(element) && | 329 if (Elements.isNativeOrExtendsNative(element) && |
| 333 !typeTestRegistry.rtiNeededClasses.contains(element)) { | 330 !classesOnlyNeededForRti.contains(element)) { |
| 334 // For now, native classes and related classes cannot be deferred. | 331 // For now, native classes and related classes cannot be deferred. |
| 335 nativeClassesAndSubclasses.add(element); | 332 nativeClassesAndSubclasses.add(element); |
| 336 assert(invariant(element, | 333 assert(invariant(element, |
| 337 !compiler.deferredLoadTask.isDeferred(element))); | 334 !compiler.deferredLoadTask.isDeferred(element))); |
| 338 outputClassLists.putIfAbsent(compiler.deferredLoadTask.mainOutputUnit, | 335 outputClassLists.putIfAbsent(compiler.deferredLoadTask.mainOutputUnit, |
| 339 () => new List<ClassElement>()).add(element); | 336 () => new List<ClassElement>()).add(element); |
| 340 } else { | 337 } else { |
| 341 outputClassLists.putIfAbsent( | 338 outputClassLists.putIfAbsent( |
| 342 compiler.deferredLoadTask.outputUnitForElement(element), | 339 compiler.deferredLoadTask.outputUnitForElement(element), |
| 343 () => new List<ClassElement>()) | 340 () => new List<ClassElement>()) |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 383 } | 380 } |
| 384 | 381 |
| 385 backend.generatedCode.keys.forEach(addSurroundingLibraryToSet); | 382 backend.generatedCode.keys.forEach(addSurroundingLibraryToSet); |
| 386 neededClasses.forEach(addSurroundingLibraryToSet); | 383 neededClasses.forEach(addSurroundingLibraryToSet); |
| 387 } | 384 } |
| 388 | 385 |
| 389 void computeAllNeededEntities() { | 386 void computeAllNeededEntities() { |
| 390 // Compute the required type checks to know which classes need a | 387 // Compute the required type checks to know which classes need a |
| 391 // 'is$' method. | 388 // 'is$' method. |
| 392 typeTestRegistry.computeRequiredTypeChecks(); | 389 typeTestRegistry.computeRequiredTypeChecks(); |
| 390 // Compute the classes needed by RTI. |
| 391 Set<ClassElement> rtiClasses = typeTestRegistry.computeRtiNeededClasses(); |
| 393 | 392 |
| 394 computeNeededDeclarations(); | 393 computeNeededDeclarations(rtiClasses); |
| 395 computeNeededConstants(); | 394 computeNeededConstants(); |
| 396 computeNeededStatics(); | 395 computeNeededStatics(); |
| 397 computeNeededStaticNonFinalFields(); | 396 computeNeededStaticNonFinalFields(); |
| 398 computeNeededLibraries(); | 397 computeNeededLibraries(); |
| 399 } | 398 } |
| 400 | 399 |
| 401 int assembleProgram() { | 400 int assembleProgram() { |
| 402 return measure(() { | 401 return measure(() { |
| 403 emitter.invalidateCaches(); | 402 emitter.invalidateCaches(); |
| 404 | 403 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 453 bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant); | 452 bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant); |
| 454 | 453 |
| 455 /// Returns the JS code for accessing the given [constant]. | 454 /// Returns the JS code for accessing the given [constant]. |
| 456 jsAst.Expression constantReference(ConstantValue constant); | 455 jsAst.Expression constantReference(ConstantValue constant); |
| 457 | 456 |
| 458 /// Returns the JS template for the given [builtin]. | 457 /// Returns the JS template for the given [builtin]. |
| 459 jsAst.Template templateForBuiltin(JsBuiltin builtin); | 458 jsAst.Template templateForBuiltin(JsBuiltin builtin); |
| 460 | 459 |
| 461 void invalidateCaches(); | 460 void invalidateCaches(); |
| 462 } | 461 } |
| OLD | NEW |