| Index: pkg/compiler/lib/src/dart_backend/backend.dart
|
| diff --git a/pkg/compiler/lib/src/dart_backend/backend.dart b/pkg/compiler/lib/src/dart_backend/backend.dart
|
| deleted file mode 100644
|
| index c9d69aeb74244d61af08ad51d96682fd2ced14cd..0000000000000000000000000000000000000000
|
| --- a/pkg/compiler/lib/src/dart_backend/backend.dart
|
| +++ /dev/null
|
| @@ -1,546 +0,0 @@
|
| -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -part of dart_backend;
|
| -
|
| -// TODO(ahe): This class is simply wrong. This backend should use
|
| -// elements when it can, not AST nodes. Perhaps a [Map<Element,
|
| -// TreeElements>] is what is needed.
|
| -class ElementAst {
|
| - final Node ast;
|
| - final TreeElements treeElements;
|
| -
|
| - ElementAst(this.ast, this.treeElements);
|
| -}
|
| -
|
| -class DartBackend extends Backend {
|
| - final List<CompilerTask> tasks;
|
| - final bool stripAsserts;
|
| -
|
| - bool get supportsReflection => true;
|
| -
|
| - // TODO(zarah) Maybe change this to a command-line option.
|
| - // Right now, it is set by the tests.
|
| - bool useMirrorHelperLibrary = false;
|
| -
|
| - /// Updated to a [MirrorRenamerImpl] instance if the [useMirrorHelperLibrary]
|
| - /// field is set and mirror are needed.
|
| - MirrorRenamer mirrorRenamer = const MirrorRenamer();
|
| -
|
| - final DartOutputter outputter;
|
| -
|
| - // Used in test.
|
| - PlaceholderRenamer get placeholderRenamer => outputter.renamer;
|
| - Map<ClassNode, List<Node>> get memberNodes => outputter.output.memberNodes;
|
| -
|
| - ConstantSystem get constantSystem {
|
| - return constantCompilerTask.constantCompiler.constantSystem;
|
| - }
|
| -
|
| - BackendConstantEnvironment get constants => constantCompilerTask;
|
| -
|
| - DartConstantTask constantCompilerTask;
|
| -
|
| - DartImpactTransformer impactTransformer;
|
| -
|
| - final Set<ClassElement> usedTypeLiterals = new Set<ClassElement>();
|
| -
|
| - /// The set of visible platform classes that are implemented by instantiated
|
| - /// user classes.
|
| - final Set<ClassElement> _userImplementedPlatformClasses =
|
| - new Set<ClassElement>();
|
| -
|
| - bool enableCodegenWithErrorsIfSupported(Spannable node) {
|
| - reporter.reportHintMessage(node, MessageKind.GENERIC, {
|
| - 'text': "Generation of code with compile time errors is not "
|
| - "supported for dart2dart."
|
| - });
|
| - return false;
|
| - }
|
| -
|
| - /**
|
| - * Tells whether it is safe to remove type declarations from variables,
|
| - * functions parameters. It becomes not safe if:
|
| - * 1) TypeError is used somewhere in the code,
|
| - * 2) The code has typedefs in right hand side of IS checks,
|
| - * 3) The code has classes which extend typedefs, have type arguments typedefs
|
| - * or type variable bounds typedefs.
|
| - * These restrictions can be less strict.
|
| - */
|
| - bool isSafeToRemoveTypeDeclarations(
|
| - Map<ClassElement, Iterable<Element>> classMembers) {
|
| - ClassElement typeErrorElement = compiler.coreLibrary.find('TypeError');
|
| - if (classMembers.containsKey(typeErrorElement) ||
|
| - compiler.resolverWorld.isChecks
|
| - .any((DartType type) => type.element == typeErrorElement)) {
|
| - return false;
|
| - }
|
| - Set<DartType> processedTypes = new Set<DartType>();
|
| - List<DartType> workQueue = new List<DartType>();
|
| - workQueue
|
| - .addAll(classMembers.keys.map((classElement) => classElement.thisType));
|
| - workQueue.addAll(compiler.resolverWorld.isChecks);
|
| -
|
| - while (!workQueue.isEmpty) {
|
| - DartType type = workQueue.removeLast();
|
| - if (processedTypes.contains(type)) continue;
|
| - processedTypes.add(type);
|
| - if (type is FunctionType) return false;
|
| - if (type is TypedefType) return false;
|
| - if (type is InterfaceType) {
|
| - InterfaceType interfaceType = type;
|
| - // Check all type arguments.
|
| - interfaceType.typeArguments.forEach(workQueue.add);
|
| - ClassElement element = type.element;
|
| - // Check all supertypes.
|
| - if (element.allSupertypes != null) {
|
| - element.allSupertypes.forEach(workQueue.add);
|
| - }
|
| - }
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - DartBackend(Compiler compiler, List<String> strips, {bool multiFile})
|
| - : tasks = <CompilerTask>[],
|
| - stripAsserts = strips.indexOf('asserts') != -1,
|
| - constantCompilerTask = new DartConstantTask(compiler),
|
| - outputter = new DartOutputter(
|
| - compiler.reporter, compiler.outputProvider,
|
| - forceStripTypes: strips.indexOf('types') != -1,
|
| - multiFile: multiFile,
|
| - enableMinification: compiler.options.enableMinification),
|
| - super(compiler) {
|
| - impactTransformer = new DartImpactTransformer(this);
|
| - }
|
| -
|
| - DiagnosticReporter get reporter => compiler.reporter;
|
| -
|
| - Resolution get resolution => compiler.resolution;
|
| -
|
| - bool classNeedsRti(ClassElement cls) => false;
|
| - bool methodNeedsRti(FunctionElement function) => false;
|
| -
|
| - void enqueueHelpers(ResolutionEnqueuer world, Registry registry) {
|
| - // Right now resolver doesn't always resolve interfaces needed
|
| - // for literals, so force them. TODO(antonm): fix in the resolver.
|
| - final LITERAL_TYPE_NAMES = const [
|
| - 'Map',
|
| - 'List',
|
| - 'num',
|
| - 'int',
|
| - 'double',
|
| - 'bool'
|
| - ];
|
| - final coreLibrary = compiler.coreLibrary;
|
| - for (final name in LITERAL_TYPE_NAMES) {
|
| - ClassElement classElement = coreLibrary.findLocal(name);
|
| - classElement.ensureResolved(resolution);
|
| - }
|
| - // Enqueue the methods that the VM might invoke on user objects because
|
| - // we don't trust the resolution to always get these included.
|
| - world.registerDynamicUse(new DynamicUse(Selectors.toString_, null));
|
| - world.registerDynamicUse(new DynamicUse(Selectors.hashCode_, null));
|
| - world.registerDynamicUse(
|
| - new DynamicUse(new Selector.binaryOperator('=='), null));
|
| - world.registerDynamicUse(new DynamicUse(Selectors.compareTo, null));
|
| - }
|
| -
|
| - WorldImpact codegen(CodegenWorkItem work) {
|
| - return const WorldImpact();
|
| - }
|
| -
|
| - /**
|
| - * Tells whether we should output given element. Corelib classes like
|
| - * Object should not be in the resulting code.
|
| - */
|
| - @override
|
| - bool shouldOutput(Element element) {
|
| - return (!element.library.isPlatformLibrary &&
|
| - !element.isSynthesized &&
|
| - element is! AbstractFieldElement) ||
|
| - mirrorRenamer.isMirrorHelperLibrary(element.library);
|
| - }
|
| -
|
| - int assembleProgram() {
|
| - ElementAst computeElementAst(AstElement element) {
|
| - return new ElementAst(
|
| - element.resolvedAst.node, element.resolvedAst.elements);
|
| - }
|
| -
|
| - // TODO(johnniwinther): Remove the need for this method.
|
| - void postProcessElementAst(AstElement element, ElementAst elementAst,
|
| - newTypedefElementCallback, newClassElementCallback) {
|
| - ReferencedElementCollector collector = new ReferencedElementCollector(
|
| - reporter,
|
| - element,
|
| - elementAst,
|
| - newTypedefElementCallback,
|
| - newClassElementCallback);
|
| - collector.collect();
|
| - }
|
| -
|
| - int totalSize = outputter.assembleProgram(
|
| - libraries: compiler.libraryLoader.libraries,
|
| - instantiatedClasses: compiler.resolverWorld.directlyInstantiatedClasses,
|
| - resolvedElements: compiler.enqueuer.resolution.processedElements,
|
| - usedTypeLiterals: usedTypeLiterals,
|
| - postProcessElementAst: postProcessElementAst,
|
| - computeElementAst: computeElementAst,
|
| - shouldOutput: shouldOutput,
|
| - isSafeToRemoveTypeDeclarations: isSafeToRemoveTypeDeclarations,
|
| - sortElements: Elements.sortedByPosition,
|
| - mirrorRenamer: mirrorRenamer,
|
| - mainFunction: compiler.mainFunction,
|
| - outputUri: compiler.options.outputUri);
|
| -
|
| - // Output verbose info about size ratio of resulting bundle to all
|
| - // referenced non-platform sources.
|
| - logResultBundleSizeInfo(outputter.libraryInfo.userLibraries,
|
| - outputter.elementInfo.topLevelElements, totalSize);
|
| -
|
| - return totalSize;
|
| - }
|
| -
|
| - void logResultBundleSizeInfo(Iterable<LibraryElement> userLibraries,
|
| - Iterable<Element> topLevelElements, int totalOutputSize) {
|
| - // Sum total size of scripts in each referenced library.
|
| - int nonPlatformSize = 0;
|
| - for (LibraryElement lib in userLibraries) {
|
| - for (CompilationUnitElement compilationUnit in lib.compilationUnits) {
|
| - nonPlatformSize += compilationUnit.script.file.length;
|
| - }
|
| - }
|
| - int percentage = totalOutputSize * 100 ~/ nonPlatformSize;
|
| - log('Total used non-platform files size: ${nonPlatformSize} bytes, '
|
| - 'Output total size: $totalOutputSize bytes (${percentage}%)');
|
| - }
|
| -
|
| - log(String message) => reporter.log('[DartBackend] $message');
|
| -
|
| - @override
|
| - Future onLibrariesLoaded(LoadedLibraries loadedLibraries) {
|
| - // All platform classes must be resolved to ensure that their member names
|
| - // are preserved.
|
| - loadedLibraries.forEachLibrary((LibraryElement library) {
|
| - if (library.isPlatformLibrary) {
|
| - library.forEachLocalMember((Element element) {
|
| - if (element.isClass) {
|
| - ClassElement classElement = element;
|
| - classElement.ensureResolved(resolution);
|
| - }
|
| - });
|
| - }
|
| - });
|
| - if (useMirrorHelperLibrary &&
|
| - loadedLibraries.containsLibrary(Uris.dart_mirrors)) {
|
| - return compiler.libraryLoader
|
| - .loadLibrary(compiler.resolvedUriTranslator.translate(
|
| - loadedLibraries.getLibrary(Uris.dart_mirrors),
|
| - MirrorRenamerImpl.DART_MIRROR_HELPER,
|
| - null))
|
| - .then((LibraryElement library) {
|
| - mirrorRenamer = new MirrorRenamerImpl(compiler, this, library);
|
| - });
|
| - }
|
| - return new Future.value();
|
| - }
|
| -
|
| - @override
|
| - void registerStaticUse(Element element, Enqueuer enqueuer) {
|
| - if (element == compiler.mirrorSystemGetNameFunction) {
|
| - FunctionElement getNameFunction = mirrorRenamer.getNameFunction;
|
| - if (getNameFunction != null) {
|
| - enqueuer.addToWorkList(getNameFunction);
|
| - }
|
| - }
|
| - }
|
| -
|
| - @override
|
| - void registerInstantiatedType(
|
| - InterfaceType type, Enqueuer enqueuer, Registry registry,
|
| - {bool mirrorUsage: false}) {
|
| - registerPlatformMembers(type, registerUse: registry.registerDynamicUse);
|
| - super.registerInstantiatedType(type, enqueuer, registry,
|
| - mirrorUsage: mirrorUsage);
|
| - }
|
| -
|
| - /// Register dynamic access of members of [type] that implement members
|
| - /// of types defined in the platform libraries.
|
| - void registerPlatformMembers(InterfaceType type,
|
| - {void registerUse(DynamicUse dynamicUse)}) {
|
| - // Without patching, dart2dart has no way of performing sound tree-shaking
|
| - // in face external functions. Therefore we employ another scheme:
|
| - //
|
| - // Based on the assumption that the platform code only relies on the
|
| - // interfaces of it's own classes, we can approximate the semantics of
|
| - // external functions by eagerly registering dynamic invocation of instance
|
| - // members defined the platform interfaces.
|
| - //
|
| - // Since we only need to generate code for non-platform classes we can
|
| - // restrict this registration to platform interfaces implemented by
|
| - // instantiated non-platform classes.
|
| - //
|
| - // Consider for instance this program:
|
| - //
|
| - // import 'dart:math' show Random;
|
| - //
|
| - // class MyRandom implements Random {
|
| - // int nextInt() => 0;
|
| - // }
|
| - //
|
| - // main() {
|
| - // print([0, 1, 2].shuffle(new MyRandom()));
|
| - // }
|
| - //
|
| - // Here `MyRandom` is a subtype if `Random` defined in 'dart:math'. By the
|
| - // assumption, all methods defined `Random` are potentially called, and
|
| - // therefore, though there are no visible call sites from the user node,
|
| - // dynamic invocation of for instance `nextInt` should be registered. In
|
| - // this case, `nextInt` is actually called by the standard implementation of
|
| - // `shuffle`.
|
| -
|
| - ClassElement cls = type.element;
|
| - if (!cls.library.isPlatformLibrary) {
|
| - for (Link<DartType> link = cls.allSupertypes;
|
| - !link.isEmpty;
|
| - link = link.tail) {
|
| - InterfaceType supertype = link.head;
|
| - ClassElement superclass = supertype.element;
|
| - LibraryElement library = superclass.library;
|
| - if (library.isPlatformLibrary) {
|
| - if (_userImplementedPlatformClasses.add(superclass)) {
|
| - // Register selectors for all instance methods since these might
|
| - // be called on user classes from within the platform
|
| - // implementation.
|
| - superclass.forEachLocalMember((MemberElement element) {
|
| - if (element.isConstructor || element.isStatic) return;
|
| -
|
| - element.computeType(resolution);
|
| - Selector selector = new Selector.fromElement(element);
|
| - registerUse(new DynamicUse(selector, null));
|
| - });
|
| - }
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - @override
|
| - bool enableDeferredLoadingIfSupported(Spannable node, Registry registry) {
|
| - // TODO(sigurdm): Implement deferred loading for dart2dart.
|
| - reporter.reportWarningMessage(
|
| - node, MessageKind.DEFERRED_LIBRARY_DART_2_DART);
|
| - return false;
|
| - }
|
| -
|
| - @override
|
| - Uri resolvePatchUri(String libraryName, Uri) {
|
| - // Dart2dart does not use patches.
|
| - return null;
|
| - }
|
| -}
|
| -
|
| -class DartImpactTransformer extends ImpactTransformer {
|
| - final DartBackend backend;
|
| -
|
| - DartImpactTransformer(this.backend);
|
| -
|
| - @override
|
| - WorldImpact transformResolutionImpact(ResolutionImpact worldImpact) {
|
| - TransformedWorldImpact transformed =
|
| - new TransformedWorldImpact(worldImpact);
|
| - for (TypeUse typeUse in worldImpact.typeUses) {
|
| - if (typeUse.kind == TypeUseKind.TYPE_LITERAL &&
|
| - typeUse.type.isInterfaceType) {
|
| - backend.usedTypeLiterals.add(typeUse.type.element);
|
| - }
|
| - if (typeUse.kind == TypeUseKind.INSTANTIATION) {
|
| - backend.registerPlatformMembers(typeUse.type,
|
| - registerUse: transformed.registerDynamicUse);
|
| - }
|
| - }
|
| - return transformed;
|
| - }
|
| -}
|
| -
|
| -class EmitterUnparser extends Unparser {
|
| - final Map<Node, String> renames;
|
| -
|
| - EmitterUnparser(this.renames, {bool minify, bool stripTypes})
|
| - : super(minify: minify, stripTypes: stripTypes);
|
| -
|
| - visit(Node node) {
|
| - if (node != null && renames.containsKey(node)) {
|
| - write(renames[node]);
|
| - } else {
|
| - super.visit(node);
|
| - }
|
| - }
|
| -
|
| - unparseSendReceiver(Send node, {bool spacesNeeded: false}) {
|
| - // TODO(smok): Remove ugly hack for library prefices.
|
| - if (node.receiver != null && renames[node.receiver] == '') return;
|
| - super.unparseSendReceiver(node, spacesNeeded: spacesNeeded);
|
| - }
|
| -
|
| - unparseFunctionName(Node name) {
|
| - if (name != null && renames.containsKey(name)) {
|
| - write(renames[name]);
|
| - } else {
|
| - super.unparseFunctionName(name);
|
| - }
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Some elements are not recorded by resolver now,
|
| - * for example, typedefs or classes which are only
|
| - * used in signatures, as/is operators or in super clauses
|
| - * (just to name a few). Retraverse AST to pick those up.
|
| - */
|
| -class ReferencedElementCollector extends Visitor {
|
| - final DiagnosticReporter reporter;
|
| - final Element element;
|
| - final ElementAst elementAst;
|
| - final newTypedefElementCallback;
|
| - final newClassElementCallback;
|
| -
|
| - ReferencedElementCollector(this.reporter, this.element, this.elementAst,
|
| - this.newTypedefElementCallback, this.newClassElementCallback);
|
| -
|
| - visitNode(Node node) {
|
| - node.visitChildren(this);
|
| - }
|
| -
|
| - visitTypeAnnotation(TypeAnnotation typeAnnotation) {
|
| - TreeElements treeElements = elementAst.treeElements;
|
| - final DartType type = treeElements.getType(typeAnnotation);
|
| - assert(invariant(typeAnnotation, type != null,
|
| - message: "Missing type for type annotation: $treeElements."));
|
| - if (type.isTypedef) newTypedefElementCallback(type.element);
|
| - if (type.isInterfaceType) newClassElementCallback(type.element);
|
| - typeAnnotation.visitChildren(this);
|
| - }
|
| -
|
| - void collect() {
|
| - reporter.withCurrentElement(element, () {
|
| - elementAst.ast.accept(this);
|
| - });
|
| - }
|
| -}
|
| -
|
| -Comparator compareBy(f) => (x, y) => f(x).compareTo(f(y));
|
| -
|
| -List sorted(Iterable l, comparison) {
|
| - final result = new List.from(l);
|
| - result.sort(comparison);
|
| - return result;
|
| -}
|
| -
|
| -compareElements(e0, e1) {
|
| - int result = compareBy((e) => e.library.canonicalUri.toString())(e0, e1);
|
| - if (result != 0) return result;
|
| - return compareBy((e) => e.position.charOffset)(e0, e1);
|
| -}
|
| -
|
| -/// [ConstantCompilerTask] for compilation of constants for the Dart backend.
|
| -///
|
| -/// Since this task needs no distinction between frontend and backend constants
|
| -/// it also serves as the [BackendConstantEnvironment].
|
| -class DartConstantTask extends ConstantCompilerTask
|
| - implements BackendConstantEnvironment {
|
| - final DartConstantCompiler constantCompiler;
|
| -
|
| - DartConstantTask(Compiler compiler)
|
| - : this.constantCompiler = new DartConstantCompiler(compiler),
|
| - super(compiler.measurer);
|
| -
|
| - String get name => 'ConstantHandler';
|
| -
|
| - @override
|
| - ConstantSystem get constantSystem => constantCompiler.constantSystem;
|
| -
|
| - @override
|
| - bool hasConstantValue(ConstantExpression expression) {
|
| - return constantCompiler.hasConstantValue(expression);
|
| - }
|
| -
|
| - @override
|
| - ConstantValue getConstantValue(ConstantExpression expression) {
|
| - return constantCompiler.getConstantValue(expression);
|
| - }
|
| -
|
| - @override
|
| - ConstantValue getConstantValueForVariable(VariableElement element) {
|
| - return constantCompiler.getConstantValueForVariable(element);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression getConstantForNode(Node node, TreeElements elements) {
|
| - return constantCompiler.getConstantForNode(node, elements);
|
| - }
|
| -
|
| - @override
|
| - ConstantValue getConstantValueForNode(Node node, TreeElements elements) {
|
| - return getConstantValue(
|
| - constantCompiler.getConstantForNode(node, elements));
|
| - }
|
| -
|
| - @override
|
| - ConstantValue getConstantValueForMetadata(MetadataAnnotation metadata) {
|
| - return getConstantValue(metadata.constant);
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression compileConstant(VariableElement element) {
|
| - return measure(() {
|
| - return constantCompiler.compileConstant(element);
|
| - });
|
| - }
|
| -
|
| - @override
|
| - void evaluate(ConstantExpression constant) {
|
| - return measure(() {
|
| - return constantCompiler.evaluate(constant);
|
| - });
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression compileVariable(VariableElement element) {
|
| - return measure(() {
|
| - return constantCompiler.compileVariable(element);
|
| - });
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression compileNode(Node node, TreeElements elements,
|
| - {bool enforceConst: true}) {
|
| - return measure(() {
|
| - return constantCompiler.compileNodeWithDefinitions(node, elements,
|
| - isConst: enforceConst);
|
| - });
|
| - }
|
| -
|
| - @override
|
| - ConstantExpression compileMetadata(
|
| - MetadataAnnotation metadata, Node node, TreeElements elements) {
|
| - return measure(() {
|
| - return constantCompiler.compileMetadata(metadata, node, elements);
|
| - });
|
| - }
|
| -
|
| - // TODO(johnniwinther): Remove this when values are computed from the
|
| - // expressions.
|
| - @override
|
| - void copyConstantValues(DartConstantTask task) {
|
| - constantCompiler.constantValueMap
|
| - .addAll(task.constantCompiler.constantValueMap);
|
| - }
|
| -
|
| - @override
|
| - void registerLazyStatic(FieldElement element) {
|
| - // Do nothing.
|
| - }
|
| -}
|
|
|