JavaAstConstructor uses UnifyAst.
http://gwt-code-reviews.appspot.com/1453810/
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10312 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/AstConstructor.java b/dev/core/src/com/google/gwt/dev/jjs/AstConstructor.java
new file mode 100644
index 0000000..4b4c7f7
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/AstConstructor.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.jjs;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.javac.CompilationState;
+import com.google.gwt.dev.javac.StandardGeneratorContext;
+import com.google.gwt.dev.jdt.RebindPermutationOracle;
+import com.google.gwt.dev.jjs.CorrelationFactory.DummyCorrelationFactory;
+import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.impl.AssertionNormalizer;
+import com.google.gwt.dev.jjs.impl.AssertionRemover;
+import com.google.gwt.dev.jjs.impl.FixAssignmentToUnbox;
+import com.google.gwt.dev.jjs.impl.GwtAstBuilder;
+import com.google.gwt.dev.jjs.impl.ImplementClassLiteralsAsFields;
+import com.google.gwt.dev.jjs.impl.ReplaceRunAsyncs;
+import com.google.gwt.dev.jjs.impl.UnifyAst;
+import com.google.gwt.dev.js.ast.JsProgram;
+
+/**
+ * Constructs a full Java AST from source.
+ */
+public class AstConstructor {
+
+ /**
+ * Construct an simple AST representing an entire {@link CompilationState}.
+ * Does not support deferred binding. Implementation mostly copied from
+ * {@link JavaToJavaScriptCompiler}.
+ */
+ public static JProgram construct(TreeLogger logger, final CompilationState state,
+ JJSOptions options) throws UnableToCompleteException {
+
+ InternalCompilerException.preload();
+
+ RebindPermutationOracle rpo = new RebindPermutationOracle() {
+ @Override
+ public void clear() {
+ }
+
+ @Override
+ public String[] getAllPossibleRebindAnswers(TreeLogger logger, String sourceTypeName)
+ throws UnableToCompleteException {
+ return new String[0];
+ }
+
+ public CompilationState getCompilationState() {
+ return state;
+ }
+
+ public StandardGeneratorContext getGeneratorContext() {
+ return null;
+ }
+ };
+
+ JProgram jprogram = new JProgram(DummyCorrelationFactory.INSTANCE);
+ JsProgram jsProgram = new JsProgram(DummyCorrelationFactory.INSTANCE);
+ assert GwtAstBuilder.ENABLED;
+ UnifyAst unifyAst = new UnifyAst(jprogram, jsProgram, options, rpo);
+ unifyAst.buildEverything(logger);
+
+ // Compute all super type/sub type info
+ jprogram.typeOracle.computeBeforeAST();
+
+ // (3) Perform Java AST normalizations.
+ FixAssignmentToUnbox.exec(jprogram);
+
+ /*
+ * TODO: If we defer this until later, we could maybe use the results of the
+ * assertions to enable more optimizations.
+ */
+ if (options.isEnableAssertions()) {
+ // Turn into assertion checking calls.
+ AssertionNormalizer.exec(jprogram);
+ } else {
+ // Remove all assert statements.
+ AssertionRemover.exec(jprogram);
+ }
+
+ if (options.isRunAsyncEnabled()) {
+ ReplaceRunAsyncs.exec(logger, jprogram);
+ }
+
+ ImplementClassLiteralsAsFields.exec(jprogram);
+ return jprogram;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
index e7b17f1..7d0957b 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
@@ -2902,6 +2902,13 @@
return result;
}
+ SourceInfo makeSourceInfo(AbstractMethodDeclaration x) {
+ int startLine =
+ Util.getLineNumber(x.sourceStart, curCud.separatorPositions, 0,
+ curCud.separatorPositions.length - 1);
+ return SourceOrigin.create(x.sourceStart, x.bodyEnd, startLine, curCud.fileName);
+ }
+
SourceInfo makeSourceInfo(ASTNode x) {
int startLine =
Util.getLineNumber(x.sourceStart, curCud.separatorPositions, 0,
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java
index af0afd8..7d50f49 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java
@@ -37,6 +37,7 @@
import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -172,9 +173,14 @@
}
if (matches.size() > 1) {
TreeLogger branch = error(info, "Multiple runAsync calls are named " + name);
+ List<String> errors = new ArrayList<String>();
for (JRunAsync match : matches) {
- branch.log(TreeLogger.ERROR, "One call is at '" + match.getSourceInfo().getFileName()
- + ':' + match.getSourceInfo().getStartLine() + "'");
+ errors.add("One call is at '" + match.getSourceInfo().getFileName() + ':'
+ + match.getSourceInfo().getStartLine() + "'");
+ }
+ Collections.sort(errors);
+ for (String error : errors) {
+ branch.log(TreeLogger.ERROR, error);
}
return;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java b/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
index 0ebe6e8..b29358a 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
@@ -71,6 +71,7 @@
import com.google.gwt.dev.js.ast.JsRootScope;
import com.google.gwt.dev.util.JsniRef;
import com.google.gwt.dev.util.Name.BinaryName;
+import com.google.gwt.dev.util.Name.InternalName;
import com.google.gwt.dev.util.collect.IdentityHashSet;
import com.google.gwt.dev.util.collect.Lists;
@@ -461,6 +462,7 @@
CLASS_IS_CLASS_METADATA_ENABLED));
private final Map<String, CompiledClass> classFileMap;
+ private boolean errorsFound = false;
private final Map<String, JField> fieldMap = new HashMap<String, JField>();
/**
@@ -521,7 +523,41 @@
}
}
- public void exec(TreeLogger logger) {
+ /**
+ * Special AST construction, useful for tests. Everything is resolved,
+ * translated, and unified.
+ */
+ public void buildEverything(TreeLogger logger) throws UnableToCompleteException {
+ this.logger = logger;
+ for (String internalName : classFileMap.keySet()) {
+ String typeName = InternalName.toBinaryName(internalName);
+ searchForType(typeName);
+ }
+
+ for (JDeclaredType type : program.getDeclaredTypes()) {
+ instantiate(type);
+ for (JField field : type.getFields()) {
+ flowInto(field);
+ }
+ for (JMethod method : type.getMethods()) {
+ flowInto(method);
+ }
+ }
+
+ mainLoop();
+
+ computeOverrides();
+ if (errorsFound) {
+ throw new UnableToCompleteException();
+ }
+ }
+
+ /**
+ * For normal compilation, only translate and stitch types reachable from
+ * entry points. This reduces memory and improves compile speed. Any
+ * unreachable elements are pruned.
+ */
+ public void exec(TreeLogger logger) throws UnableToCompleteException {
this.logger = logger;
// Trace execution from entry points.
@@ -577,14 +613,7 @@
}
}
- /*
- * Main loop: run through the queue doing deferred resolution. We could have
- * made this entirely recursive, but a work queues uses much less max stack.
- */
- UnifyVisitor visitor = new UnifyVisitor();
- while (!todo.isEmpty()) {
- visitor.accept(todo.poll());
- }
+ mainLoop();
// Post-stitching clean-ups.
@@ -614,21 +643,9 @@
}
}
- // Compute overrides.
- for (JDeclaredType type : program.getDeclaredTypes()) {
- Map<String, Set<JMethod>> collected = new HashMap<String, Set<JMethod>>();
- for (JMethod method : type.getMethods()) {
- if (method.canBePolymorphic()) {
- collected.put(method.getSignature(), new LinkedHashSet<JMethod>());
- }
- }
- collectUpRefsInSupers(type, collected);
- for (JMethod method : type.getMethods()) {
- if (method.canBePolymorphic()) {
- Set<JMethod> uprefs = collected.get(method.getSignature());
- method.addOverrides(Lists.create(uprefs));
- }
- }
+ computeOverrides();
+ if (errorsFound) {
+ throw new UnableToCompleteException();
}
}
@@ -674,16 +691,48 @@
}
}
+ /**
+ * Compute all overrides.
+ */
+ private void computeOverrides() {
+ for (JDeclaredType type : program.getDeclaredTypes()) {
+ Map<String, Set<JMethod>> collected = new HashMap<String, Set<JMethod>>();
+ for (JMethod method : type.getMethods()) {
+ if (method.canBePolymorphic()) {
+ collected.put(method.getSignature(), new LinkedHashSet<JMethod>());
+ }
+ }
+ collectUpRefsInSupers(type, collected);
+ for (JMethod method : type.getMethods()) {
+ if (method.canBePolymorphic()) {
+ Set<JMethod> uprefs = collected.get(method.getSignature());
+ method.addOverrides(Lists.create(uprefs));
+ }
+ }
+ }
+ }
+
private void error(JNode x, String errorMessage) {
- // TODO: logging.
- throw new InternalCompilerException(x, errorMessage, null);
+ errorsFound = true;
+ TreeLogger branch =
+ logger
+ .branch(TreeLogger.ERROR, "Errors in '" + x.getSourceInfo().getFileName() + "'", null);
+ // Append 'Line #: msg' to the error message.
+ StringBuffer msgBuf = new StringBuffer();
+ int line = x.getSourceInfo().getStartLine();
+ if (line > 0) {
+ msgBuf.append("Line ");
+ msgBuf.append(line);
+ msgBuf.append(": ");
+ }
+ msgBuf.append(errorMessage);
+ branch.log(TreeLogger.ERROR, msgBuf.toString());
}
private void flowInto(JField field) {
- if (field == JField.NULL_FIELD) {
+ if (field == JField.NULL_FIELD || field.isExternal()) {
return;
}
- assert !field.isExternal();
if (!liveFieldsAndMethods.contains(field)) {
liveFieldsAndMethods.add(field);
field.setType(translate(field.getType()));
@@ -694,10 +743,9 @@
}
private void flowInto(JMethod method) {
- if (method == JMethod.NULL_METHOD) {
+ if (method == JMethod.NULL_METHOD || method.isExternal()) {
return;
}
- assert !method.isExternal();
if (!liveFieldsAndMethods.contains(method)) {
liveFieldsAndMethods.add(method);
JType originalReturnType = translate(method.getOriginalReturnType());
@@ -785,6 +833,17 @@
return type == program.getJavaScriptObject() || isJso(type.getSuperClass());
}
+ /**
+ * Main loop: run through the queue doing deferred resolution. We could have
+ * made this entirely recursive, but a work queue uses much less max stack.
+ */
+ private void mainLoop() {
+ UnifyVisitor visitor = new UnifyVisitor();
+ while (!todo.isEmpty()) {
+ visitor.accept(todo.poll());
+ }
+ }
+
private void mapApi(JDeclaredType type) {
assert !type.isExternal();
for (JField field : type.getFields()) {
@@ -888,47 +947,75 @@
}
private JDeclaredType translate(JDeclaredType type) {
- if (type.isExternal()) {
- String typeName = type.getName();
- type = searchForType(typeName);
+ if (!type.isExternal()) {
+ return type;
}
- assert !type.isExternal();
+
+ String typeName = type.getName();
+ JDeclaredType newType = searchForType(typeName);
+ if (newType != null) {
+ assert !newType.isExternal();
+ return newType;
+ }
+ // Error condition, should be logged.
+ errorsFound = true;
return type;
}
private JField translate(JField field) {
- if (field.isExternal()) {
- JDeclaredType enclosingType = field.getEnclosingType();
- String sig = enclosingType.getName() + '.' + field.getSignature();
- field = fieldMap.get(sig);
- if (field == null) {
- mapApi(translate(enclosingType));
- // Now the field should be there.
- field = fieldMap.get(sig);
- if (field == null) {
- // TODO: error logging
- throw new NoSuchFieldError(sig);
- }
- }
+ if (!field.isExternal()) {
+ return field;
}
+
+ JDeclaredType enclosingType = field.getEnclosingType();
+ String sig = enclosingType.getName() + '.' + field.getSignature();
+ JField newField = fieldMap.get(sig);
+ if (newField != null) {
+ return newField;
+ }
+
+ enclosingType = translate(enclosingType);
+ if (enclosingType.isExternal()) {
+ // Error condition, should be logged.
+ return field;
+ }
+ mapApi(enclosingType);
+
+ // Now the field should be there.
+ field = fieldMap.get(sig);
+ if (field == null) {
+ // TODO: error logging
+ throw new NoSuchFieldError(sig);
+ }
+
assert !field.isExternal();
return field;
}
private JMethod translate(JMethod method) {
- if (method.isExternal()) {
- JDeclaredType enclosingType = method.getEnclosingType();
- String sig = enclosingType.getName() + '.' + method.getSignature();
- method = methodMap.get(sig);
- if (method == null) {
- mapApi(translate(enclosingType));
- // Now the method should be there.
- method = methodMap.get(sig);
- if (method == null) {
- // TODO: error logging
- throw new NoSuchMethodError(sig);
- }
- }
+ if (!method.isExternal()) {
+ return method;
+ }
+
+ JDeclaredType enclosingType = method.getEnclosingType();
+ String sig = enclosingType.getName() + '.' + method.getSignature();
+ JMethod newMethod = methodMap.get(sig);
+ if (newMethod != null) {
+ return newMethod;
+ }
+
+ enclosingType = translate(enclosingType);
+ if (enclosingType.isExternal()) {
+ // Error condition, should be logged.
+ return method;
+ }
+ mapApi(enclosingType);
+
+ // Now the method should be there.
+ method = methodMap.get(sig);
+ if (method == null) {
+ // TODO: error logging
+ throw new NoSuchMethodError(sig);
}
assert !method.isExternal();
return method;
diff --git a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
index a333f54..94a6be6 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
@@ -20,31 +20,13 @@
import com.google.gwt.dev.javac.CompilationState;
import com.google.gwt.dev.javac.testing.impl.JavaResourceBase;
import com.google.gwt.dev.javac.testing.impl.MockJavaResource;
-import com.google.gwt.dev.jdt.AbstractCompiler.CompilationResults;
-import com.google.gwt.dev.jdt.BasicWebModeCompiler;
-import com.google.gwt.dev.jdt.FindDeferredBindingSitesVisitor;
-import com.google.gwt.dev.jjs.CorrelationFactory.DummyCorrelationFactory;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JProgram;
-import com.google.gwt.dev.jjs.impl.AssertionNormalizer;
-import com.google.gwt.dev.jjs.impl.BuildTypeMap;
-import com.google.gwt.dev.jjs.impl.FixAssignmentToUnbox;
-import com.google.gwt.dev.jjs.impl.GenerateJavaAST;
-import com.google.gwt.dev.jjs.impl.ImplementClassLiteralsAsFields;
-import com.google.gwt.dev.jjs.impl.TypeLinker;
-import com.google.gwt.dev.jjs.impl.TypeMap;
-import com.google.gwt.dev.js.ast.JsProgram;
-
-import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import java.util.Set;
-import java.util.TreeSet;
/**
* Constructs a Java AST for testing.
@@ -214,65 +196,9 @@
public static JProgram construct(TreeLogger logger, CompilationState state, String... entryPoints)
throws UnableToCompleteException {
- return construct(logger, state, TypeLinker.NULL_TYPE_LINKER, entryPoints);
- }
-
- public static JProgram construct(TreeLogger logger, CompilationState state, TypeLinker linker,
- String... entryPoints) throws UnableToCompleteException {
- Set<String> allRootTypes = new TreeSet<String>(Arrays.asList(entryPoints));
- for (MockJavaResource resource : getCompilerTypes()) {
- allRootTypes.add(resource.getTypeName());
- }
-
- CompilationResults units =
- BasicWebModeCompiler.getCompilationUnitDeclarations(logger, state, linker, allRootTypes
- .toArray(new String[allRootTypes.size()]));
-
- CompilationUnitDeclaration[] goldenCuds = units.compiledUnits;
-
- // Check for compilation problems. We don't log here because any problems
- // found here will have already been logged by AbstractCompiler.
- //
- JavaToJavaScriptCompiler.checkForErrors(logger, goldenCuds, false);
-
-
- // Find errors in usage of GWT.create() calls
- for (CompilationUnitDeclaration jdtCud : goldenCuds) {
- jdtCud.traverse(new FindDeferredBindingSitesVisitor(), jdtCud.scope);
- }
-
- JavaToJavaScriptCompiler.checkForErrors(logger, goldenCuds, true);
-
- CorrelationFactory correlator = DummyCorrelationFactory.INSTANCE;
- JProgram jprogram = new JProgram(correlator);
- JsProgram jsProgram = new JsProgram(correlator);
-
- /*
- * (1) Build a flattened map of TypeDeclarations => JType. The resulting map
- * contains entries for all reference types. BuildTypeMap also parses all
- * JSNI.
- */
- TypeMap typeMap = new TypeMap(jprogram);
- TypeDeclaration[] allTypeDeclarations = BuildTypeMap.exec(typeMap, units, jsProgram, linker);
-
- // BuildTypeMap can uncover syntactic JSNI errors; report & abort
- JavaToJavaScriptCompiler.checkForErrors(logger, goldenCuds, true);
-
- // Compute all super type/sub type info
- jprogram.typeOracle.computeBeforeAST();
-
- // (2) Create our own Java AST from the JDT AST.
JJSOptionsImpl options = new JJSOptionsImpl();
options.setEnableAssertions(true);
- GenerateJavaAST.exec(allTypeDeclarations, typeMap, jprogram, options);
-
- // GenerateJavaAST can uncover semantic JSNI errors; report & abort
- JavaToJavaScriptCompiler.checkForErrors(logger, goldenCuds, true);
-
- // (3) Perform Java AST normalizations.
- FixAssignmentToUnbox.exec(jprogram);
- // Turn into assertion checking calls.
- AssertionNormalizer.exec(jprogram);
+ JProgram jprogram = AstConstructor.construct(logger, state, options);
// Add entry methods for entry points.
for (String entryPoint : entryPoints) {
@@ -283,9 +209,6 @@
}
}
}
-
- ImplementClassLiteralsAsFields.exec(jprogram);
-
// Tree is now ready to optimize.
return jprogram;
}
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/JJSTestBase.java b/dev/core/test/com/google/gwt/dev/jjs/impl/JJSTestBase.java
index 21ae7b5..a1087b0 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/JJSTestBase.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/JJSTestBase.java
@@ -235,11 +235,17 @@
}
});
addBuiltinClasses(sourceOracle);
- CompilationState state = CompilationStateBuilder.buildFrom(logger,
- sourceOracle.getResources(), getAdditionalTypeProviderDelegate());
- JProgram program = JavaAstConstructor.construct(logger, state,
- "test.EntryPoint", "com.google.gwt.lang.Exceptions");
- return program;
+ boolean wasEnabled = GwtAstBuilder.ENABLED;
+ try {
+ GwtAstBuilder.ENABLED = true;
+ CompilationState state = CompilationStateBuilder.buildFrom(logger,
+ sourceOracle.getResources(), getAdditionalTypeProviderDelegate());
+ JProgram program = JavaAstConstructor.construct(logger, state,
+ "test.EntryPoint", "com.google.gwt.lang.Exceptions");
+ return program;
+ } finally {
+ GwtAstBuilder.ENABLED = wasEnabled;
+ }
}
protected void addBuiltinClasses(MockResourceOracle sourceOracle) {