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<ClassNode, List<Node>> memberNodes; | 26 final Map<ClassNode, List<Node>> memberNodes; |
27 | 27 |
| 28 /// If `true`, libraries are generated into separate files. |
| 29 final bool multiFile; |
| 30 |
28 PlaceholderRenamer placeholderRenamer; | 31 PlaceholderRenamer placeholderRenamer; |
29 | 32 |
30 // TODO(zarah) Maybe change this to a command-line option. | 33 // TODO(zarah) Maybe change this to a command-line option. |
31 // Right now, it is set by the tests. | 34 // Right now, it is set by the tests. |
32 bool useMirrorHelperLibrary = false; | 35 bool useMirrorHelperLibrary = false; |
33 | 36 |
34 /// Initialized if the useMirrorHelperLibrary field is set. | 37 /// Initialized if the useMirrorHelperLibrary field is set. |
35 MirrorRenamer mirrorRenamer; | 38 MirrorRenamer mirrorRenamer; |
36 | 39 |
37 /// Initialized when dart:mirrors is loaded if the useMirrorHelperLibrary | 40 /// Initialized when dart:mirrors is loaded if the useMirrorHelperLibrary |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
95 ClassElement element = type.element; | 98 ClassElement element = type.element; |
96 // Check all supertypes. | 99 // Check all supertypes. |
97 if (element.allSupertypes != null) { | 100 if (element.allSupertypes != null) { |
98 element.allSupertypes.forEach(workQueue.add); | 101 element.allSupertypes.forEach(workQueue.add); |
99 } | 102 } |
100 } | 103 } |
101 } | 104 } |
102 return true; | 105 return true; |
103 } | 106 } |
104 | 107 |
105 DartBackend(Compiler compiler, List<String> strips) | 108 DartBackend(Compiler compiler, List<String> strips, {this.multiFile}) |
106 : tasks = <CompilerTask>[], | 109 : tasks = <CompilerTask>[], |
107 memberNodes = new Map<ClassNode, List<Node>>(), | 110 memberNodes = new Map<ClassNode, List<Node>>(), |
108 forceStripTypes = strips.indexOf('types') != -1, | 111 forceStripTypes = strips.indexOf('types') != -1, |
109 stripAsserts = strips.indexOf('asserts') != -1, | 112 stripAsserts = strips.indexOf('asserts') != -1, |
110 constantCompilerTask = new DartConstantTask(compiler), | 113 constantCompilerTask = new DartConstantTask(compiler), |
111 super(compiler) { | 114 super(compiler) { |
112 resolutionCallbacks = new DartResolutionCallbacks(this); | 115 resolutionCallbacks = new DartResolutionCallbacks(this); |
113 } | 116 } |
114 | 117 |
115 bool classNeedsRti(ClassElement cls) => false; | 118 bool classNeedsRti(ClassElement cls) => false; |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
222 } | 225 } |
223 | 226 |
224 final elementAsts = new Map<Element, ElementAst>(); | 227 final elementAsts = new Map<Element, ElementAst>(); |
225 | 228 |
226 ElementAst parse(AstElement element) { | 229 ElementAst parse(AstElement element) { |
227 if (!compiler.irBuilder.hasIr(element)) { | 230 if (!compiler.irBuilder.hasIr(element)) { |
228 return new ElementAst(element); | 231 return new ElementAst(element); |
229 } else { | 232 } else { |
230 cps_ir.FunctionDefinition function = compiler.irBuilder.getIr(element); | 233 cps_ir.FunctionDefinition function = compiler.irBuilder.getIr(element); |
231 // Transformations on the CPS IR. | 234 // Transformations on the CPS IR. |
232 compiler.tracer.traceCompilation(element.name, null, compiler); | 235 compiler.tracer.traceCompilation(element.name, null, compiler); |
233 new ConstantPropagator(compiler, constantSystem).rewrite(function); | 236 new ConstantPropagator(compiler, constantSystem).rewrite(function); |
234 compiler.tracer.traceGraph("Sparse constant propagation", function); | 237 compiler.tracer.traceGraph("Sparse constant propagation", function); |
235 new RedundantPhiEliminator().rewrite(function); | 238 new RedundantPhiEliminator().rewrite(function); |
236 compiler.tracer.traceGraph("Redundant phi elimination", function); | 239 compiler.tracer.traceGraph("Redundant phi elimination", function); |
237 new ShrinkingReducer().rewrite(function); | 240 new ShrinkingReducer().rewrite(function); |
238 compiler.tracer.traceGraph("Shrinking reductions", function); | 241 compiler.tracer.traceGraph("Shrinking reductions", function); |
239 // Do not rewrite the IR after variable allocation. Allocation | 242 // Do not rewrite the IR after variable allocation. Allocation |
240 // makes decisions based on an approximation of IR variable live | 243 // makes decisions based on an approximation of IR variable live |
241 // ranges that can be invalidated by transforming the IR. | 244 // ranges that can be invalidated by transforming the IR. |
242 new cps_ir.RegisterAllocator().visit(function); | 245 new cps_ir.RegisterAllocator().visit(function); |
(...skipping 16 matching lines...) Expand all Loading... |
259 compiler.tracer.traceGraph('Unshadow parameters', definition); | 262 compiler.tracer.traceGraph('Unshadow parameters', definition); |
260 | 263 |
261 TreeElementMapping treeElements = new TreeElementMapping(element); | 264 TreeElementMapping treeElements = new TreeElementMapping(element); |
262 backend_ast.Node backendAst = | 265 backend_ast.Node backendAst = |
263 backend_ast_emitter.emit(definition); | 266 backend_ast_emitter.emit(definition); |
264 Node frontend_ast = backend2frontend.emit(treeElements, backendAst); | 267 Node frontend_ast = backend2frontend.emit(treeElements, backendAst); |
265 return new ElementAst.internal(frontend_ast, treeElements); | 268 return new ElementAst.internal(frontend_ast, treeElements); |
266 } | 269 } |
267 } | 270 } |
268 | 271 |
| 272 List<LibraryElement> userLibraries = |
| 273 compiler.libraryLoader.libraries.where(isUserLibrary).toList(); |
| 274 |
269 Set<Element> topLevelElements = new Set<Element>(); | 275 Set<Element> topLevelElements = new Set<Element>(); |
270 Map<ClassElement, Set<Element>> classMembers = | 276 Map<ClassElement, Set<Element>> classMembers = |
271 new Map<ClassElement, Set<Element>>(); | 277 new Map<ClassElement, Set<Element>>(); |
272 | 278 |
273 // Build all top level elements to emit and necessary class members. | 279 // Build all top level elements to emit and necessary class members. |
274 var newTypedefElementCallback, newClassElementCallback; | 280 var newTypedefElementCallback, newClassElementCallback; |
275 | 281 |
276 void processElement(Element element, ElementAst elementAst) { | 282 void processElement(Element element, ElementAst elementAst) { |
277 ReferencedElementCollector collector = | 283 ReferencedElementCollector collector = |
278 new ReferencedElementCollector(compiler, | 284 new ReferencedElementCollector(compiler, |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
447 } | 453 } |
448 memberNodes[elementAsts[element].ast] = members; | 454 memberNodes[elementAsts[element].ast] = members; |
449 } | 455 } |
450 } | 456 } |
451 | 457 |
452 if (useMirrorHelperLibrary) { | 458 if (useMirrorHelperLibrary) { |
453 mirrorRenamer.addRenames(placeholderRenamer.renames, | 459 mirrorRenamer.addRenames(placeholderRenamer.renames, |
454 topLevelNodes, collector); | 460 topLevelNodes, collector); |
455 } | 461 } |
456 | 462 |
457 final EmitterUnparser unparser = | 463 Map<LibraryElement, String> outputPaths = new Map<LibraryElement, String>(); |
458 new EmitterUnparser(placeholderRenamer.renames, | 464 Map<LibraryElement, EmitterUnparser> unparsers = |
459 stripTypes: forceStripTypes, | 465 new Map<LibraryElement, EmitterUnparser>(); |
460 minify: compiler.enableMinification); | 466 |
461 for (LibraryElement library in placeholderRenamer.platformImports) { | 467 // The single unparser used if we collect all the output in one file. |
462 if (library.isPlatformLibrary && !library.isInternalLibrary) { | 468 EmitterUnparser mainUnparser = multiFile |
463 unparser.unparseImportTag(library.canonicalUri.toString()); | 469 ? null |
| 470 : new EmitterUnparser(placeholderRenamer.renames, |
| 471 stripTypes: forceStripTypes, |
| 472 minify: compiler.enableMinification); |
| 473 |
| 474 if (multiFile) { |
| 475 // TODO(sigurdm): Factor handling of library-paths out from emitting. |
| 476 String mainName = compiler.outputUri.pathSegments.last; |
| 477 String mainBaseName = mainName.endsWith(".dart") |
| 478 ? mainName.substring(0, mainName.length - 5) |
| 479 : mainName; |
| 480 // Map each library to a path based on the uri of the original |
| 481 // library and [compiler.outputUri]. |
| 482 Set<String> usedLibraryPaths = new Set<String>(); |
| 483 for (LibraryElement library in userLibraries) { |
| 484 if (library == compiler.mainApp) { |
| 485 outputPaths[library] = mainBaseName; |
| 486 } else { |
| 487 List<String> names = |
| 488 library.canonicalUri.pathSegments.last.split("."); |
| 489 if (names.last == "dart") { |
| 490 names = names.sublist(0, names.length - 1); |
| 491 } |
| 492 outputPaths[library] = |
| 493 "$mainBaseName.${makeUnique(names.join("."), usedLibraryPaths)}"; |
| 494 } |
| 495 } |
| 496 |
| 497 /// Rewrites imports/exports to refer to the paths given in [outputPaths]. |
| 498 for(LibraryElement outputLibrary in userLibraries) { |
| 499 EmitterUnparser unparser = new EmitterUnparser( |
| 500 placeholderRenamer.renames, |
| 501 stripTypes: forceStripTypes, |
| 502 minify: compiler.enableMinification); |
| 503 unparsers[outputLibrary] = unparser; |
| 504 LibraryName libraryName = outputLibrary.libraryTag; |
| 505 if (libraryName != null) { |
| 506 unparser.visitLibraryName(libraryName); |
| 507 } |
| 508 for (LibraryTag tag in outputLibrary.tags) { |
| 509 if (tag is! LibraryDependency) continue; |
| 510 LibraryDependency dependency = tag; |
| 511 LibraryElement libraryElement = |
| 512 outputLibrary.getLibraryFromTag(dependency); |
| 513 String uri = outputPaths.containsKey(libraryElement) |
| 514 ? "${outputPaths[libraryElement]}.dart" |
| 515 : libraryElement.canonicalUri.toString(); |
| 516 if (dependency is Import) { |
| 517 unparser.unparseImportTag(uri); |
| 518 } else { |
| 519 unparser.unparseExportTag(uri); |
| 520 } |
| 521 } |
| 522 } |
| 523 } else { |
| 524 for(LibraryElement library in placeholderRenamer.platformImports) { |
| 525 if (library.isPlatformLibrary && !library.isInternalLibrary) { |
| 526 mainUnparser.unparseImportTag(library.canonicalUri.toString()); |
| 527 } |
464 } | 528 } |
465 } | 529 } |
| 530 |
466 for (int i = 0; i < sortedTopLevels.length; i++) { | 531 for (int i = 0; i < sortedTopLevels.length; i++) { |
467 Element element = sortedTopLevels[i]; | 532 Element element = sortedTopLevels[i]; |
468 Node node = topLevelNodes[i]; | 533 Node node = topLevelNodes[i]; |
| 534 Unparser unparser = multiFile ? unparsers[element.library] : mainUnparser; |
469 if (node is ClassNode) { | 535 if (node is ClassNode) { |
470 // TODO(smok): Filter out default constructors here. | 536 // TODO(smok): Filter out default constructors here. |
471 unparser.unparseClassWithBody(node, memberNodes[node]); | 537 unparser.unparseClassWithBody(node, memberNodes[node]); |
472 } else { | 538 } else { |
473 unparser.unparse(node); | 539 unparser.unparse(node); |
474 } | 540 } |
475 unparser.newline(); | 541 unparser.newline(); |
476 } | 542 } |
477 | 543 |
478 compiler.assembledCode = unparser.result; | 544 int totalSize = 0; |
479 compiler.outputProvider("", "dart") | 545 if (multiFile) { |
480 ..add(compiler.assembledCode) | 546 for(LibraryElement outputLibrary in userLibraries) { |
481 ..close(); | 547 // TODO(sigurdm): Make the unparser output directly into the buffer inst
ead |
| 548 // of caching in `.result`. |
| 549 String code = unparsers[outputLibrary].result; |
| 550 totalSize += code.length; |
| 551 compiler.outputProvider(outputPaths[outputLibrary], "dart") |
| 552 ..add(code) |
| 553 ..close(); |
| 554 } |
| 555 // TODO(sigurdm): We should get rid of compiler.assembledCode. |
| 556 compiler.assembledCode = unparsers[compiler.mainApp].result; |
| 557 } else { |
| 558 compiler.assembledCode = mainUnparser.result; |
| 559 compiler.outputProvider("", "dart") |
| 560 ..add(compiler.assembledCode) |
| 561 ..close(); |
| 562 |
| 563 totalSize = compiler.assembledCode.length; |
| 564 } |
| 565 |
482 // Output verbose info about size ratio of resulting bundle to all | 566 // Output verbose info about size ratio of resulting bundle to all |
483 // referenced non-platform sources. | 567 // referenced non-platform sources. |
484 logResultBundleSizeInfo(topLevelElements); | 568 logResultBundleSizeInfo(topLevelElements, totalSize); |
485 } | 569 } |
486 | 570 |
487 void logResultBundleSizeInfo(Set<Element> topLevelElements) { | 571 void logResultBundleSizeInfo(Set<Element> topLevelElements, |
| 572 int totalOutputSize) { |
488 Iterable<LibraryElement> referencedLibraries = | 573 Iterable<LibraryElement> referencedLibraries = |
489 compiler.libraryLoader.libraries.where(isUserLibrary); | 574 compiler.libraryLoader.libraries.where(isUserLibrary); |
490 // Sum total size of scripts in each referenced library. | 575 // Sum total size of scripts in each referenced library. |
491 int nonPlatformSize = 0; | 576 int nonPlatformSize = 0; |
492 for (LibraryElement lib in referencedLibraries) { | 577 for (LibraryElement lib in referencedLibraries) { |
493 for (CompilationUnitElement compilationUnit in lib.compilationUnits) { | 578 for (CompilationUnitElement compilationUnit in lib.compilationUnits) { |
494 nonPlatformSize += compilationUnit.script.file.length; | 579 nonPlatformSize += compilationUnit.script.file.length; |
495 } | 580 } |
496 } | 581 } |
497 int percentage = compiler.assembledCode.length * 100 ~/ nonPlatformSize; | 582 int percentage = totalOutputSize * 100 ~/ nonPlatformSize; |
498 log('Total used non-platform files size: ${nonPlatformSize} bytes, ' | 583 log('Total used non-platform files size: ${nonPlatformSize} bytes, ' |
499 'bundle size: ${compiler.assembledCode.length} bytes (${percentage}%)'); | 584 'Output total size: $totalOutputSize bytes (${percentage}%)'); |
500 } | 585 } |
501 | 586 |
502 log(String message) => compiler.log('[DartBackend] $message'); | 587 log(String message) => compiler.log('[DartBackend] $message'); |
503 | 588 |
504 Future onLibrariesLoaded(Map<Uri, LibraryElement> loadedLibraries) { | 589 Future onLibrariesLoaded(Map<Uri, LibraryElement> loadedLibraries) { |
505 // All platform classes must be resolved to ensure that their member names | 590 // All platform classes must be resolved to ensure that their member names |
506 // are preserved. | 591 // are preserved. |
507 loadedLibraries.values.forEach((LibraryElement library) { | 592 loadedLibraries.values.forEach((LibraryElement library) { |
508 if (library.isPlatformLibrary) { | 593 if (library.isPlatformLibrary) { |
509 library.forEachLocalMember((Element element) { | 594 library.forEachLocalMember((Element element) { |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
696 } | 781 } |
697 | 782 |
698 Constant compileMetadata(MetadataAnnotation metadata, | 783 Constant compileMetadata(MetadataAnnotation metadata, |
699 Node node, | 784 Node node, |
700 TreeElements elements) { | 785 TreeElements elements) { |
701 return measure(() { | 786 return measure(() { |
702 return constantCompiler.compileMetadata(metadata, node, elements); | 787 return constantCompiler.compileMetadata(metadata, node, elements); |
703 }); | 788 }); |
704 } | 789 } |
705 } | 790 } |
OLD | NEW |