Now that the file/line information and new visitor pattern is in, it's
time to leverage the infrastructure! This change adds try/catch blocks
into the major compiler visitors (both JDT and our own AST) which record a
stack of nodes being visited, much like a stack trace. When the ICE is
caught by the main compile method, a log message points users to the
portion of their code that triggered the fault.
Review by: mmendez
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@392 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
index 262ca4d..51988d1 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -30,6 +30,7 @@
import com.google.gwt.dev.jjs.ast.JNewInstance;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JReferenceType;
+import com.google.gwt.dev.jjs.ast.JSourceInfo;
import com.google.gwt.dev.jjs.impl.ArrayNormalizer;
import com.google.gwt.dev.jjs.impl.BuildTypeMap;
import com.google.gwt.dev.jjs.impl.CastNormalizer;
@@ -39,6 +40,7 @@
import com.google.gwt.dev.jjs.impl.DeadCodeElimination;
import com.google.gwt.dev.jjs.impl.GenerateJavaAST;
import com.google.gwt.dev.jjs.impl.GenerateJavaScriptAST;
+import com.google.gwt.dev.jjs.impl.InternalCompilerException;
import com.google.gwt.dev.jjs.impl.JavaScriptObjectCaster;
import com.google.gwt.dev.jjs.impl.MakeCallsStatic;
import com.google.gwt.dev.jjs.impl.MethodAndClassFinalizer;
@@ -48,6 +50,7 @@
import com.google.gwt.dev.jjs.impl.ReplaceRebinds;
import com.google.gwt.dev.jjs.impl.TypeMap;
import com.google.gwt.dev.jjs.impl.TypeTightener;
+import com.google.gwt.dev.jjs.impl.InternalCompilerException.NodeInfo;
import com.google.gwt.dev.js.FullNamingStrategy;
import com.google.gwt.dev.js.JsSourceGenerationVisitor;
import com.google.gwt.dev.js.NamingStrategy;
@@ -65,6 +68,8 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
import java.util.Set;
/**
@@ -383,6 +388,36 @@
} catch (UnableToCompleteException e) {
// just rethrow
throw e;
+ } catch (InternalCompilerException e) {
+ TreeLogger topBranch = logger.branch(TreeLogger.ERROR,
+ "An internal compiler exception occurred", e);
+ List nodeTrace = e.getNodeTrace();
+ for (Iterator it = nodeTrace.iterator(); it.hasNext();) {
+ NodeInfo nodeInfo = (NodeInfo) it.next();
+ JSourceInfo info = nodeInfo.getSourceInfo();
+ String msg;
+ if (info != null) {
+ String fileName = info.getFileName();
+ fileName = fileName.substring(fileName.lastIndexOf('/') + 1);
+ fileName = fileName.substring(fileName.lastIndexOf('\\') + 1);
+ msg = "at " + fileName + "(" + info.getStartLine() + "): ";
+ } else {
+ msg = "<no source info>: ";
+ }
+
+ String description = nodeInfo.getDescription();
+ if (description != null) {
+ msg += description;
+ } else {
+ msg += "<no description available>";
+ }
+ TreeLogger nodeBranch = topBranch.branch(TreeLogger.ERROR, msg, null);
+ String className = nodeInfo.getClassName();
+ if (className != null) {
+ nodeBranch.log(TreeLogger.INFO, className, null);
+ }
+ }
+ throw new UnableToCompleteException();
} catch (Throwable e) {
logger.log(TreeLogger.ERROR, "Unexpected internal compiler error", e);
throw new UnableToCompleteException();
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java
index fc9c259..89f9782 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java
@@ -516,40 +516,21 @@
}
protected final void doTraverse(JNode node, Context ctx) {
- // boolean trace = false;
- // String before = null;
try {
- // trace = !(this instanceof ToStringGenerationVisitor)
- // && (node instanceof JTryStatement);
- // if (trace) {
- // before = node.toSource();
- // }
node.traverse(this, ctx);
- // if (trace) {
- // String after = node.toSource();
- // if (!before.equals(after)) {
- // System.out.println(this.getClass().getName() + ":");
- // System.out.println("--");
- // System.out.println(before);
- // System.out.println("VV");
- // System.out.println(after);
- // System.out.println("---------------------------------------------------------");
- // }
- // }
- } catch (InternalCompilerException ice) {
- ice.addNode(node);
- throw ice;
} catch (Throwable e) {
- // if (trace) {
- // System.out.println(this.getClass().getName() + ":");
- // System.out.println("--");
- // System.out.println(before);
- // System.out.println(e);
- // }
- InternalCompilerException ice = new InternalCompilerException(
- "Unexpected error during visit.", e);
- ice.addNode(node);
- throw ice;
+ throw translateException(node, e);
}
}
+
+ private InternalCompilerException translateException(JNode node, Throwable e) {
+ InternalCompilerException ice;
+ if (e instanceof InternalCompilerException) {
+ ice = (InternalCompilerException) e;
+ } else {
+ ice = new InternalCompilerException("Error constructing Java AST", e);
+ }
+ ice.addNode(node);
+ return ice;
+ }
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java b/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
index 7f5dd22..9f43513 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
@@ -104,6 +104,18 @@
startLine, fileName);
}
+ private static InternalCompilerException translateException(
+ AbstractMethodDeclaration amd, Throwable e) {
+ InternalCompilerException ice;
+ if (e instanceof InternalCompilerException) {
+ ice = (InternalCompilerException) e;
+ } else {
+ ice = new InternalCompilerException("Error building type map", e);
+ }
+ ice.addNode(amd.getClass().getName(), amd.toString(), makeSourceInfo(amd));
+ return ice;
+ }
+
private String currentFileName;
private int[] currentSeparatorPositions;
private final JsParser jsParser = new JsParser();
@@ -124,18 +136,22 @@
}
public boolean visit(Argument argument, BlockScope scope) {
- if (scope == scope.methodScope()) {
- return true;
- }
+ try {
+ if (scope == scope.methodScope()) {
+ return true;
+ }
- JSourceInfo info = makeInfo(argument);
- LocalVariableBinding b = argument.binding;
- JType localType = (JType) typeMap.get(b.type);
- JMethod enclosingMethod = findEnclosingMethod(scope);
- JLocal newLocal = program.createLocal(info, argument.name, localType,
- b.isFinal(), enclosingMethod);
- typeMap.put(b, newLocal);
- return true;
+ JSourceInfo info = makeSourceInfo(argument);
+ LocalVariableBinding b = argument.binding;
+ JType localType = (JType) typeMap.get(b.type);
+ JMethod enclosingMethod = findEnclosingMethod(scope);
+ JLocal newLocal = program.createLocal(info, argument.name, localType,
+ b.isFinal(), enclosingMethod);
+ typeMap.put(b, newLocal);
+ return true;
+ } catch (Throwable e) {
+ throw translateException(argument, e);
+ }
}
/**
@@ -146,191 +162,208 @@
* for details.
*/
public boolean visit(ConstructorDeclaration ctorDecl, ClassScope scope) {
- MethodBinding b = ctorDecl.binding;
- JClassType enclosingType = (JClassType) typeMap.get(scope.enclosingSourceType());
- String name = enclosingType.getShortName();
- JSourceInfo info = makeSourceInfo(ctorDecl);
- JMethod newMethod = program.createMethod(info, name.toCharArray(),
- enclosingType, enclosingType, false, false, true, b.isPrivate(),
- false);
- mapThrownExceptions(newMethod, ctorDecl);
+ try {
+ MethodBinding b = ctorDecl.binding;
+ JClassType enclosingType = (JClassType) typeMap.get(scope.enclosingSourceType());
+ String name = enclosingType.getShortName();
+ JSourceInfo info = makeSourceInfo(ctorDecl);
+ JMethod newMethod = program.createMethod(info, name.toCharArray(),
+ enclosingType, enclosingType, false, false, true, b.isPrivate(),
+ false);
+ mapThrownExceptions(newMethod, ctorDecl);
- int syntheticParamCount = 0;
- ReferenceBinding declaringClass = b.declaringClass;
- if (declaringClass.isNestedType() && !declaringClass.isStatic()) {
- // add synthentic args for outer this and locals
- NestedTypeBinding nestedBinding = (NestedTypeBinding) declaringClass;
- Set alreadyNamedVariables = new HashSet();
- if (nestedBinding.enclosingInstances != null) {
- for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) {
- SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i];
- String argName = String.valueOf(arg.name);
- if (alreadyNamedVariables.contains(argName)) {
- argName += "_" + i;
+ int syntheticParamCount = 0;
+ ReferenceBinding declaringClass = b.declaringClass;
+ if (declaringClass.isNestedType() && !declaringClass.isStatic()) {
+ // add synthentic args for outer this and locals
+ NestedTypeBinding nestedBinding = (NestedTypeBinding) declaringClass;
+ Set alreadyNamedVariables = new HashSet();
+ if (nestedBinding.enclosingInstances != null) {
+ for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) {
+ SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i];
+ String argName = String.valueOf(arg.name);
+ if (alreadyNamedVariables.contains(argName)) {
+ argName += "_" + i;
+ }
+ createParameter(arg, argName, newMethod);
+ ++syntheticParamCount;
+ alreadyNamedVariables.add(argName);
}
- createParameter(arg, argName, newMethod);
- ++syntheticParamCount;
- alreadyNamedVariables.add(argName);
+ }
+
+ if (nestedBinding.outerLocalVariables != null) {
+ for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) {
+ SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i];
+ String argName = String.valueOf(arg.name);
+ if (alreadyNamedVariables.contains(argName)) {
+ argName += "_" + i;
+ }
+ createParameter(arg, argName, newMethod);
+ ++syntheticParamCount;
+ alreadyNamedVariables.add(argName);
+ }
}
}
- if (nestedBinding.outerLocalVariables != null) {
- for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) {
- SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i];
- String argName = String.valueOf(arg.name);
- if (alreadyNamedVariables.contains(argName)) {
- argName += "_" + i;
- }
- createParameter(arg, argName, newMethod);
- ++syntheticParamCount;
- alreadyNamedVariables.add(argName);
- }
+ // user args
+ mapParameters(newMethod, ctorDecl);
+
+ // remove synthetic args from the original param types list
+ for (; syntheticParamCount > 0; --syntheticParamCount) {
+ newMethod.getOriginalParamTypes().remove(0);
}
+
+ typeMap.put(b, newMethod);
+ return true;
+ } catch (Throwable e) {
+ throw translateException(ctorDecl, e);
}
-
- // user args
- mapParameters(newMethod, ctorDecl);
-
- // remove synthetic args from the original param types list
- for (; syntheticParamCount > 0; --syntheticParamCount) {
- newMethod.getOriginalParamTypes().remove(0);
- }
-
- typeMap.put(b, newMethod);
- return true;
}
public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) {
- FieldBinding b = fieldDeclaration.binding;
- JSourceInfo info = makeInfo(fieldDeclaration);
- JReferenceType enclosingType = (JReferenceType) typeMap.get(scope.enclosingSourceType());
- createField(info, b, enclosingType,
- fieldDeclaration.initialization != null);
- return true;
+ try {
+ FieldBinding b = fieldDeclaration.binding;
+ JSourceInfo info = makeSourceInfo(fieldDeclaration);
+ JReferenceType enclosingType = (JReferenceType) typeMap.get(scope.enclosingSourceType());
+ createField(info, b, enclosingType,
+ fieldDeclaration.initialization != null);
+ return true;
+ } catch (Throwable e) {
+ throw translateException(fieldDeclaration, e);
+ }
}
public boolean visit(LocalDeclaration localDeclaration, BlockScope scope) {
- LocalVariableBinding b = localDeclaration.binding;
- JType localType = (JType) typeMap.get(localDeclaration.type.resolvedType);
- JMethod enclosingMethod = findEnclosingMethod(scope);
- JSourceInfo info = makeInfo(localDeclaration);
- JLocal newLocal = program.createLocal(info, localDeclaration.name,
- localType, b.isFinal(), enclosingMethod);
- typeMap.put(b, newLocal);
- return true;
+ try {
+ LocalVariableBinding b = localDeclaration.binding;
+ JType localType = (JType) typeMap.get(localDeclaration.type.resolvedType);
+ JMethod enclosingMethod = findEnclosingMethod(scope);
+ JSourceInfo info = makeSourceInfo(localDeclaration);
+ JLocal newLocal = program.createLocal(info, localDeclaration.name,
+ localType, b.isFinal(), enclosingMethod);
+ typeMap.put(b, newLocal);
+ return true;
+ } catch (Throwable e) {
+ throw translateException(localDeclaration, e);
+ }
}
public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {
- MethodBinding b = methodDeclaration.binding;
- JSourceInfo info = makeSourceInfo(methodDeclaration);
- JType returnType = (JType) typeMap.get(methodDeclaration.returnType.resolvedType);
- JReferenceType enclosingType = (JReferenceType) typeMap.get(scope.enclosingSourceType());
- JMethod newMethod = program.createMethod(info,
- methodDeclaration.selector, enclosingType, returnType,
- b.isAbstract(), b.isStatic(), b.isFinal(), b.isPrivate(),
- b.isNative());
+ try {
+ MethodBinding b = methodDeclaration.binding;
+ JSourceInfo info = makeSourceInfo(methodDeclaration);
+ JType returnType = (JType) typeMap.get(methodDeclaration.returnType.resolvedType);
+ JReferenceType enclosingType = (JReferenceType) typeMap.get(scope.enclosingSourceType());
+ JMethod newMethod = program.createMethod(info,
+ methodDeclaration.selector, enclosingType, returnType,
+ b.isAbstract(), b.isStatic(), b.isFinal(), b.isPrivate(),
+ b.isNative());
- mapThrownExceptions(newMethod, methodDeclaration);
- mapParameters(newMethod, methodDeclaration);
- typeMap.put(b, newMethod);
+ mapThrownExceptions(newMethod, methodDeclaration);
+ mapParameters(newMethod, methodDeclaration);
+ typeMap.put(b, newMethod);
- if (newMethod.isNative()) {
- // Handle JSNI block
- char[] source = methodDeclaration.compilationResult().getCompilationUnit().getContents();
- String jsniCode = String.valueOf(source, methodDeclaration.bodyStart,
- methodDeclaration.bodyEnd - methodDeclaration.bodyStart + 1);
- int startPos = jsniCode.indexOf("/*-{");
- int endPos = jsniCode.lastIndexOf("}-*/");
- if (startPos < 0 && endPos < 0) {
- GenerateJavaAST.reportJsniError(
- info,
- methodDeclaration,
- "Native methods require a JavaScript implementation enclosed with /*-{ and }-*/");
- return true;
- }
- if (startPos < 0) {
- GenerateJavaAST.reportJsniError(info, methodDeclaration,
- "Unable to find start of native block; begin your JavaScript block with: /*-{");
- return true;
- }
- if (endPos < 0) {
- GenerateJavaAST.reportJsniError(
- info,
- methodDeclaration,
- "Unable to find end of native block; terminate your JavaScript block with: }-*/");
- return true;
- }
-
- startPos += 3; // move up to open brace
- endPos += 1; // move past close brace
-
- jsniCode = jsniCode.substring(startPos, endPos);
-
- // Here we parse it as an anonymous function, but we will give it a
- // name later when we generate the JavaScript during codegen.
- //
- String syntheticFnHeader = "function (";
- boolean first = true;
- for (int i = 0; i < newMethod.params.size(); ++i) {
- JParameter param = (JParameter) newMethod.params.get(i);
- if (first) {
- first = false;
- } else {
- syntheticFnHeader += ',';
+ if (newMethod.isNative()) {
+ // Handle JSNI block
+ char[] source = methodDeclaration.compilationResult().getCompilationUnit().getContents();
+ String jsniCode = String.valueOf(source, methodDeclaration.bodyStart,
+ methodDeclaration.bodyEnd - methodDeclaration.bodyStart + 1);
+ int startPos = jsniCode.indexOf("/*-{");
+ int endPos = jsniCode.lastIndexOf("}-*/");
+ if (startPos < 0 && endPos < 0) {
+ GenerateJavaAST.reportJsniError(
+ info,
+ methodDeclaration,
+ "Native methods require a JavaScript implementation enclosed with /*-{ and }-*/");
+ return true;
}
- syntheticFnHeader += param.getName();
- }
- syntheticFnHeader += ')';
- StringReader sr = new StringReader(syntheticFnHeader + '\n' + jsniCode);
- try {
- // start at -1 to avoid counting our synthetic header
- // TODO: get the character position start correct
- JsStatements result = jsParser.parse(jsProgram.getScope(), sr, -1);
- JsExprStmt jsExprStmt = (JsExprStmt) result.get(0);
- JsFunction jsFunction = (JsFunction) jsExprStmt.getExpression();
- ((JsniMethod) newMethod).setFunc(jsFunction);
- } catch (IOException e) {
- throw new InternalCompilerException(
- "Internal error parsing JSNI in method '" + newMethod
- + "' in type '" + enclosingType.getName() + "'", e);
- } catch (JsParserException e) {
- /*
- * count the number of characters to the problem (from the start of
- * the JSNI code)
- */
- SourceDetail detail = e.getSourceDetail();
- int line = detail.getLine();
- char[] chars = jsniCode.toCharArray();
- int i = 0, n = chars.length;
- while (line > 0) {
- // CHECKSTYLE_OFF
- switch (chars[i]) {
- case '\r':
- // if skip an extra character if this is a CR/LF
- if (i + 1 < n && chars[i + 1] == '\n') {
- ++i;
- }
- // intentional fall-through
- case '\n':
- --line;
- // intentional fall-through
- default:
- ++i;
+ if (startPos < 0) {
+ GenerateJavaAST.reportJsniError(info, methodDeclaration,
+ "Unable to find start of native block; begin your JavaScript block with: /*-{");
+ return true;
+ }
+ if (endPos < 0) {
+ GenerateJavaAST.reportJsniError(
+ info,
+ methodDeclaration,
+ "Unable to find end of native block; terminate your JavaScript block with: }-*/");
+ return true;
+ }
+
+ startPos += 3; // move up to open brace
+ endPos += 1; // move past close brace
+
+ jsniCode = jsniCode.substring(startPos, endPos);
+
+ // Here we parse it as an anonymous function, but we will give it a
+ // name later when we generate the JavaScript during codegen.
+ //
+ String syntheticFnHeader = "function (";
+ boolean first = true;
+ for (int i = 0; i < newMethod.params.size(); ++i) {
+ JParameter param = (JParameter) newMethod.params.get(i);
+ if (first) {
+ first = false;
+ } else {
+ syntheticFnHeader += ',';
}
- // CHECKSTYLE_ON
+ syntheticFnHeader += param.getName();
}
+ syntheticFnHeader += ')';
+ StringReader sr = new StringReader(syntheticFnHeader + '\n'
+ + jsniCode);
+ try {
+ // start at -1 to avoid counting our synthetic header
+ // TODO: get the character position start correct
+ JsStatements result = jsParser.parse(jsProgram.getScope(), sr, -1);
+ JsExprStmt jsExprStmt = (JsExprStmt) result.get(0);
+ JsFunction jsFunction = (JsFunction) jsExprStmt.getExpression();
+ ((JsniMethod) newMethod).setFunc(jsFunction);
+ } catch (IOException e) {
+ throw new InternalCompilerException(
+ "Internal error parsing JSNI in method '" + newMethod
+ + "' in type '" + enclosingType.getName() + "'", e);
+ } catch (JsParserException e) {
+ /*
+ * count the number of characters to the problem (from the start of
+ * the JSNI code)
+ */
+ SourceDetail detail = e.getSourceDetail();
+ int line = detail.getLine();
+ char[] chars = jsniCode.toCharArray();
+ int i = 0, n = chars.length;
+ while (line > 0) {
+ // CHECKSTYLE_OFF
+ switch (chars[i]) {
+ case '\r':
+ // if skip an extra character if this is a CR/LF
+ if (i + 1 < n && chars[i + 1] == '\n') {
+ ++i;
+ }
+ // intentional fall-through
+ case '\n':
+ --line;
+ // intentional fall-through
+ default:
+ ++i;
+ }
+ // CHECKSTYLE_ON
+ }
- // TODO: check this
- // Map into the original source stream;
- i += startPos + detail.getLineOffset();
- info = new JSourceInfo(i, i, info.getStartLine() + detail.getLine(),
- info.getFileName());
- GenerateJavaAST.reportJsniError(info, methodDeclaration,
- e.getMessage());
+ // TODO: check this
+ // Map into the original source stream;
+ i += startPos + detail.getLineOffset();
+ info = new JSourceInfo(i, i,
+ info.getStartLine() + detail.getLine(), info.getFileName());
+ GenerateJavaAST.reportJsniError(info, methodDeclaration,
+ e.getMessage());
+ }
}
- }
- return true;
+ return true;
+ } catch (Throwable e) {
+ throw translateException(methodDeclaration, e);
+ }
}
public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) {
@@ -370,7 +403,7 @@
private JParameter createParameter(LocalVariableBinding binding,
JMethod enclosingMethod) {
JType type = (JType) typeMap.get(binding.type);
- JSourceInfo info = makeInfo(binding.declaration);
+ JSourceInfo info = makeSourceInfo(binding.declaration);
JParameter param = program.createParameter(info, binding.name, type,
binding.isFinal(), enclosingMethod);
typeMap.put(binding, param);
@@ -403,7 +436,7 @@
return (JMethod) typeMap.get(referenceMethod.binding);
}
- private JSourceInfo makeInfo(Statement stmt) {
+ private JSourceInfo makeSourceInfo(Statement stmt) {
int startLine = ProblemHandler.searchLineNumber(
currentSeparatorPositions, stmt.sourceStart);
return new JSourceInfo(stmt.sourceStart, stmt.sourceEnd, startLine,
@@ -455,44 +488,63 @@
return false;
}
JReferenceType type = (JReferenceType) typeMap.get(binding);
+ try {
+ if (binding.isNestedType() && !binding.isStatic()) {
+ // add synthentic fields for outer this and locals
+ assert (type instanceof JClassType);
+ NestedTypeBinding nestedBinding = (NestedTypeBinding) binding;
+ if (nestedBinding.enclosingInstances != null) {
+ for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) {
+ SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i];
+ if (arg.matchingField != null) {
+ createField(arg, type);
+ }
+ }
+ }
- if (binding.isNestedType() && !binding.isStatic()) {
- // add synthentic fields for outer this and locals
- assert (type instanceof JClassType);
- NestedTypeBinding nestedBinding = (NestedTypeBinding) binding;
- if (nestedBinding.enclosingInstances != null) {
- for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) {
- SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i];
- if (arg.matchingField != null) {
+ if (nestedBinding.outerLocalVariables != null) {
+ for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) {
+ SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i];
createField(arg, type);
}
}
}
- if (nestedBinding.outerLocalVariables != null) {
- for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) {
- SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i];
- createField(arg, type);
- }
+ ReferenceBinding superClassBinding = binding.superclass();
+ if (superClassBinding != null) {
+ assert (binding.superclass().isClass());
+ JClassType superClass = (JClassType) typeMap.get(superClassBinding);
+ type.extnds = superClass;
}
- }
- ReferenceBinding superClassBinding = binding.superclass();
- if (superClassBinding != null) {
- assert (binding.superclass().isClass());
- JClassType superClass = (JClassType) typeMap.get(superClassBinding);
- type.extnds = superClass;
+ ReferenceBinding[] superInterfaces = binding.superInterfaces();
+ for (int i = 0; i < superInterfaces.length; ++i) {
+ ReferenceBinding superInterfaceBinding = superInterfaces[i];
+ assert (superInterfaceBinding.isInterface());
+ JInterfaceType superInterface = (JInterfaceType) typeMap.get(superInterfaceBinding);
+ type.implments.add(superInterface);
+ }
+ typeDecls.add(typeDeclaration);
+ return true;
+ } catch (InternalCompilerException ice) {
+ ice.addNode(type);
+ throw ice;
+ } catch (Throwable e) {
+ throw new InternalCompilerException(type, "Error building type map", e);
}
+ }
- ReferenceBinding[] superInterfaces = binding.superInterfaces();
- for (int i = 0; i < superInterfaces.length; ++i) {
- ReferenceBinding superInterfaceBinding = superInterfaces[i];
- assert (superInterfaceBinding.isInterface());
- JInterfaceType superInterface = (JInterfaceType) typeMap.get(superInterfaceBinding);
- type.implments.add(superInterface);
+ private InternalCompilerException translateException(Statement stmt,
+ Throwable e) {
+ InternalCompilerException ice;
+ if (e instanceof InternalCompilerException) {
+ ice = (InternalCompilerException) e;
+ } else {
+ ice = new InternalCompilerException("Error building type map", e);
}
- typeDecls.add(typeDeclaration);
- return true;
+ ice.addNode(stmt.getClass().getName(), stmt.toString(),
+ makeSourceInfo(stmt));
+ return ice;
}
}
@@ -514,6 +566,19 @@
fileName);
}
+ private static InternalCompilerException translateException(
+ TypeDeclaration typeDecl, Throwable e) {
+ InternalCompilerException ice;
+ if (e instanceof InternalCompilerException) {
+ ice = (InternalCompilerException) e;
+ } else {
+ ice = new InternalCompilerException("Error building type map", e);
+ }
+ ice.addNode(typeDecl.getClass().getName(), typeDecl.toString(),
+ makeSourceInfo(typeDecl));
+ return ice;
+ }
+
private final JProgram program;
private final TypeMap typeMap;
@@ -537,57 +602,61 @@
}
private boolean process(TypeDeclaration typeDeclaration) {
- char[][] name = typeDeclaration.binding.compoundName;
- SourceTypeBinding binding = typeDeclaration.binding;
- if (binding instanceof LocalTypeBinding) {
- char[] localName = binding.constantPoolName();
- if (localName == null) {
- /*
- * Weird case: if JDT determines that this local class is totally
- * uninstantiable, it won't bother allocating a local name.
- */
+ try {
+ char[][] name = typeDeclaration.binding.compoundName;
+ SourceTypeBinding binding = typeDeclaration.binding;
+ if (binding instanceof LocalTypeBinding) {
+ char[] localName = binding.constantPoolName();
+ if (localName == null) {
+ /*
+ * Weird case: if JDT determines that this local class is totally
+ * uninstantiable, it won't bother allocating a local name.
+ */
+ return false;
+ }
+
+ for (int i = 0, c = localName.length; i < c; ++i) {
+ if (localName[i] == '/') {
+ localName[i] = '.';
+ }
+ }
+ name = new char[1][0];
+ name[0] = localName;
+ }
+
+ JSourceInfo info = makeSourceInfo(typeDeclaration);
+ JReferenceType newType;
+ if (binding.isClass()) {
+ newType = program.createClass(info, name, binding.isAbstract(),
+ binding.isFinal());
+ } else if (binding.isInterface()) {
+ newType = program.createInterface(info, name);
+ } else {
+ assert (false);
return false;
}
- for (int i = 0, c = localName.length; i < c; ++i) {
- if (localName[i] == '/') {
- localName[i] = '.';
- }
+ /**
+ * We emulate static initializers and intance initializers as methods.
+ * As in other cases, this gives us: simpler AST, easier to optimize,
+ * more like output JavaScript. Clinit is always in slot 0, init (if it
+ * exists) is always in slot 1.
+ */
+ JMethod clinit = program.createMethod(null, "$clinit".toCharArray(),
+ newType, program.getTypeVoid(), false, true, true, true, false);
+ clinit.freezeParamTypes();
+
+ if (newType instanceof JClassType) {
+ JMethod init = program.createMethod(null, "$init".toCharArray(),
+ newType, program.getTypeVoid(), false, false, true, true, false);
+ init.freezeParamTypes();
}
- name = new char[1][0];
- name[0] = localName;
+
+ typeMap.put(binding, newType);
+ return true;
+ } catch (Throwable e) {
+ throw translateException(typeDeclaration, e);
}
-
- JSourceInfo info = makeSourceInfo(typeDeclaration);
- JReferenceType newType;
- if (binding.isClass()) {
- newType = program.createClass(info, name, binding.isAbstract(),
- binding.isFinal());
- } else if (binding.isInterface()) {
- newType = program.createInterface(info, name);
- } else {
- assert (false);
- return false;
- }
-
- /**
- * We emulate static initializers and intance initializers as methods. As
- * in other cases, this gives us: simpler AST, easier to optimize, more
- * like output JavaScript. Clinit is always in slot 0, init (if it exists)
- * is always in slot 1.
- */
- JMethod clinit = program.createMethod(null, "$clinit".toCharArray(),
- newType, program.getTypeVoid(), false, true, true, true, false);
- clinit.freezeParamTypes();
-
- if (newType instanceof JClassType) {
- JMethod init = program.createMethod(null, "$init".toCharArray(),
- newType, program.getTypeVoid(), false, false, true, true, false);
- init.freezeParamTypes();
- }
-
- typeMap.put(binding, newType);
- return true;
}
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
index c903926..e80f39c 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
@@ -84,7 +84,6 @@
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.ast.AND_AND_Expression;
-import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression;
@@ -225,6 +224,19 @@
return sb.toString();
}
+ private static InternalCompilerException translateException(JNode node,
+ Throwable e) {
+ InternalCompilerException ice;
+ if (e instanceof InternalCompilerException) {
+ ice = (InternalCompilerException) e;
+ ice.addNode(node);
+ } else {
+ ice = new InternalCompilerException(node,
+ "Error constructing Java AST", e);
+ }
+ return ice;
+ }
+
private Object[] args = new Object[1];
private JReferenceType currentClass;
@@ -259,54 +271,58 @@
*/
public void processType(TypeDeclaration x) {
currentClass = (JReferenceType) typeMap.get(x.binding);
- currentClassScope = x.scope;
- currentSeparatorPositions = x.compilationResult.lineSeparatorPositions;
- currentFileName = String.valueOf(x.compilationResult.fileName);
+ try {
+ currentClassScope = x.scope;
+ currentSeparatorPositions = x.compilationResult.lineSeparatorPositions;
+ currentFileName = String.valueOf(x.compilationResult.fileName);
- if (x.fields != null) {
- // Process fields
- for (int i = 0, n = x.fields.length; i < n; ++i) {
- FieldDeclaration fieldDeclaration = x.fields[i];
- if (fieldDeclaration.isStatic()) {
- // clinit
- currentMethod = (JMethod) currentClass.methods.get(0);
- currentMethodScope = x.staticInitializerScope;
- } else {
- // init
- currentMethod = (JMethod) currentClass.methods.get(1);
- currentMethodScope = x.initializerScope;
- }
+ if (x.fields != null) {
+ // Process fields
+ for (int i = 0, n = x.fields.length; i < n; ++i) {
+ FieldDeclaration fieldDeclaration = x.fields[i];
+ if (fieldDeclaration.isStatic()) {
+ // clinit
+ currentMethod = (JMethod) currentClass.methods.get(0);
+ currentMethodScope = x.staticInitializerScope;
+ } else {
+ // init
+ currentMethod = (JMethod) currentClass.methods.get(1);
+ currentMethodScope = x.initializerScope;
+ }
- if (fieldDeclaration instanceof Initializer) {
- assert (currentClass instanceof JClassType);
- processInitializer((Initializer) fieldDeclaration);
- } else {
- processField(fieldDeclaration);
+ if (fieldDeclaration instanceof Initializer) {
+ assert (currentClass instanceof JClassType);
+ processInitializer((Initializer) fieldDeclaration);
+ } else {
+ processField(fieldDeclaration);
+ }
}
}
- }
- currentMethodScope = null;
- currentMethod = null;
+ currentMethodScope = null;
+ currentMethod = null;
- if (x.methods != null) {
- // Process methods
- for (int i = 0, n = x.methods.length; i < n; ++i) {
- if (x.methods[i].isConstructor()) {
- assert (currentClass instanceof JClassType);
- processConstructor((ConstructorDeclaration) x.methods[i]);
- } else if (x.methods[i].isClinit()) {
- // nothing to do
- } else {
- processMethod(x.methods[i]);
+ if (x.methods != null) {
+ // Process methods
+ for (int i = 0, n = x.methods.length; i < n; ++i) {
+ if (x.methods[i].isConstructor()) {
+ assert (currentClass instanceof JClassType);
+ processConstructor((ConstructorDeclaration) x.methods[i]);
+ } else if (x.methods[i].isClinit()) {
+ // nothing to do
+ } else {
+ processMethod(x.methods[i]);
+ }
}
}
- }
- currentClassScope = null;
- currentClass = null;
- currentSeparatorPositions = null;
- currentFileName = null;
+ currentClassScope = null;
+ currentClass = null;
+ currentSeparatorPositions = null;
+ currentFileName = null;
+ } catch (Throwable e) {
+ throw translateException(currentClass, e);
+ }
}
/**
@@ -319,35 +335,15 @@
}
try {
- try {
- params[0] = child.getClass();
- Method method = getClass().getDeclaredMethod(name, params);
- args[0] = child;
- return (JNode) method.invoke(this, args);
- } catch (SecurityException e) {
- throw new InternalCompilerException("Error during dispatch", e);
- } catch (NoSuchMethodException e) {
- String s = params[0].getName();
- throw new InternalCompilerException("Expecting: private void " + name
- + "(" + s.substring(s.lastIndexOf('.') + 1) + " x) { }", e);
- } catch (IllegalArgumentException e) {
- throw new InternalCompilerException("Error during dispatch", e);
- } catch (IllegalAccessException e) {
- throw new InternalCompilerException("Error during dispatch", e);
- } catch (InvocationTargetException e) {
- Throwable target = e.getTargetException();
- if (target instanceof InternalCompilerException) {
- throw (InternalCompilerException) target;
- } else {
- throw new InternalCompilerException(
- "Error during AST construction", target);
- }
+ params[0] = child.getClass();
+ Method method = getClass().getDeclaredMethod(name, params);
+ args[0] = child;
+ return (JNode) method.invoke(this, args);
+ } catch (Throwable e) {
+ if (e instanceof InvocationTargetException) {
+ e = ((InvocationTargetException) e).getTargetException();
}
- } catch (InternalCompilerException ice) {
- if (child instanceof ASTNode) {
- ice.addNode((ASTNode) child);
- }
- throw ice;
+ throw translateException(child, e);
}
}
@@ -449,48 +445,64 @@
*/
void processConstructor(ConstructorDeclaration x) {
JMethod ctor = (JMethod) typeMap.get(x.binding);
- JSourceInfo info = ctor.body.getSourceInfo();
+ try {
+ JSourceInfo info = ctor.body.getSourceInfo();
- currentMethod = ctor;
- currentMethodScope = x.scope;
+ currentMethod = ctor;
+ currentMethodScope = x.scope;
- JMethodCall call = null;
- ExplicitConstructorCall ctorCall = x.constructorCall;
- if (ctorCall != null) {
- call = processExpression(ctorCall);
- }
+ JMethodCall call = null;
+ ExplicitConstructorCall ctorCall = x.constructorCall;
+ if (ctorCall != null) {
+ call = (JMethodCall) dispatch("processExpression", ctorCall);
+ }
- /*
- * Determine if we have an explicit this call. The presence of an explicit
- * this call indicates we can skip certain initialization steps (as the
- * callee will perform those steps for us). These skippable steps are 1)
- * assigning synthetic args to fields and 2) running initializers.
- */
- boolean hasExplicitThis = (ctorCall != null) && !ctorCall.isSuperAccess();
+ /*
+ * Determine if we have an explicit this call. The presence of an
+ * explicit this call indicates we can skip certain initialization steps
+ * (as the callee will perform those steps for us). These skippable
+ * steps are 1) assigning synthetic args to fields and 2) running
+ * initializers.
+ */
+ boolean hasExplicitThis = (ctorCall != null)
+ && !ctorCall.isSuperAccess();
- JClassType enclosingType = (JClassType) ctor.getEnclosingType();
+ JClassType enclosingType = (JClassType) ctor.getEnclosingType();
- // Call clinit; $clinit is always in position 0.
- JMethod clinitMethod = (JMethod) enclosingType.methods.get(0);
- JMethodCall clinitCall = new JMethodCall(program, info, null,
- clinitMethod);
- ctor.body.statements.add(new JExpressionStatement(program, info,
- clinitCall));
+ // Call clinit; $clinit is always in position 0.
+ JMethod clinitMethod = (JMethod) enclosingType.methods.get(0);
+ JMethodCall clinitCall = new JMethodCall(program, info, null,
+ clinitMethod);
+ ctor.body.statements.add(new JExpressionStatement(program, info,
+ clinitCall));
- /*
- * All synthetic fields must be assigned, unless we have an explicit this
- * constructor call, in which case the callee will assign them for us.
- */
- if (!hasExplicitThis) {
- ReferenceBinding declaringClass = x.binding.declaringClass;
- if (declaringClass instanceof NestedTypeBinding) {
- Iterator/* <JParameter> */paramIt = ctor.params.iterator();
- NestedTypeBinding nestedBinding = (NestedTypeBinding) declaringClass;
- if (nestedBinding.enclosingInstances != null) {
- for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) {
- SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i];
- JParameter param = (JParameter) paramIt.next();
- if (arg.matchingField != null) {
+ /*
+ * All synthetic fields must be assigned, unless we have an explicit
+ * this constructor call, in which case the callee will assign them for
+ * us.
+ */
+ if (!hasExplicitThis) {
+ ReferenceBinding declaringClass = x.binding.declaringClass;
+ if (declaringClass instanceof NestedTypeBinding) {
+ Iterator/* <JParameter> */paramIt = ctor.params.iterator();
+ NestedTypeBinding nestedBinding = (NestedTypeBinding) declaringClass;
+ if (nestedBinding.enclosingInstances != null) {
+ for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) {
+ SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i];
+ JParameter param = (JParameter) paramIt.next();
+ if (arg.matchingField != null) {
+ JField field = (JField) typeMap.get(arg);
+ ctor.body.statements.add(program.createAssignmentStmt(info,
+ createVariableRef(info, field), createVariableRef(info,
+ param)));
+ }
+ }
+ }
+
+ if (nestedBinding.outerLocalVariables != null) {
+ for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) {
+ SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i];
+ JParameter param = (JParameter) paramIt.next();
JField field = (JField) typeMap.get(arg);
ctor.body.statements.add(program.createAssignmentStmt(info,
createVariableRef(info, field), createVariableRef(info,
@@ -498,57 +510,48 @@
}
}
}
+ }
- if (nestedBinding.outerLocalVariables != null) {
- for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) {
- SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i];
- JParameter param = (JParameter) paramIt.next();
- JField field = (JField) typeMap.get(arg);
- ctor.body.statements.add(program.createAssignmentStmt(info,
- createVariableRef(info, field),
- createVariableRef(info, param)));
+ // optional this or super constructor call
+ if (call != null) {
+ ctor.body.statements.add(new JExpressionStatement(program,
+ makeSourceInfo(ctorCall), call));
+ }
+
+ JExpression thisRef = createThisRef(info, enclosingType);
+
+ /*
+ * Call the synthetic instance initializer method, unless we have an
+ * explicit this constructor call, in which case the callee will.
+ */
+ if (!hasExplicitThis) {
+ // $init is always in position 1 (clinit is in 0)
+ JMethod initMethod = (JMethod) enclosingType.methods.get(1);
+ JMethodCall initCall = new JMethodCall(program, info, thisRef,
+ initMethod);
+ ctor.body.statements.add(new JExpressionStatement(program, info,
+ initCall));
+ }
+
+ // user code (finally!)
+ if (x.statements != null) {
+ for (int i = 0, n = x.statements.length; i < n; ++i) {
+ Statement origStmt = x.statements[i];
+ JStatement jstmt = dispProcessStatement(origStmt);
+ if (jstmt != null) {
+ ctor.body.statements.add(jstmt);
}
}
}
+
+ currentMethodScope = null;
+ currentMethod = null;
+
+ // synthesize a return statement to emulate returning the new object
+ ctor.body.statements.add(new JReturnStatement(program, null, thisRef));
+ } catch (Throwable e) {
+ throw translateException(ctor, e);
}
-
- // optional this or super constructor call
- if (call != null) {
- ctor.body.statements.add(new JExpressionStatement(program,
- makeSourceInfo(ctorCall), call));
- }
-
- JExpression thisRef = createThisRef(info, enclosingType);
-
- /*
- * Call the synthetic instance initializer method, unless we have an
- * explicit this constructor call, in which case the callee will.
- */
- if (!hasExplicitThis) {
- // $init is always in position 1 (clinit is in 0)
- JMethod initMethod = (JMethod) enclosingType.methods.get(1);
- JMethodCall initCall = new JMethodCall(program, info, thisRef,
- initMethod);
- ctor.body.statements.add(new JExpressionStatement(program, info,
- initCall));
- }
-
- // user code (finally!)
- if (x.statements != null) {
- for (int i = 0, n = x.statements.length; i < n; ++i) {
- Statement origStmt = x.statements[i];
- JStatement jstmt = dispProcessStatement(origStmt);
- if (jstmt != null) {
- ctor.body.statements.add(jstmt);
- }
- }
- }
-
- currentMethodScope = null;
- currentMethod = null;
-
- // synthesize a return statement to emulate returning the new object
- ctor.body.statements.add(new JReturnStatement(program, null, thisRef));
}
JExpression processExpression(AllocationExpression x) {
@@ -1198,63 +1201,69 @@
*/
return;
}
- JExpression initializer = null;
- if (declaration.initialization != null) {
- initializer = dispProcessExpression(declaration.initialization);
- }
+ try {
+ JExpression initializer = null;
+ if (declaration.initialization != null) {
+ initializer = dispProcessExpression(declaration.initialization);
+ }
- if (initializer instanceof JLiteral) {
- field.constInitializer = (JLiteral) initializer;
- } else if (initializer != null) {
- JSourceInfo info = makeSourceInfo(declaration);
- JStatement assignStmt = program.createAssignmentStmt(info,
- createVariableRef(info, field), initializer);
+ if (initializer instanceof JLiteral) {
+ field.constInitializer = (JLiteral) initializer;
+ } else if (initializer != null) {
+ JSourceInfo info = makeSourceInfo(declaration);
+ JStatement assignStmt = program.createAssignmentStmt(info,
+ createVariableRef(info, field), initializer);
- // will either be init or clinit
- currentMethod.body.statements.add(assignStmt);
+ // will either be init or clinit
+ currentMethod.body.statements.add(assignStmt);
+ }
+ } catch (Throwable e) {
+ throw translateException(field, e);
}
}
void processInitializer(Initializer initializer) {
- JBlock block = processStatement(initializer.block);
- // will either be init or clinit
- currentMethod.body.statements.add(block);
+ JBlock block = (JBlock) dispProcessStatement(initializer.block);
+ try {
+ // will either be init or clinit
+ currentMethod.body.statements.add(block);
+ } catch (Throwable e) {
+ throw translateException(initializer, e);
+ }
}
void processMethod(AbstractMethodDeclaration x) {
MethodBinding b = x.binding;
JMethod method = (JMethod) typeMap.get(b);
+ try {
+ if (b.isImplementing() || b.isOverriding()) {
+ tryFindUpRefs(method, b);
+ }
- if (b.isImplementing() || b.isOverriding()) {
- tryFindUpRefs(method, b);
- }
+ if (x.isNative()) {
+ processNativeMethod(x, (JsniMethod) method);
+ return;
+ }
- if (x.isNative()) {
- processNativeMethod(x, (JsniMethod) method);
- return;
- }
+ currentMethod = method;
+ currentMethodScope = x.scope;
- currentMethod = method;
- currentMethodScope = x.scope;
-
- if (x.statements != null) {
- for (int i = 0, n = x.statements.length; i < n; ++i) {
- Statement origStmt = x.statements[i];
- JStatement jstmt = dispProcessStatement(origStmt);
- if (jstmt != null) {
- method.body.statements.add(jstmt);
+ if (x.statements != null) {
+ for (int i = 0, n = x.statements.length; i < n; ++i) {
+ Statement origStmt = x.statements[i];
+ JStatement jstmt = dispProcessStatement(origStmt);
+ if (jstmt != null) {
+ method.body.statements.add(jstmt);
+ }
}
}
+ currentMethodScope = null;
+ currentMethod = null;
+ } catch (Throwable e) {
+ throw translateException(method, e);
}
- currentMethodScope = null;
- currentMethod = null;
}
- // // 5.0
- // JStatement processStatement(ForeachStatement x) {
- // return null;
- // }
-
void processNativeMethod(AbstractMethodDeclaration x,
JsniMethod nativeMethod) {
@@ -1319,6 +1328,11 @@
}
}
+ // // 5.0
+ // JStatement processStatement(ForeachStatement x) {
+ // return null;
+ // }
+
JStatement processStatement(AssertStatement x) {
JSourceInfo info = makeSourceInfo(x);
JExpression expr = dispProcessExpression(x.assertExpression);
@@ -1469,7 +1483,7 @@
JStatement processStatement(SynchronizedStatement x) {
JSourceInfo info = makeSourceInfo(x);
- JBlock block = processStatement(x.block);
+ JBlock block = (JBlock) dispProcessStatement(x.block);
JExpression expr = dispProcessExpression(x.expression);
block.statements.add(0, new JExpressionStatement(program, info, expr));
return block;
@@ -1483,7 +1497,7 @@
JStatement processStatement(TryStatement x) {
JSourceInfo info = makeSourceInfo(x);
- JBlock tryBlock = processStatement(x.tryBlock);
+ JBlock tryBlock = (JBlock) dispProcessStatement(x.tryBlock);
List/* <JLocalRef> */catchArgs = new ArrayList/* <JLocalRef> */();
List/* <JBlock> */catchBlocks = new ArrayList/* <JBlock> */();
if (x.catchBlocks != null) {
@@ -1492,10 +1506,10 @@
catchArgs.add(createVariableRef(info, local));
}
for (int i = 0, c = x.catchBlocks.length; i < c; ++i) {
- catchBlocks.add(processStatement(x.catchBlocks[i]));
+ catchBlocks.add(dispProcessStatement(x.catchBlocks[i]));
}
}
- JBlock finallyBlock = processStatement(x.finallyBlock);
+ JBlock finallyBlock = (JBlock) dispProcessStatement(x.finallyBlock);
return new JTryStatement(program, info, tryBlock, catchArgs, catchBlocks,
finallyBlock);
}
@@ -2014,6 +2028,24 @@
return binaryOperation;
}
+ private InternalCompilerException translateException(Object node,
+ Throwable e) {
+ InternalCompilerException ice;
+ if (e instanceof InternalCompilerException) {
+ ice = (InternalCompilerException) e;
+ } else {
+ ice = new InternalCompilerException("Error constructing Java AST", e);
+ }
+ String className = node.getClass().getName();
+ String description = node.toString();
+ JSourceInfo sourceInfo = null;
+ if (node instanceof Statement) {
+ sourceInfo = makeSourceInfo((Statement) node);
+ }
+ ice.addNode(className, description, sourceInfo);
+ return ice;
+ }
+
/**
* For a given method(and method binding), try to find all methods that it
* overrides/implements.
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/InternalCompilerException.java b/dev/core/src/com/google/gwt/dev/jjs/impl/InternalCompilerException.java
index 29d3f35..9b0a299 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/InternalCompilerException.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/InternalCompilerException.java
@@ -16,8 +16,10 @@
package com.google.gwt.dev.jjs.impl;
import com.google.gwt.dev.jjs.ast.JNode;
+import com.google.gwt.dev.jjs.ast.JSourceInfo;
-import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import java.util.ArrayList;
+import java.util.List;
/**
* Indicates the compiler encountered an unexpected and unsupported state of
@@ -25,20 +27,123 @@
*/
public class InternalCompilerException extends RuntimeException {
+ /**
+ * Tracks if there's a pending addNode() to avoid recursion sickness.
+ */
+ private static final ThreadLocal pendingICE = new ThreadLocal();
+
+ /**
+ * Information regarding a node that was being processed when an
+ * InternalCompilerException was thrown.
+ */
+ public static final class NodeInfo {
+
+ private final String className;
+ private final String description;
+ private final JSourceInfo sourceInfo;
+
+ private NodeInfo(String className, String description,
+ JSourceInfo sourceInfo) {
+ this.className = className;
+ this.description = description;
+ this.sourceInfo = sourceInfo;
+ }
+
+ /**
+ * Returns the name of the Java class of the node.
+ */
+ public String getClassName() {
+ return className;
+ }
+
+ /**
+ * Returns a text description of the node; typically toString().
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Returns the node's source info, if available; otherwise <code>null</code>.
+ */
+ public JSourceInfo getSourceInfo() {
+ return sourceInfo;
+ }
+ }
+
+ private final List nodeTrace = new ArrayList();
+
+ /**
+ * Constructs a new exception with the specified node, message, and cause.
+ */
+ public InternalCompilerException(JNode node, String message, Throwable cause) {
+ this(message, cause);
+ addNode(node);
+ }
+
+ /**
+ * Constructs a new exception with the specified message.
+ */
public InternalCompilerException(String message) {
super(message);
}
+ /**
+ * Constructs a new exception with the specified message and cause.
+ */
public InternalCompilerException(String message, Throwable cause) {
super(message, cause);
}
- public void addNode(ASTNode node) {
- // TODO Auto-generated method stub
+ /**
+ * Adds a node to the end of the node trace. This is similar to how a stack
+ * trace works.
+ */
+ public void addNode(JNode node) {
+ InternalCompilerException other = (InternalCompilerException) pendingICE.get();
+ if (other != null) {
+ // Avoiding recursion sickness: Yet Another ICE must have occured while
+ // generating info for a prior ICE. Just bail!
+ return;
+ }
+
+ String className = null;
+ String description = null;
+ JSourceInfo sourceInfo = null;
+ try {
+ pendingICE.set(this);
+ className = node.getClass().getName();
+ sourceInfo = node.getSourceInfo();
+ description = node.toString();
+ } catch (Throwable e) {
+ // ignore any exceptions
+ if (description == null) {
+ description = "<source info not available>";
+ }
+ } finally {
+ pendingICE.set(null);
+ }
+ addNode(className, description, sourceInfo);
}
- public void addNode(JNode node) {
- // TODO Auto-generated method stub
+ /**
+ * Adds information about a a node to the end of the node trace. This is
+ * similar to how a stack trace works.
+ */
+ public void addNode(String className, String description,
+ JSourceInfo sourceInfo) {
+ nodeTrace.add(new NodeInfo(className, description, sourceInfo));
+ }
+
+ /**
+ * Returns a list of nodes that were being processed when this exception was
+ * thrown. The list reflects the parent-child relationships of the AST and is
+ * is in order from children to parents. The first element of the returned
+ * list is the node that was most specifically being visited when the
+ * exception was thrown.
+ */
+ public List getNodeTrace() {
+ return nodeTrace;
}
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeMap.java b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeMap.java
index ac61804..27ae042 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeMap.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeMap.java
@@ -49,7 +49,9 @@
public JNode get(Binding binding) {
JNode result = internalGet(binding);
if (result == null) {
- throw new RuntimeException("Failed to get JNode");
+ InternalCompilerException ice = new InternalCompilerException(
+ "Failed to get JNode");
+ ice.addNode(binding.getClass().getName(), binding.toString(), null);
}
return result;
}