| 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 /** | 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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 final Map<ClassElement, Map<String, jsAst.Expression>> additionalProperties = | 48 final Map<ClassElement, Map<String, jsAst.Expression>> additionalProperties = |
| 49 new Map<ClassElement, Map<String, jsAst.Expression>>(); | 49 new Map<ClassElement, Map<String, jsAst.Expression>>(); |
| 50 | 50 |
| 51 /// Records if a type variable is read dynamically for type tests. | 51 /// Records if a type variable is read dynamically for type tests. |
| 52 final Set<TypeVariableElement> readTypeVariables = | 52 final Set<TypeVariableElement> readTypeVariables = |
| 53 new Set<TypeVariableElement>(); | 53 new Set<TypeVariableElement>(); |
| 54 | 54 |
| 55 // TODO(ngeoffray): remove this field. | 55 // TODO(ngeoffray): remove this field. |
| 56 Set<ClassElement> instantiatedClasses; | 56 Set<ClassElement> instantiatedClasses; |
| 57 | 57 |
| 58 List<TypedefElement> typedefsNeededForReflection; | |
| 59 | |
| 60 JavaScriptBackend get backend => compiler.backend; | 58 JavaScriptBackend get backend => compiler.backend; |
| 61 TypeVariableHandler get typeVariableHandler => backend.typeVariableHandler; | 59 TypeVariableHandler get typeVariableHandler => backend.typeVariableHandler; |
| 62 | 60 |
| 63 String get _ => space; | 61 String get _ => space; |
| 64 String get space => compiler.enableMinification ? "" : " "; | 62 String get space => compiler.enableMinification ? "" : " "; |
| 65 String get n => compiler.enableMinification ? "" : "\n"; | 63 String get n => compiler.enableMinification ? "" : "\n"; |
| 66 String get N => compiler.enableMinification ? "\n" : ";\n"; | 64 String get N => compiler.enableMinification ? "\n" : ";\n"; |
| 67 | 65 |
| 68 CodeBuffer getBuffer(OutputUnit outputUnit) { | |
| 69 return outputBuffers.putIfAbsent(outputUnit, () => new CodeBuffer()); | |
| 70 } | |
| 71 | |
| 72 CodeBuffer get mainBuffer { | 66 CodeBuffer get mainBuffer { |
| 73 return getBuffer(compiler.deferredLoadTask.mainOutputUnit); | 67 return outputBuffers.putIfAbsent(compiler.deferredLoadTask.mainOutputUnit, |
| 68 () => new CodeBuffer()); |
| 74 } | 69 } |
| 75 | 70 |
| 76 /** | 71 /** |
| 77 * List of expressions and statements that will be included in the | 72 * List of expressions and statements that will be included in the |
| 78 * precompiled function. | 73 * precompiled function. |
| 79 * | 74 * |
| 80 * To save space, dart2js normally generates constructors and accessors | 75 * To save space, dart2js normally generates constructors and accessors |
| 81 * dynamically. This doesn't work in CSP mode, and may impact startup time | 76 * dynamically. This doesn't work in CSP mode, and may impact startup time |
| 82 * negatively. So dart2js will emit these functions to a separate file that | 77 * negatively. So dart2js will emit these functions to a separate file that |
| 83 * can be optionally included to support CSP mode or for faster startup. | 78 * can be optionally included to support CSP mode or for faster startup. |
| (...skipping 772 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 856 void emitStaticFunctions() { | 851 void emitStaticFunctions() { |
| 857 bool isStaticFunction(Element element) => | 852 bool isStaticFunction(Element element) => |
| 858 !element.isInstanceMember && !element.isField; | 853 !element.isInstanceMember && !element.isField; |
| 859 | 854 |
| 860 Iterable<Element> elements = | 855 Iterable<Element> elements = |
| 861 backend.generatedCode.keys.where(isStaticFunction); | 856 backend.generatedCode.keys.where(isStaticFunction); |
| 862 | 857 |
| 863 for (Element element in Elements.sortedByPosition(elements)) { | 858 for (Element element in Elements.sortedByPosition(elements)) { |
| 864 ClassBuilder builder = new ClassBuilder(namer); | 859 ClassBuilder builder = new ClassBuilder(namer); |
| 865 containerBuilder.addMember(element, builder); | 860 containerBuilder.addMember(element, builder); |
| 866 getElementDescriptor(element).properties.addAll(builder.properties); | 861 getElementDecriptor(element).properties.addAll(builder.properties); |
| 867 } | 862 } |
| 868 } | 863 } |
| 869 | 864 |
| 870 void emitStaticNonFinalFieldInitializations(CodeBuffer buffer) { | 865 void emitStaticNonFinalFieldInitializations(CodeBuffer buffer) { |
| 871 JavaScriptConstantCompiler handler = backend.constants; | 866 JavaScriptConstantCompiler handler = backend.constants; |
| 872 Iterable<VariableElement> staticNonFinalFields = | 867 Iterable<VariableElement> staticNonFinalFields = |
| 873 handler.getStaticNonFinalFieldsForEmission(); | 868 handler.getStaticNonFinalFieldsForEmission(); |
| 874 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) { | 869 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) { |
| 875 // [:interceptedNames:] is handled in [emitInterceptedNames]. | 870 // [:interceptedNames:] is handled in [emitInterceptedNames]. |
| 876 if (element == backend.interceptedNames) continue; | 871 if (element == backend.interceptedNames) continue; |
| (...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1142 // The back-end introduces some constants, like "InterceptorConstant" or | 1137 // The back-end introduces some constants, like "InterceptorConstant" or |
| 1143 // some list constants. They are emitted in the main output-unit. | 1138 // some list constants. They are emitted in the main output-unit. |
| 1144 // TODO(sigurdm): We should track those constants. | 1139 // TODO(sigurdm): We should track those constants. |
| 1145 constantUnit = compiler.deferredLoadTask.mainOutputUnit; | 1140 constantUnit = compiler.deferredLoadTask.mainOutputUnit; |
| 1146 } | 1141 } |
| 1147 outputConstantLists.putIfAbsent(constantUnit, () => new List<Constant>()) | 1142 outputConstantLists.putIfAbsent(constantUnit, () => new List<Constant>()) |
| 1148 .add(constant); | 1143 .add(constant); |
| 1149 } | 1144 } |
| 1150 } | 1145 } |
| 1151 | 1146 |
| 1152 /// Compute all the classes and typedefs that must be emitted. | 1147 /** |
| 1153 void computeNeededDeclarations() { | 1148 * Compute all the classes that must be emitted. |
| 1154 // Compute needed typedefs. | 1149 */ |
| 1155 typedefsNeededForReflection = Elements.sortedByPosition( | 1150 void computeNeededClasses() { |
| 1156 compiler.world.allTypedefs | |
| 1157 .where(backend.isNeededForReflection) | |
| 1158 .toList()); | |
| 1159 | |
| 1160 // Compute needed classes. | |
| 1161 instantiatedClasses = | 1151 instantiatedClasses = |
| 1162 compiler.codegenWorld.instantiatedClasses.where(computeClassFilter()) | 1152 compiler.codegenWorld.instantiatedClasses.where(computeClassFilter()) |
| 1163 .toSet(); | 1153 .toSet(); |
| 1164 | 1154 |
| 1165 void addClassWithSuperclasses(ClassElement cls) { | 1155 void addClassWithSuperclasses(ClassElement cls) { |
| 1166 neededClasses.add(cls); | 1156 neededClasses.add(cls); |
| 1167 for (ClassElement superclass = cls.superclass; | 1157 for (ClassElement superclass = cls.superclass; |
| 1168 superclass != null; | 1158 superclass != null; |
| 1169 superclass = superclass.superclass) { | 1159 superclass = superclass.superclass) { |
| 1170 neededClasses.add(superclass); | 1160 neededClasses.add(superclass); |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1305 | 1295 |
| 1306 mainBuffer.add(jsAst.prettyPrint(convertToFastObject, compiler)); | 1296 mainBuffer.add(jsAst.prettyPrint(convertToFastObject, compiler)); |
| 1307 mainBuffer.add(N); | 1297 mainBuffer.add(N); |
| 1308 } | 1298 } |
| 1309 | 1299 |
| 1310 void writeLibraryDescriptors(LibraryElement library) { | 1300 void writeLibraryDescriptors(LibraryElement library) { |
| 1311 var uri = library.canonicalUri; | 1301 var uri = library.canonicalUri; |
| 1312 if (uri.scheme == 'file' && compiler.outputUri != null) { | 1302 if (uri.scheme == 'file' && compiler.outputUri != null) { |
| 1313 uri = relativize(compiler.outputUri, library.canonicalUri, false); | 1303 uri = relativize(compiler.outputUri, library.canonicalUri, false); |
| 1314 } | 1304 } |
| 1315 Map<OutputUnit, ClassBuilder> descriptors = elementDescriptors[library]; | 1305 Map<OutputUnit, ClassBuilder> descriptors = |
| 1306 elementDescriptors[library]; |
| 1316 | 1307 |
| 1317 for (OutputUnit outputUnit in compiler.deferredLoadTask.allOutputUnits) { | 1308 for (OutputUnit outputUnit in compiler.deferredLoadTask.allOutputUnits) { |
| 1318 if (!descriptors.containsKey(outputUnit)) continue; | 1309 ClassBuilder descriptor = |
| 1319 | 1310 descriptors.putIfAbsent(outputUnit, () => new ClassBuilder(namer)); |
| 1320 ClassBuilder descriptor = descriptors[outputUnit]; | 1311 if (descriptor.properties.isEmpty) continue; |
| 1312 bool isDeferred = |
| 1313 outputUnit != compiler.deferredLoadTask.mainOutputUnit; |
| 1321 jsAst.Fun metadata = metadataEmitter.buildMetadataFunction(library); | 1314 jsAst.Fun metadata = metadataEmitter.buildMetadataFunction(library); |
| 1322 | 1315 |
| 1323 jsAst.ObjectInitializer initializers = descriptor.toObjectInitializer(); | 1316 jsAst.ObjectInitializer initializers = |
| 1324 CodeBuffer outputBuffer = getBuffer(outputUnit); | 1317 descriptor.toObjectInitializer(); |
| 1325 | 1318 CodeBuffer outputBuffer = |
| 1319 outputBuffers.putIfAbsent(outputUnit, () => new CodeBuffer()); |
| 1326 int sizeBefore = outputBuffer.length; | 1320 int sizeBefore = outputBuffer.length; |
| 1327 outputBuffers[outputUnit] | 1321 outputBuffers[outputUnit] |
| 1328 ..write('["${library.getLibraryName()}",$_') | 1322 ..write('["${library.getLibraryName()}",$_') |
| 1329 ..write('"${uri}",$_') | 1323 ..write('"${uri}",$_') |
| 1330 ..write(metadata == null ? "" : jsAst.prettyPrint(metadata, compiler)) | 1324 ..write(metadata == null ? "" : jsAst.prettyPrint(metadata, compiler)) |
| 1331 ..write(',$_') | 1325 ..write(',$_') |
| 1332 ..write(namer.globalObjectFor(library)) | 1326 ..write(namer.globalObjectFor(library)) |
| 1333 ..write(',$_') | 1327 ..write(',$_') |
| 1334 ..write(jsAst.prettyPrint(initializers, compiler)) | 1328 ..write(jsAst.prettyPrint(initializers, compiler)) |
| 1335 ..write(library == compiler.mainApp ? ',${n}1' : "") | 1329 ..write(library == compiler.mainApp ? ',${n}1' : "") |
| 1336 ..write('],$n'); | 1330 ..write('],$n'); |
| 1337 int sizeAfter = outputBuffer.length; | 1331 int sizeAfter = outputBuffer.length; |
| 1338 compiler.dumpInfoTask.codeSizeCounter | 1332 compiler.dumpInfoTask.codeSizeCounter |
| 1339 .countCode(library, sizeAfter - sizeBefore); | 1333 .countCode(library, sizeAfter - sizeBefore); |
| 1340 } | 1334 } |
| 1341 } | 1335 } |
| 1342 | 1336 |
| 1343 String assembleProgram() { | 1337 String assembleProgram() { |
| 1344 measure(() { | 1338 measure(() { |
| 1345 invalidateCaches(); | 1339 invalidateCaches(); |
| 1346 | 1340 |
| 1347 // Compute the required type checks to know which classes need a | 1341 // Compute the required type checks to know which classes need a |
| 1348 // 'is$' method. | 1342 // 'is$' method. |
| 1349 typeTestEmitter.computeRequiredTypeChecks(); | 1343 typeTestEmitter.computeRequiredTypeChecks(); |
| 1350 | 1344 |
| 1351 computeNeededDeclarations(); | 1345 computeNeededClasses(); |
| 1352 | 1346 |
| 1353 mainBuffer.add(buildGeneratedBy()); | 1347 mainBuffer.add(buildGeneratedBy()); |
| 1354 addComment(HOOKS_API_USAGE, mainBuffer); | 1348 addComment(HOOKS_API_USAGE, mainBuffer); |
| 1355 | 1349 |
| 1356 if (!compiler.deferredLoadTask.splitProgram) { | 1350 if (!compiler.deferredLoadTask.splitProgram) { |
| 1357 mainBuffer.add('(function(${namer.currentIsolate})$_{$n'); | 1351 mainBuffer.add('(function(${namer.currentIsolate})$_{$n'); |
| 1358 } | 1352 } |
| 1359 | 1353 |
| 1360 // Using a named function here produces easier to read stack traces in | 1354 // Using a named function here produces easier to read stack traces in |
| 1361 // Chrome/V8. | 1355 // Chrome/V8. |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1400 } | 1394 } |
| 1401 | 1395 |
| 1402 // As a side-effect, emitting classes will produce "bound closures" in | 1396 // As a side-effect, emitting classes will produce "bound closures" in |
| 1403 // [methodClosures]. The bound closures are JS AST nodes that add | 1397 // [methodClosures]. The bound closures are JS AST nodes that add |
| 1404 // properties to $$ [classesCollector]. The bound closures are not | 1398 // properties to $$ [classesCollector]. The bound closures are not |
| 1405 // emitted until we have emitted all other classes (native or not). | 1399 // emitted until we have emitted all other classes (native or not). |
| 1406 | 1400 |
| 1407 // Might create methodClosures. | 1401 // Might create methodClosures. |
| 1408 for (List<ClassElement> outputClassList in outputClassLists.values) { | 1402 for (List<ClassElement> outputClassList in outputClassLists.values) { |
| 1409 for (ClassElement element in outputClassList) { | 1403 for (ClassElement element in outputClassList) { |
| 1410 generateClass(element, getElementDescriptor(element)); | 1404 generateClass(element, getElementDecriptor(element)); |
| 1411 } | 1405 } |
| 1412 } | 1406 } |
| 1413 | 1407 |
| 1414 nativeEmitter.finishGenerateNativeClasses(); | 1408 nativeEmitter.finishGenerateNativeClasses(); |
| 1415 nativeEmitter.assembleCode(nativeBuffer); | 1409 nativeEmitter.assembleCode(nativeBuffer); |
| 1416 | 1410 |
| 1417 | 1411 |
| 1418 // After this assignment we will produce invalid JavaScript code if we use | 1412 // After this assignment we will produce invalid JavaScript code if we use |
| 1419 // the classesCollector variable. | 1413 // the classesCollector variable. |
| 1420 classesCollector = 'classesCollector should not be used from now on'; | 1414 classesCollector = 'classesCollector should not be used from now on'; |
| 1421 | 1415 |
| 1422 // TODO(sigurdm): Need to check this for each outputUnit. | 1416 // TODO(sigurdm): Need to check this for each outputUnit. |
| 1423 if (!elementDescriptors.isEmpty) { | 1417 if (!elementDescriptors.isEmpty) { |
| 1424 var oldClassesCollector = classesCollector; | 1418 var oldClassesCollector = classesCollector; |
| 1425 classesCollector = r"$$"; | 1419 classesCollector = r"$$"; |
| 1426 if (compiler.enableMinification) { | 1420 if (compiler.enableMinification) { |
| 1427 mainBuffer.write(';'); | 1421 mainBuffer.write(';'); |
| 1428 } | 1422 } |
| 1429 | 1423 |
| 1430 // TODO(karlklose): document what kinds of fields this loop adds to the | |
| 1431 // library class builder. | |
| 1432 for (Element element in elementDescriptors.keys) { | 1424 for (Element element in elementDescriptors.keys) { |
| 1433 // TODO(ahe): Should iterate over all libraries. Otherwise, we will | 1425 // TODO(ahe): Should iterate over all libraries. Otherwise, we will |
| 1434 // not see libraries that only have fields. | 1426 // not see libraries that only have fields. |
| 1435 if (element.isLibrary) { | 1427 if (element.isLibrary) { |
| 1436 LibraryElement library = element; | 1428 LibraryElement library = element; |
| 1437 ClassBuilder builder = new ClassBuilder(namer); | 1429 ClassBuilder builder = new ClassBuilder(namer); |
| 1438 if (classEmitter.emitFields( | 1430 if (classEmitter.emitFields( |
| 1439 library, builder, null, emitStatics: true)) { | 1431 library, builder, null, emitStatics: true)) { |
| 1440 OutputUnit mainUnit = compiler.deferredLoadTask.mainOutputUnit; | 1432 OutputUnit mainUnit = compiler.deferredLoadTask.mainOutputUnit; |
| 1441 getElementDescriptorForOutputUnit(library, mainUnit) | 1433 getElementDescriptorForOutputUnit(library, mainUnit) |
| 1442 .properties.addAll(builder.toObjectInitializer().properties); | 1434 .properties.addAll(builder.toObjectInitializer().properties); |
| 1443 } | 1435 } |
| 1444 } | 1436 } |
| 1445 } | 1437 } |
| 1446 | 1438 |
| 1447 // Emit all required typedef declarations into the main output unit. | |
| 1448 // TODO(karlklose): unify required classes and typedefs to declarations | |
| 1449 // and have builders for each kind. | |
| 1450 for (TypedefElement typedef in typedefsNeededForReflection) { | |
| 1451 OutputUnit mainUnit = compiler.deferredLoadTask.mainOutputUnit; | |
| 1452 LibraryElement library = typedef.library; | |
| 1453 // TODO(karlklose): add a TypedefBuilder and move this code there. | |
| 1454 DartType type = typedef.alias; | |
| 1455 int typeIndex = metadataEmitter.reifyType(type); | |
| 1456 String typeReference = | |
| 1457 encoding.encodeTypedefFieldDescriptor(typeIndex); | |
| 1458 jsAst.Property descriptor = new jsAst.Property( | |
| 1459 js.string(namer.classDescriptorProperty), | |
| 1460 js.string(typeReference)); | |
| 1461 jsAst.Node declaration = new jsAst.ObjectInitializer([descriptor]); | |
| 1462 ClassBuilder builder; | |
| 1463 getElementDescriptorForOutputUnit(library, mainUnit) | |
| 1464 .addProperty(namer.getNameX(typedef), declaration); | |
| 1465 } | |
| 1466 | |
| 1467 if (!mangledFieldNames.isEmpty) { | 1439 if (!mangledFieldNames.isEmpty) { |
| 1468 var keys = mangledFieldNames.keys.toList(); | 1440 var keys = mangledFieldNames.keys.toList(); |
| 1469 keys.sort(); | 1441 keys.sort(); |
| 1470 var properties = []; | 1442 var properties = []; |
| 1471 for (String key in keys) { | 1443 for (String key in keys) { |
| 1472 var value = js.string('${mangledFieldNames[key]}'); | 1444 var value = js.string('${mangledFieldNames[key]}'); |
| 1473 properties.add(new jsAst.Property(js.string(key), value)); | 1445 properties.add(new jsAst.Property(js.string(key), value)); |
| 1474 } | 1446 } |
| 1475 var map = new jsAst.ObjectInitializer(properties); | 1447 var map = new jsAst.ObjectInitializer(properties); |
| 1476 mainBuffer.write( | 1448 mainBuffer.write( |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1713 | 1685 |
| 1714 ClassBuilder getElementDescriptorForOutputUnit(Element element, | 1686 ClassBuilder getElementDescriptorForOutputUnit(Element element, |
| 1715 OutputUnit outputUnit) { | 1687 OutputUnit outputUnit) { |
| 1716 Map<OutputUnit, ClassBuilder> descriptors = | 1688 Map<OutputUnit, ClassBuilder> descriptors = |
| 1717 elementDescriptors.putIfAbsent( | 1689 elementDescriptors.putIfAbsent( |
| 1718 element, () => new Map<OutputUnit, ClassBuilder>()); | 1690 element, () => new Map<OutputUnit, ClassBuilder>()); |
| 1719 return descriptors.putIfAbsent(outputUnit, | 1691 return descriptors.putIfAbsent(outputUnit, |
| 1720 () => new ClassBuilder(namer)); | 1692 () => new ClassBuilder(namer)); |
| 1721 } | 1693 } |
| 1722 | 1694 |
| 1723 ClassBuilder getElementDescriptor(Element element) { | 1695 ClassBuilder getElementDecriptor(Element element) { |
| 1724 Element owner = element.library; | 1696 Element owner = element.library; |
| 1725 if (!element.isTopLevel && !element.isNative) { | 1697 if (!element.isTopLevel && !element.isNative) { |
| 1726 // For static (not top level) elements, record their code in a buffer | 1698 // For static (not top level) elements, record their code in a buffer |
| 1727 // specific to the class. For now, not supported for native classes and | 1699 // specific to the class. For now, not supported for native classes and |
| 1728 // native elements. | 1700 // native elements. |
| 1729 ClassElement cls = | 1701 ClassElement cls = |
| 1730 element.enclosingClassOrCompilationUnit.declaration; | 1702 element.enclosingClassOrCompilationUnit.declaration; |
| 1731 if (compiler.codegenWorld.instantiatedClasses.contains(cls) | 1703 if (compiler.codegenWorld.instantiatedClasses.contains(cls) |
| 1732 && !cls.isNative) { | 1704 && !cls.isNative) { |
| 1733 owner = cls; | 1705 owner = cls; |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1828 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) { | 1800 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) { |
| 1829 if (element.isInstanceMember) { | 1801 if (element.isInstanceMember) { |
| 1830 cachedClassBuilders.remove(element.enclosingClass); | 1802 cachedClassBuilders.remove(element.enclosingClass); |
| 1831 | 1803 |
| 1832 nativeEmitter.cachedBuilders.remove(element.enclosingClass); | 1804 nativeEmitter.cachedBuilders.remove(element.enclosingClass); |
| 1833 | 1805 |
| 1834 } | 1806 } |
| 1835 } | 1807 } |
| 1836 } | 1808 } |
| 1837 } | 1809 } |
| OLD | NEW |