| Index: compiler/java/com/google/dart/compiler/backend/js/AbstractJsBackend.java
|
| diff --git a/compiler/java/com/google/dart/compiler/backend/js/AbstractJsBackend.java b/compiler/java/com/google/dart/compiler/backend/js/AbstractJsBackend.java
|
| deleted file mode 100644
|
| index 231c1e9b6c8349dd9244097ef6c15666a355ccc5..0000000000000000000000000000000000000000
|
| --- a/compiler/java/com/google/dart/compiler/backend/js/AbstractJsBackend.java
|
| +++ /dev/null
|
| @@ -1,518 +0,0 @@
|
| -// Copyright (c) 2011, 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.
|
| -
|
| -package com.google.dart.compiler.backend.js;
|
| -
|
| -import com.google.common.collect.ArrayListMultimap;
|
| -import com.google.common.collect.HashMultimap;
|
| -import com.google.common.collect.HashMultiset;
|
| -import com.google.common.collect.Lists;
|
| -import com.google.common.collect.Maps;
|
| -import com.google.common.collect.Multimap;
|
| -import com.google.common.collect.Multimaps;
|
| -import com.google.common.collect.Multiset;
|
| -import com.google.common.io.Closeables;
|
| -import com.google.dart.compiler.Backend;
|
| -import com.google.dart.compiler.CommandLineOptions.CompilerOptions;
|
| -import com.google.dart.compiler.DartCompilerContext;
|
| -import com.google.dart.compiler.DartSource;
|
| -import com.google.dart.compiler.ast.DartClass;
|
| -import com.google.dart.compiler.ast.DartNode;
|
| -import com.google.dart.compiler.ast.DartUnit;
|
| -import com.google.dart.compiler.ast.LibraryNode;
|
| -import com.google.dart.compiler.ast.LibraryUnit;
|
| -import com.google.dart.compiler.backend.js.ast.JsBlock;
|
| -import com.google.dart.compiler.backend.js.ast.JsProgram;
|
| -import com.google.dart.compiler.metrics.DartEventType;
|
| -import com.google.dart.compiler.metrics.Tracer.TraceEvent;
|
| -import com.google.dart.compiler.metrics.Tracer;
|
| -import com.google.dart.compiler.resolver.ClassElement;
|
| -import com.google.dart.compiler.resolver.CoreTypeProvider;
|
| -import com.google.dart.compiler.resolver.MethodElement;
|
| -import com.google.dart.compiler.type.InterfaceType;
|
| -import com.google.dart.compiler.util.DefaultTextOutput;
|
| -import com.google.dart.compiler.util.TextOutput;
|
| -
|
| -import java.io.IOException;
|
| -import java.io.Writer;
|
| -import java.security.MessageDigest;
|
| -import java.security.NoSuchAlgorithmException;
|
| -import java.util.ArrayList;
|
| -import java.util.Collection;
|
| -import java.util.Comparator;
|
| -import java.util.HashSet;
|
| -import java.util.LinkedHashMap;
|
| -import java.util.List;
|
| -import java.util.Map;
|
| -import java.util.PriorityQueue;
|
| -import java.util.Set;
|
| -
|
| -/**
|
| - * Methods common to the ClosureJsBackend and JavascriptBackend.
|
| - * @author johnlenz@google.com (John Lenz)
|
| - */
|
| -public abstract class AbstractJsBackend implements Backend {
|
| -
|
| - public static final String EXTENSION_JS = "js";
|
| - public static final String EXTENSION_APP_JS = "app.js";
|
| -
|
| - private static final String ROOT_PART_NAME = "";
|
| - private static final String STATICS_PART_NAME = "$statics$";
|
| - private static final String SEPARATOR_PART_NAME = "$seperator$";
|
| -
|
| - protected final DartMangler mangler = new DollarMangler();
|
| -
|
| - protected static class Part {
|
| - final LibraryUnit lib;
|
| - final DartUnit unit;
|
| - final String part;
|
| - final ClassElement element;
|
| - final ClassElement superElement;
|
| -
|
| - public Part(LibraryUnit lib, DartUnit unit, String part,
|
| - ClassElement element, ClassElement superElement) {
|
| - this.lib = lib;
|
| - this.unit = unit;
|
| - this.element = element;
|
| - this.part = part;
|
| - this.superElement = superElement;
|
| - }
|
| -
|
| - @Override
|
| - public int hashCode() {
|
| - if (element != null) {
|
| - return element.hashCode();
|
| - }
|
| - final int prime = 31;
|
| - int result = 1;
|
| - result = prime * result + ((part == null) ? 0 : part.hashCode());
|
| - result = prime * result + ((unit == null) ? 0 : unit.hashCode());
|
| - return result;
|
| - }
|
| -
|
| - @Override
|
| - public boolean equals(Object obj) {
|
| - if (this == obj) {
|
| - return true;
|
| - }
|
| - if (obj == null) {
|
| - return false;
|
| - }
|
| - if (getClass() != obj.getClass()) {
|
| - return false;
|
| - }
|
| - Part other = (Part) obj;
|
| - if (element != null) {
|
| - return element.equals(other.element);
|
| - }
|
| - return unit.equals(other.unit) && part.equals(other.part);
|
| - }
|
| - }
|
| -
|
| - protected static interface DepsCallback {
|
| - void visitNative(LibraryUnit libUnit, LibraryNode node) throws IOException;
|
| - void visitPart(Part part) throws IOException;
|
| - }
|
| -
|
| - protected static class DependencyBuilder {
|
| - private final List<Part> parts;
|
| - private final Part staticSeparator = new Part(null, null, SEPARATOR_PART_NAME, null, null);
|
| -
|
| - static void build(LibraryUnit libUnit, DepsCallback callback) throws IOException {
|
| - DependencyBuilder builder = new DependencyBuilder();
|
| - builder.gatherParts(libUnit);
|
| - builder.sortParts();
|
| - builder.writeParts(callback);
|
| - }
|
| -
|
| - private DependencyBuilder() {
|
| - this.parts = new ArrayList<Part>();
|
| - }
|
| -
|
| - private void gatherParts(LibraryUnit libUnit) {
|
| - gatherParts(libUnit, new HashSet<LibraryUnit>());
|
| - }
|
| -
|
| - private void gatherParts(LibraryUnit libUnit, Set<LibraryUnit> seenLibs) {
|
| - // Avoid cycles.
|
| - if (seenLibs.contains(libUnit)) {
|
| - return;
|
| - }
|
| - seenLibs.add(libUnit);
|
| -
|
| - // Visit dependencies first.
|
| - for (LibraryUnit importUnit : libUnit.getImports()) {
|
| - gatherParts(importUnit, seenLibs);
|
| - }
|
| -
|
| - for (DartUnit unit : libUnit.getUnits()) {
|
| - DartSource src = unit.getSource();
|
| - if (src != null) {
|
| - // get the list of source source parts
|
| - gatherUnitParts(libUnit, unit);
|
| - }
|
| - }
|
| - }
|
| -
|
| - private void gatherUnitParts(LibraryUnit libUnit, DartUnit unit) {
|
| - List<DartNode> nodes = ((DartUnit)unit.getNormalizedNode()).getTopLevelNodes();
|
| - for (DartNode node : nodes) {
|
| - DartNode norm = node.getNormalizedNode();
|
| - if (norm instanceof DartClass) {
|
| - DartClass clasz = (DartClass)norm;
|
| - ClassElement selfElement = clasz.getSymbol();
|
| - InterfaceType superType = selfElement.getSupertype();
|
| - ClassElement superElement = null;
|
| - if (superType != null) {
|
| - superElement = superType.getElement();
|
| - assert(superElement != null);
|
| - }
|
| -
|
| - parts.add(new Part(libUnit, unit,
|
| - clasz.getClassName(), selfElement, superElement));
|
| - }
|
| - }
|
| -
|
| - parts.add(new Part(libUnit, unit, ROOT_PART_NAME, null, null)); // top-level bits
|
| - parts.add(new Part(libUnit, unit, STATICS_PART_NAME, null, null)); // static initializer bits
|
| - }
|
| -
|
| - /**
|
| - * @param items The list of items to sort.
|
| - * @param deps A map of dependencies between items.
|
| - * @return A list of items in dependency order.
|
| - */
|
| - private static <T> List<T> topologicalStableSort(
|
| - List<T> items, Multimap<T, T> deps) {
|
| - final Map<T, Integer> originalIndex = Maps.newHashMap();
|
| - for (int i = 0; i < items.size(); i++) {
|
| - originalIndex.put(items.get(i), i);
|
| - }
|
| -
|
| - PriorityQueue<T> inDegreeZero = new PriorityQueue<T>(items.size(),
|
| - new Comparator<T>() {
|
| - @Override
|
| - public int compare(T a, T b) {
|
| - return originalIndex.get(a).intValue() -
|
| - originalIndex.get(b).intValue();
|
| - }
|
| - });
|
| - List<T> result = Lists.newArrayList();
|
| -
|
| - Multiset<T> inDegree = HashMultiset.create();
|
| - Multimap<T, T> reverseDeps = ArrayListMultimap.create();
|
| - Multimaps.invertFrom(deps, reverseDeps);
|
| -
|
| - // First, add all the inputs with in-degree 0.
|
| - for (T item : items) {
|
| - Collection<T> itemDeps = deps.get(item);
|
| - inDegree.add(item, itemDeps.size());
|
| - if (itemDeps.isEmpty()) {
|
| - inDegreeZero.add(item);
|
| - }
|
| - }
|
| -
|
| - // Then, iterate to a fixed point over the reverse dependency graph.
|
| - while (!inDegreeZero.isEmpty()) {
|
| - T item = inDegreeZero.remove();
|
| - result.add(item);
|
| - for (T inWaiting : reverseDeps.get(item)) {
|
| - inDegree.remove(inWaiting, 1);
|
| - if (inDegree.count(inWaiting) == 0) {
|
| - inDegreeZero.add(inWaiting);
|
| - }
|
| - }
|
| - }
|
| -
|
| - return result;
|
| - }
|
| -
|
| - /**
|
| - * Build a map of dependencies between Parts.
|
| - * @param parts The parts to build dependencies from.
|
| - */
|
| - private Multimap<Part, Part> buildDependencyMap(List<Part> parts) {
|
| - // Add a Part to act as separator between class initialization
|
| - // and static initialization. Statics may depend on the classes
|
| - // being properly setup.
|
| - parts.add(staticSeparator);
|
| -
|
| - final Map<ClassElement, Part> elementToPartMap = Maps.newHashMap();
|
| - for (Part part : parts) {
|
| - if (part.element != null) {
|
| - Part previous = elementToPartMap.put(part.element, part);
|
| - assert(previous == null);
|
| - }
|
| - }
|
| -
|
| - // Get the direct dependencies.
|
| - final Multimap<Part, Part> deps = HashMultimap.create();
|
| - for (Part part : parts) {
|
| - if (part.superElement != null) {
|
| - Part superPart = elementToPartMap.get(part.superElement);
|
| - assert(superPart != null);
|
| - deps.put(part, superPart);
|
| - }
|
| -
|
| - // Don't add a dependency on itself.
|
| - if (part != staticSeparator) {
|
| - if (part.part.equals(STATICS_PART_NAME)) {
|
| - // Push all statics after classes.
|
| - deps.put(part, staticSeparator);
|
| - } else {
|
| - // All classes before statics.
|
| - deps.put(staticSeparator, part);
|
| - }
|
| - }
|
| - }
|
| - return deps;
|
| - }
|
| -
|
| - /**
|
| - * Sort the parts based on their dependencies.
|
| - */
|
| - private void sortParts() {
|
| - List<Part> unsortedParts = parts;
|
| -
|
| - Multimap<Part, Part> deps = buildDependencyMap(unsortedParts);
|
| - List<Part> sortParts = topologicalStableSort(unsortedParts, deps);
|
| -
|
| - parts.clear();
|
| - parts.addAll(sortParts);
|
| - }
|
| -
|
| - private long writeParts(DepsCallback callback)
|
| - throws IOException {
|
| - long charsWritten = 0;
|
| - Set<LibraryUnit> seenLibs = new HashSet<LibraryUnit>();
|
| - for (Part part : parts) {
|
| - writePart(part, callback, seenLibs);
|
| - }
|
| - return charsWritten;
|
| - }
|
| -
|
| - private void writePart(Part part, DepsCallback callback, Set<LibraryUnit> seenLibs)
|
| - throws IOException {
|
| -
|
| - // Don't try to do anything with the fake separator part.
|
| - if (part == staticSeparator) {
|
| - return;
|
| - }
|
| -
|
| - // Avoid cycles.
|
| - if (!seenLibs.contains(part.lib)) {
|
| - seenLibs.add(part.lib);
|
| - // Prepend all native JS for this library.
|
| - for (LibraryNode node : part.lib.getNativePaths()) {
|
| - callback.visitNative(part.lib, node);
|
| - }
|
| - }
|
| -
|
| - callback.visitPart(part);
|
| - }
|
| - }
|
| -
|
| - protected Map<String, JsProgram> translateToJS(DartUnit unit, DartCompilerContext context,
|
| - CoreTypeProvider typeProvider) {
|
| - TraceEvent logEvent =
|
| - Tracer.canTrace() ? Tracer.start(DartEventType.TRANSLATE_TO_JS, "unit",
|
| - unit.getSourceName()) : null;
|
| -
|
| - try {
|
| - TraceEvent normalizeEvent =
|
| - Tracer.canTrace() ? Tracer.start(DartEventType.JS_NORMALIZE, "unit",
|
| - unit.getSourceName()) : null;
|
| - try {
|
| - // Normalize front-end AST for back-end consumption.
|
| - unit = (DartUnit) (new Normalizer()).exec(unit, typeProvider).getNormalizedNode();
|
| - } finally {
|
| - Tracer.end(normalizeEvent);
|
| - }
|
| -
|
| - // TODO(floitsch.: Make namer configurable.
|
| - JsNamer namer = new JsPrettyNamer();
|
| -
|
| - Map<String, JsProgram> parts = new LinkedHashMap<String, JsProgram>();
|
| -
|
| - List<DartNode> topNodes = unit.getTopLevelNodes();
|
| -
|
| - // Generate an id for this unit that can be used to make globally unique
|
| - // identifiers.
|
| - String baseUnitId = generateBaseUnitId(unit);
|
| - int partIndex = 0;
|
| -
|
| - // Translate the AST to JS.
|
| - JsProgram nonClassStatements = new JsProgram(baseUnitId + partIndex++);
|
| - GenerateJavascriptAST nonClassGenerator = null;
|
| - TranslationContext nonClassTranslationContext = null;
|
| -
|
| - JsProgram staticInitStatements = new JsProgram(baseUnitId + partIndex++);
|
| - JsBlock staticInitBlock = staticInitStatements.getGlobalBlock();
|
| -
|
| - for (DartNode node : topNodes) {
|
| - node = node.getNormalizedNode();
|
| - if (node instanceof DartClass) {
|
| - // TODO: Don't write out *.js for interfaces -- there are a lot of them
|
| - TraceEvent nodeEvent =
|
| - Tracer.canTrace() ? Tracer.start(DartEventType.TRANSLATE_NODE, "unit",
|
| - unit.getSourceName(), "node", node.getSymbol().getOriginalSymbolName()) : null;
|
| - try {
|
| - // Translate the AST to JS.
|
| - JsProgram program = new JsProgram(baseUnitId + partIndex++);
|
| -
|
| - TranslationContext translationContext = TranslationContext.createContext(unit, program,
|
| - mangler, node);
|
| -
|
| - // Generate the Javascript AST.
|
| - GenerateJavascriptAST generator =
|
| - new GenerateJavascriptAST(unit, typeProvider, context);
|
| - generator.translateNode(translationContext, node, staticInitBlock);
|
| -
|
| - TraceEvent namerEvent =
|
| - Tracer.canTrace() ? Tracer.start(DartEventType.NAMER, "unit",
|
| - unit.getSourceName()) : null;
|
| - try {
|
| - namer.exec(program);
|
| - } finally {
|
| - Tracer.end(namerEvent);
|
| - }
|
| -
|
| - parts.put(((DartClass) node).getClassName(), program);
|
| - } finally {
|
| - Tracer.end(nodeEvent);
|
| - }
|
| - } else {
|
| -
|
| - if (nonClassGenerator == null) {
|
| - // This block generates the AST used to generate for all non-class nodes at once
|
| - // and is saved for subsequent iterations.
|
| - TraceEvent genInitEvent =
|
| - Tracer.canTrace() ? Tracer.start(DartEventType.GEN_AST_INIT, "unit",
|
| - unit.getSourceName()) : null;
|
| - try {
|
| - nonClassTranslationContext = TranslationContext.createContext(unit,
|
| - nonClassStatements, mangler, null);
|
| - nonClassGenerator = new GenerateJavascriptAST(unit, typeProvider, context);
|
| - } finally {
|
| - Tracer.end(genInitEvent);
|
| - }
|
| - }
|
| -
|
| - nonClassGenerator.translateNode(nonClassTranslationContext, node, staticInitBlock);
|
| - }
|
| - }
|
| -
|
| - TraceEvent namerEvent =
|
| - Tracer.canTrace() ? Tracer.start(DartEventType.NAMER, "unit", unit.getSourceName())
|
| - : null;
|
| - try {
|
| - namer.exec(nonClassStatements);
|
| - } finally {
|
| - Tracer.end(namerEvent);
|
| - }
|
| -
|
| - // Out-of-date checks rely on the root JS file existing, even if it is empty
|
| - parts.put(ROOT_PART_NAME, nonClassStatements);
|
| -
|
| - // Only add static parts if they are not empty
|
| - for (int i = 0; i < staticInitStatements.getFragmentCount(); ++i) {
|
| - if (!staticInitStatements.getFragmentBlock(i).getStatements().isEmpty()) {
|
| - parts.put(STATICS_PART_NAME, staticInitStatements);
|
| - break;
|
| - }
|
| - }
|
| -
|
| - return parts;
|
| - } finally {
|
| - Tracer.end(logEvent);
|
| - }
|
| - }
|
| -
|
| - private static String generateBaseUnitId(DartUnit unit) {
|
| - MessageDigest md;
|
| - try {
|
| - md = MessageDigest.getInstance("MD5");
|
| - } catch (NoSuchAlgorithmException e) {
|
| - throw new AssertionError("Could not find MD5 digest");
|
| - }
|
| - StringBuilder sb = new StringBuilder();
|
| - byte[] md5 = md.digest(unit.getSource().getUri().toString().getBytes());
|
| - // Only use the first 6 hex characters of the md5.
|
| - for (int i = 0; i < 3; i++) {
|
| - sb.append(Integer.toHexString((md5[i] & 0xf0) >> 4));
|
| - sb.append(Integer.toHexString(md5[i] & 0xf));
|
| - }
|
| -
|
| - return sb.toString();
|
| - }
|
| -
|
| - protected int writeEntryPointCall(String entry, Writer out) throws IOException {
|
| - // Emit entry point call.
|
| - // TODO: Actually validate that this method exists.
|
| - // Small hack: the V8 arguments object is not an instance of Array. [].concat(arguments)
|
| - // copies the elements of the arguments and returns a proper array.
|
| - // However in Rhino this operation simply creates an array with 'arguments' as the first (and
|
| - // only) element. By calling "arguments.slice()" on it, a new array is returned, and the
|
| - // concatenation works again.
|
| - // TODO: Use a more robust check to test that the argument is
|
| - // array.
|
| - String entryPointCall = "RunEntry(" + entry + ", this.arguments ?" +
|
| - " (this.arguments.slice ? [].concat(this.arguments.slice())" +
|
| - " : this.arguments) : []);";
|
| - out.write(entryPointCall);
|
| - return entryPointCall.length();
|
| - }
|
| -
|
| - protected String getMangledEntryPoint(DartCompilerContext context) {
|
| - MethodElement entry = context.getApplicationUnit().getElement().getEntryPoint();
|
| - if (entry == null) {
|
| - return null;
|
| - }
|
| -
|
| - return mangler.mangleEntryPoint(entry, context.getApplicationUnit().getElement());
|
| - }
|
| -
|
| - @Override
|
| - public boolean isOutOfDate(DartSource src, DartCompilerContext context) {
|
| - return context.isOutOfDate(src, src, EXTENSION_JS);
|
| - }
|
| -
|
| - @Override
|
| - public void compileUnit(DartUnit unit, DartSource src, DartCompilerContext context,
|
| - CoreTypeProvider typeProvider) throws IOException {
|
| - // Translate the AST to JS.
|
| - Map<String, JsProgram> parts = translateToJS(unit, context, typeProvider);
|
| - String srcName = src.getName();
|
| -
|
| - for (Map.Entry<String, JsProgram> entry : parts.entrySet()) {
|
| - // Generate Javascript output.
|
| - TextOutput out = new DefaultTextOutput(false);
|
| - JsToStringGenerationVisitor srcGenerator;
|
| - String name = entry.getKey();
|
| - boolean failed = true;
|
| - Writer w;
|
| -
|
| - JsProgram program = entry.getValue();
|
| - JsBlock globalBlock = program.getGlobalBlock();
|
| -
|
| - TraceEvent srcEvent =
|
| - Tracer.canTrace() ? Tracer.start(DartEventType.JS_SOURCE_GEN, "src", srcName, "name",
|
| - name) : null;
|
| - try {
|
| - srcGenerator = new JsSourceGenerationVisitor(out);
|
| -
|
| - srcGenerator.accept(globalBlock);
|
| - w = context.getArtifactWriter(src, name, EXTENSION_JS);
|
| - try {
|
| - w.write(out.toString());
|
| - failed = false;
|
| - } finally {
|
| - Closeables.close(w, failed);
|
| - }
|
| - } finally {
|
| - Tracer.end(srcEvent);
|
| - }
|
| - }
|
| - }
|
| -}
|
|
|