| 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 dart_backend; | 5 part of dart_backend; |
| 6 | 6 |
| 7 // TODO(ahe): This class is simply wrong. This backend should use | 7 // TODO(ahe): This class is simply wrong. This backend should use |
| 8 // elements when it can, not AST nodes. Perhaps a [Map<Element, | 8 // elements when it can, not AST nodes. Perhaps a [Map<Element, |
| 9 // TreeElements>] is what is needed. | 9 // TreeElements>] is what is needed. |
| 10 class ElementAst { | 10 class ElementAst { |
| 11 final Node ast; | 11 final Node ast; |
| 12 final TreeElements treeElements; | 12 final TreeElements treeElements; |
| 13 | 13 |
| 14 ElementAst(AstElement element) | 14 ElementAst(AstElement element) |
| 15 : this.internal(element.resolvedAst.node, element.resolvedAst.elements); | 15 : this.internal(element.resolvedAst.node, element.resolvedAst.elements); |
| 16 | 16 |
| 17 ElementAst.internal(this.ast, this.treeElements); | 17 ElementAst.internal(this.ast, this.treeElements); |
| 18 } | 18 } |
| 19 | 19 |
| 20 class DartBackend extends Backend { | 20 class DartBackend extends Backend { |
| 21 final List<CompilerTask> tasks; | 21 final List<CompilerTask> tasks; |
| 22 final bool forceStripTypes; | 22 final bool forceStripTypes; |
| 23 final bool stripAsserts; | 23 final bool stripAsserts; |
| 24 // TODO(antonm): make available from command-line options. | 24 // TODO(antonm): make available from command-line options. |
| 25 final bool outputAst = false; | 25 final bool outputAst = false; |
| 26 final Map<Node, String> renames; | |
| 27 final Map<LibraryElement, String> imports; | |
| 28 final Map<ClassNode, List<Node>> memberNodes; | 26 final Map<ClassNode, List<Node>> memberNodes; |
| 29 Map<Element, LibraryElement> reexportingLibraries; | 27 |
| 28 PlaceholderRenamer placeholderRenamer; |
| 30 | 29 |
| 31 // TODO(zarah) Maybe change this to a command-line option. | 30 // TODO(zarah) Maybe change this to a command-line option. |
| 32 // Right now, it is set by the tests. | 31 // Right now, it is set by the tests. |
| 33 bool useMirrorHelperLibrary = false; | 32 bool useMirrorHelperLibrary = false; |
| 34 | 33 |
| 35 /// Initialized if the useMirrorHelperLibrary field is set. | 34 /// Initialized if the useMirrorHelperLibrary field is set. |
| 36 MirrorRenamer mirrorRenamer; | 35 MirrorRenamer mirrorRenamer; |
| 37 | 36 |
| 38 /// Initialized when dart:mirrors is loaded if the useMirrorHelperLibrary | 37 /// Initialized when dart:mirrors is loaded if the useMirrorHelperLibrary |
| 39 /// field is set. | 38 /// field is set. |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 98 if (element.allSupertypes != null) { | 97 if (element.allSupertypes != null) { |
| 99 element.allSupertypes.forEach(workQueue.add); | 98 element.allSupertypes.forEach(workQueue.add); |
| 100 } | 99 } |
| 101 } | 100 } |
| 102 } | 101 } |
| 103 return true; | 102 return true; |
| 104 } | 103 } |
| 105 | 104 |
| 106 DartBackend(Compiler compiler, List<String> strips) | 105 DartBackend(Compiler compiler, List<String> strips) |
| 107 : tasks = <CompilerTask>[], | 106 : tasks = <CompilerTask>[], |
| 108 renames = new Map<Node, String>(), | |
| 109 imports = new Map<LibraryElement, String>(), | |
| 110 memberNodes = new Map<ClassNode, List<Node>>(), | 107 memberNodes = new Map<ClassNode, List<Node>>(), |
| 111 reexportingLibraries = <Element, LibraryElement>{}, | |
| 112 forceStripTypes = strips.indexOf('types') != -1, | 108 forceStripTypes = strips.indexOf('types') != -1, |
| 113 stripAsserts = strips.indexOf('asserts') != -1, | 109 stripAsserts = strips.indexOf('asserts') != -1, |
| 114 constantCompilerTask = new DartConstantTask(compiler), | 110 constantCompilerTask = new DartConstantTask(compiler), |
| 115 super(compiler) { | 111 super(compiler) { |
| 116 resolutionCallbacks = new DartResolutionCallbacks(this); | 112 resolutionCallbacks = new DartResolutionCallbacks(this); |
| 117 } | 113 } |
| 118 | 114 |
| 119 bool classNeedsRti(ClassElement cls) => false; | 115 bool classNeedsRti(ClassElement cls) => false; |
| 120 bool methodNeedsRti(FunctionElement function) => false; | 116 bool methodNeedsRti(FunctionElement function) => false; |
| 121 | 117 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 152 element is !AbstractFieldElement) | 148 element is !AbstractFieldElement) |
| 153 || element.library == mirrorHelperLibrary; | 149 || element.library == mirrorHelperLibrary; |
| 154 } | 150 } |
| 155 | 151 |
| 156 void assembleProgram() { | 152 void assembleProgram() { |
| 157 // Conservatively traverse all platform libraries and collect member names. | 153 // Conservatively traverse all platform libraries and collect member names. |
| 158 // TODO(antonm): ideally we should only collect names of used members, | 154 // TODO(antonm): ideally we should only collect names of used members, |
| 159 // however as of today there are problems with names of some core library | 155 // however as of today there are problems with names of some core library |
| 160 // interfaces, most probably for interfaces of literals. | 156 // interfaces, most probably for interfaces of literals. |
| 161 final fixedMemberNames = new Set<String>(); | 157 final fixedMemberNames = new Set<String>(); |
| 158 |
| 159 Map<Element, LibraryElement> reexportingLibraries = |
| 160 <Element, LibraryElement>{}; |
| 161 |
| 162 for (final library in compiler.libraryLoader.libraries) { | 162 for (final library in compiler.libraryLoader.libraries) { |
| 163 if (!library.isPlatformLibrary) continue; | 163 if (!library.isPlatformLibrary) continue; |
| 164 library.forEachLocalMember((Element element) { | 164 library.forEachLocalMember((Element element) { |
| 165 if (element.isClass) { | 165 if (element.isClass) { |
| 166 ClassElement classElement = element; | 166 ClassElement classElement = element; |
| 167 assert(invariant(classElement, classElement.isResolved, | 167 assert(invariant(classElement, classElement.isResolved, |
| 168 message: "Unresolved platform class.")); | 168 message: "Unresolved platform class.")); |
| 169 classElement.forEachLocalMember((member) { | 169 classElement.forEachLocalMember((member) { |
| 170 final name = member.name; | 170 final name = member.name; |
| 171 // Skip operator names. | 171 // Skip operator names. |
| 172 if (!name.startsWith(r'operator$')) { | 172 if (!name.startsWith(r'operator$')) { |
| 173 // Fetch name of named constructors and factories if any, | 173 // Fetch name of named constructors and factories if any, |
| 174 // otherwise store regular name. | 174 // otherwise store regular name. |
| 175 // TODO(antonm): better way to analyze the name. | 175 // TODO(antonm): better way to analyze the name. |
| 176 fixedMemberNames.add(name.split(r'$').last); | 176 fixedMemberNames.add(name.split(r'$').last); |
| 177 } | 177 } |
| 178 }); | 178 }); |
| 179 } | 179 } |
| 180 // Even class names are added due to a delicate problem we have: | 180 // Even class names are added due to a delicate problem we have: |
| 181 // if one imports dart:core with a prefix, we cannot tell prefix.name | 181 // if one imports dart:core with a prefix, we cannot tell prefix.name |
| 182 // from dynamic invocation (alas!). So we'd better err on preserving | 182 // from dynamic invocation (alas!). So we'd better err on preserving |
| 183 // those names. | 183 // those names. |
| 184 fixedMemberNames.add(element.name); | 184 fixedMemberNames.add(element.name); |
| 185 }); | 185 }); |
| 186 |
| 186 for (Element export in library.exports) { | 187 for (Element export in library.exports) { |
| 187 if (!library.isInternalLibrary && | 188 if (!library.isInternalLibrary && |
| 188 export.library.isInternalLibrary) { | 189 export.library.isInternalLibrary) { |
| 189 // If an element of an internal library is reexported by a platform | 190 // If an element of an internal library is reexported by a platform |
| 190 // library, we have to import the reexporting library instead of the | 191 // library, we have to import the reexporting library instead of the |
| 191 // internal library, because the internal library is an | 192 // internal library, because the internal library is an |
| 192 // implementation detail of dart2js. | 193 // implementation detail of dart2js. |
| 193 reexportingLibraries[export] = library; | 194 reexportingLibraries[export] = library; |
| 194 } | 195 } |
| 195 } | 196 } |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 391 | 392 |
| 392 if (element.isClass) { | 393 if (element.isClass) { |
| 393 classMembers[element].forEach(makePlaceholders); | 394 classMembers[element].forEach(makePlaceholders); |
| 394 } | 395 } |
| 395 } | 396 } |
| 396 topLevelElements.forEach(makePlaceholders); | 397 topLevelElements.forEach(makePlaceholders); |
| 397 // Create renames. | 398 // Create renames. |
| 398 bool shouldCutDeclarationTypes = forceStripTypes | 399 bool shouldCutDeclarationTypes = forceStripTypes |
| 399 || (compiler.enableMinification | 400 || (compiler.enableMinification |
| 400 && isSafeToRemoveTypeDeclarations(classMembers)); | 401 && isSafeToRemoveTypeDeclarations(classMembers)); |
| 401 renamePlaceholders( | 402 |
| 402 compiler, collector, renames, imports, | 403 placeholderRenamer = |
| 403 fixedMemberNames, reexportingLibraries, | 404 new PlaceholderRenamer(compiler, fixedMemberNames, reexportingLibraries, |
| 404 shouldCutDeclarationTypes, | 405 cutDeclarationTypes: shouldCutDeclarationTypes); |
| 405 uniqueGlobalNaming: useMirrorHelperLibrary); | 406 |
| 407 placeholderRenamer.computeRenames(collector); |
| 406 | 408 |
| 407 // Sort elements. | 409 // Sort elements. |
| 408 final sortedTopLevels = sortElements(topLevelElements); | 410 final List<Element> sortedTopLevels = sortElements(topLevelElements); |
| 409 final sortedClassMembers = new Map<ClassElement, List<Element>>(); | 411 final Map<ClassElement, List<Element>> sortedClassMembers = |
| 412 new Map<ClassElement, List<Element>>(); |
| 410 classMembers.forEach((classElement, members) { | 413 classMembers.forEach((classElement, members) { |
| 411 sortedClassMembers[classElement] = sortElements(members); | 414 sortedClassMembers[classElement] = sortElements(members); |
| 412 }); | 415 }); |
| 413 | 416 |
| 414 if (outputAst) { | 417 if (outputAst) { |
| 415 // TODO(antonm): Ideally XML should be a separate backend. | 418 // TODO(antonm): Ideally XML should be a separate backend. |
| 416 // TODO(antonm): obey renames and minification, at least as an option. | 419 // TODO(antonm): obey renames and minification, at least as an option. |
| 417 StringBuffer sb = new StringBuffer(); | 420 StringBuffer sb = new StringBuffer(); |
| 418 outputElement(element) { | 421 outputElement(element) { |
| 419 sb.write(element.parseNode(compiler).toDebugString()); | 422 sb.write(element.parseNode(compiler).toDebugString()); |
| 420 } | 423 } |
| 421 | 424 |
| 422 // Emit XML for AST instead of the program. | 425 // Emit XML for AST instead of the program. |
| 423 for (final topLevel in sortedTopLevels) { | 426 for (final topLevel in sortedTopLevels) { |
| 424 if (topLevel.isClass && !emitNoMembersFor.contains(topLevel)) { | 427 if (topLevel.isClass && !emitNoMembersFor.contains(topLevel)) { |
| 425 // TODO(antonm): add some class info. | 428 // TODO(antonm): add some class info. |
| 426 sortedClassMembers[topLevel].forEach(outputElement); | 429 sortedClassMembers[topLevel].forEach(outputElement); |
| 427 } else { | 430 } else { |
| 428 outputElement(topLevel); | 431 outputElement(topLevel); |
| 429 } | 432 } |
| 430 } | 433 } |
| 431 compiler.assembledCode = '<Program>\n$sb</Program>\n'; | 434 compiler.assembledCode = '<Program>\n$sb</Program>\n'; |
| 432 return; | 435 return; |
| 433 } | 436 } |
| 434 | 437 |
| 435 final topLevelNodes = <Node>[]; | 438 final List<Node> topLevelNodes = <Node>[]; |
| 436 for (final element in sortedTopLevels) { | 439 for (final element in sortedTopLevels) { |
| 437 topLevelNodes.add(elementAsts[element].ast); | 440 topLevelNodes.add(elementAsts[element].ast); |
| 438 if (element.isClass && !element.isMixinApplication) { | 441 if (element.isClass && !element.isMixinApplication) { |
| 439 final members = <Node>[]; | 442 final members = <Node>[]; |
| 440 for (final member in sortedClassMembers[element]) { | 443 for (final member in sortedClassMembers[element]) { |
| 441 members.add(elementAsts[member].ast); | 444 members.add(elementAsts[member].ast); |
| 442 } | 445 } |
| 443 memberNodes[elementAsts[element].ast] = members; | 446 memberNodes[elementAsts[element].ast] = members; |
| 444 } | 447 } |
| 445 } | 448 } |
| 446 | 449 |
| 447 if (useMirrorHelperLibrary) { | 450 if (useMirrorHelperLibrary) { |
| 448 mirrorRenamer.addRenames(renames, topLevelNodes, collector); | 451 mirrorRenamer.addRenames(placeholderRenamer.renames, |
| 452 topLevelNodes, collector); |
| 449 } | 453 } |
| 450 | 454 |
| 451 final unparser = new EmitterUnparser(renames, stripTypes: forceStripTypes, | 455 final EmitterUnparser unparser = |
| 452 minify: compiler.enableMinification); | 456 new EmitterUnparser(placeholderRenamer.renames, |
| 453 emitCode(unparser, imports, topLevelNodes, memberNodes); | 457 stripTypes: forceStripTypes, |
| 454 String assembledCode = unparser.result; | 458 minify: compiler.enableMinification); |
| 455 compiler.outputProvider('', 'dart') | 459 for (LibraryElement library in placeholderRenamer.platformImports) { |
| 456 ..add(assembledCode) | 460 if (library.isPlatformLibrary && !library.isInternalLibrary) { |
| 457 ..close(); | 461 unparser.unparseImportTag(library.canonicalUri.toString()); |
| 458 compiler.assembledCode = assembledCode; | 462 } |
| 463 } |
| 464 for (int i = 0; i < sortedTopLevels.length; i++) { |
| 465 Element element = sortedTopLevels[i]; |
| 466 Node node = topLevelNodes[i]; |
| 467 if (node is ClassNode) { |
| 468 // TODO(smok): Filter out default constructors here. |
| 469 unparser.unparseClassWithBody(node, memberNodes[node]); |
| 470 } else { |
| 471 unparser.unparse(node); |
| 472 } |
| 473 unparser.newline(); |
| 474 } |
| 459 | 475 |
| 476 compiler.assembledCode = unparser.result; |
| 477 compiler.outputProvider("", "dart") |
| 478 ..add(compiler.assembledCode) |
| 479 ..close(); |
| 460 // Output verbose info about size ratio of resulting bundle to all | 480 // Output verbose info about size ratio of resulting bundle to all |
| 461 // referenced non-platform sources. | 481 // referenced non-platform sources. |
| 462 logResultBundleSizeInfo(topLevelElements); | 482 logResultBundleSizeInfo(topLevelElements); |
| 463 } | 483 } |
| 464 | 484 |
| 465 void logResultBundleSizeInfo(Set<Element> topLevelElements) { | 485 void logResultBundleSizeInfo(Set<Element> topLevelElements) { |
| 466 Iterable<LibraryElement> referencedLibraries = | 486 Iterable<LibraryElement> referencedLibraries = |
| 467 compiler.libraryLoader.libraries.where(isUserLibrary); | 487 compiler.libraryLoader.libraries.where(isUserLibrary); |
| 468 // Sum total size of scripts in each referenced library. | 488 // Sum total size of scripts in each referenced library. |
| 469 int nonPlatformSize = 0; | 489 int nonPlatformSize = 0; |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 674 } | 694 } |
| 675 | 695 |
| 676 Constant compileMetadata(MetadataAnnotation metadata, | 696 Constant compileMetadata(MetadataAnnotation metadata, |
| 677 Node node, | 697 Node node, |
| 678 TreeElements elements) { | 698 TreeElements elements) { |
| 679 return measure(() { | 699 return measure(() { |
| 680 return constantCompiler.compileMetadata(metadata, node, elements); | 700 return constantCompiler.compileMetadata(metadata, node, elements); |
| 681 }); | 701 }); |
| 682 } | 702 } |
| 683 } | 703 } |
| OLD | NEW |