The compiler now generates code that emulates Class objects correctly. The motivation is in anticipation of support for EnumSet/EnumMap.
Suggested by: mmastrac
Review by: mmendez
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1488 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java
index f2a91a0..25f07a6 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java
@@ -15,11 +15,74 @@
*/
package com.google.gwt.dev.jjs.ast;
+import com.google.gwt.dev.jjs.InternalCompilerException;
+
/**
* Java class literal expression.
*/
public class JClassLiteral extends JLiteral {
+ // Matches constants in our java.lang.Class
+ private static final int PRIMITIVE = 0x00000001;
+ private static final int INTERFACE = 0x00000002;
+ private static final int ARRAY = 0x00000004;
+ private static final int ENUM = 0x00000008;
+
+ private static String getClassName(String fullName) {
+ int pos = fullName.lastIndexOf(".");
+ return fullName.substring(pos + 1);
+ }
+
+ private static String getPackageName(String fullName) {
+ int pos = fullName.lastIndexOf(".");
+ return fullName.substring(0, pos + 1);
+ }
+
+ private static JIntLiteral getTypeBitsLit(JProgram program, JType type) {
+ int bits;
+ if (type instanceof JArrayType) {
+ bits = ARRAY;
+ } else if (type instanceof JEnumType) {
+ bits = ENUM;
+ } else if (type instanceof JClassType) {
+ bits = 0;
+ } else if (type instanceof JInterfaceType) {
+ bits = INTERFACE;
+ } else if (type instanceof JPrimitiveType) {
+ bits = PRIMITIVE;
+ } else {
+ throw new InternalCompilerException("Unknown kind of type");
+ }
+ return program.getLiteralInt(bits);
+ }
+
+ private static JExpression getTypeNameLit(JProgram program, JType type) {
+ JExpression typeNameLit;
+ String typeName;
+ if (type instanceof JArrayType) {
+ typeName = type.getJsniSignatureName().replace('/', '.');
+ } else {
+ typeName = type.getName();
+ }
+
+ // Split the full class name into package + class so package strings
+ // can be merged.
+ String className = getClassName(typeName);
+ String packageName = getPackageName(typeName);
+ if (packageName.length() > 0) {
+ // use "com.example.foo." + "Foo"
+ typeNameLit = new JBinaryOperation(program, null,
+ program.getTypeJavaLangString(), JBinaryOperator.ADD,
+ program.getLiteralString(packageName),
+ program.getLiteralString(className));
+ } else {
+ // no package name could be split, just use the full name
+ typeNameLit = program.getLiteralString(typeName);
+ }
+ return typeNameLit;
+ }
+
+ private JExpression classObjectAllocation;
private final JType refType;
/**
@@ -28,6 +91,18 @@
JClassLiteral(JProgram program, JType type) {
super(program);
refType = type;
+
+ JNewInstance classAlloc = new JNewInstance(program, null,
+ program.getTypeJavaLangClass());
+ JMethodCall call = new JMethodCall(program, null, classAlloc,
+ program.getIndexedMethod("Class.Class"));
+
+ call.getArgs().add(getTypeNameLit(program, type));
+ call.getArgs().add(getTypeBitsLit(program, type));
+
+ // TODO: enums
+
+ classObjectAllocation = call;
}
public JType getRefType() {
@@ -35,11 +110,12 @@
}
public JType getType() {
- return program.getTypeJavaLangClass();
+ return classObjectAllocation.getType();
}
public void traverse(JVisitor visitor, Context ctx) {
if (visitor.visit(this, ctx)) {
+ classObjectAllocation = visitor.accept(classObjectAllocation);
}
visitor.endVisit(this, ctx);
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethodCall.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethodCall.java
index dfc89ea..6ae7b88 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethodCall.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethodCall.java
@@ -33,6 +33,7 @@
public JMethodCall(JProgram program, SourceInfo info, JExpression instance,
JMethod method) {
super(program, info);
+ assert (method != null);
assert (instance != null || method.isStatic());
this.instance = instance;
this.method = method;
@@ -41,7 +42,7 @@
}
/**
- * Create a method call whose type is overriden to the specified type,
+ * Create a method call whose type is overridden to the specified type,
* ignoring the return type of the target method. This constructor is used
* during normalizing transformations to preserve type semantics when calling
* externally-defined compiler implementation methods.
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JNewArray.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JNewArray.java
index 7c382fa..f8511ce 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JNewArray.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JNewArray.java
@@ -17,15 +17,15 @@
import com.google.gwt.dev.jjs.SourceInfo;
-import java.util.ArrayList;
+import java.util.List;
/**
* New array expression.
*/
public class JNewArray extends JExpression implements HasSettableType {
- public ArrayList<JExpression> dims = null;
- public ArrayList<JExpression> initializers = null;
+ public List<JExpression> dims = null;
+ public List<JExpression> initializers = null;
private JArrayType arrayType;
public JNewArray(JProgram program, SourceInfo info, JArrayType arrayType) {
@@ -70,10 +70,26 @@
if (dims != null) {
visitor.accept(dims);
+
+ // Visit all the class literals that will eventually get generated.
+ JArrayType it = arrayType;
+ for (JExpression dim : dims) {
+ if (dim instanceof JAbsentArrayDimension) {
+ break;
+ }
+ visitor.accept(program.getLiteralClass(it));
+ if (it.getElementType() instanceof JArrayType) {
+ it = (JArrayType) it.getElementType();
+ } else {
+ break;
+ }
+ }
}
if (initializers != null) {
visitor.accept(initializers);
+ // Visit the class literals that will eventually get generated.
+ visitor.accept(program.getLiteralClass(arrayType));
}
}
visitor.endVisit(this, ctx);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
index c6450a6..3f5134d 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
@@ -117,6 +117,8 @@
private final List<JReferenceType> allTypes = new ArrayList<JReferenceType>();
+ private Map<JType, JClassLiteral> classLiterals = new HashMap<JType, JClassLiteral>();
+
/**
* Each entry is a HashMap(JType => JArrayType), arranged such that the number
* of dimensions is that index (plus one) at which the JArrayTypes having that
@@ -447,8 +449,12 @@
}
public JClassLiteral getLiteralClass(JType type) {
- // could be interned
- return new JClassLiteral(this, type);
+ JClassLiteral result = classLiterals.get(type);
+ if (result == null) {
+ result = new JClassLiteral(this, type);
+ classLiterals.put(type, result);
+ }
+ return result;
}
public JClassSeed getLiteralClassSeed(JClassType type) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsonArray.java b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsonArray.java
index 9f7137c..4bf9d26 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsonArray.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsonArray.java
@@ -23,13 +23,14 @@
import com.google.gwt.dev.jjs.ast.JVisitor;
import java.util.ArrayList;
+import java.util.List;
/**
* A JSON-style list of JS expressions.
*/
public class JsonArray extends JExpression {
- public ArrayList exprs = new ArrayList();
+ public List<JExpression> exprs = new ArrayList<JExpression>();
public JsonArray(JProgram program) {
super(program, null);
@@ -43,7 +44,7 @@
public boolean hasSideEffects() {
for (int i = 0, c = exprs.size(); i < c; ++i) {
- if (((JExpression) exprs.get(i)).hasSideEffects()) {
+ if (exprs.get(i).hasSideEffects()) {
return true;
}
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java
index 45a9bd0..c540293 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java
@@ -44,7 +44,7 @@
private class ArrayVisitor extends JModVisitor {
- // @Override
+ @Override
public void endVisit(JBinaryOperation x, Context ctx) {
if (x.getOp() == JBinaryOperator.ASG && x.getLhs() instanceof JArrayRef) {
JArrayRef arrayRef = (JArrayRef) x.getLhs();
@@ -74,34 +74,19 @@
}
}
- // @Override
+ @Override
public void endVisit(JNewArray x, Context ctx) {
JArrayType type = x.getArrayType();
- JLiteral litTypeName = program.getLiteralString(calcClassName(type));
if (x.initializers != null) {
- processInitializers(x, ctx, type, litTypeName);
+ processInitializers(x, ctx, type);
} else if (type.getDims() == 1) {
- processDim(x, ctx, type, litTypeName);
+ processDim(x, ctx, type);
} else {
- processDims(x, ctx, type, litTypeName);
+ processDims(x, ctx, type);
}
}
- private char[] calcClassName(JArrayType type) {
- String leafName = type.getLeafType().getJsniSignatureName();
- leafName = leafName.replace('/', '.');
- int leafLength = leafName.length();
- int nDims = type.getDims();
- char[] className = new char[leafLength + nDims];
- for (int i = 0; i < nDims; ++i) {
- className[i] = '[';
- }
-
- leafName.getChars(0, leafLength, className, nDims);
- return className;
- }
-
/**
* @see com.google.gwt.lang.Array regarding seed types
*/
@@ -119,17 +104,17 @@
return program.getLiteralInt(0);
}
- private void processDim(JNewArray x, Context ctx, JArrayType arrayType,
- JLiteral litTypeName) {
+ private void processDim(JNewArray x, Context ctx, JArrayType arrayType) {
// override the type of the called method with the array's type
JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
initDim, arrayType);
+ JLiteral classLit = program.getLiteralClass(arrayType);
JLiteral typeIdLit = program.getLiteralInt(program.getTypeId(arrayType));
JLiteral queryIdLit = program.getLiteralInt(tryGetQueryId(arrayType));
JType leafType = arrayType.getLeafType();
- JExpression dim = (JExpression) x.dims.get(0);
+ JExpression dim = x.dims.get(0);
- call.getArgs().add(litTypeName);
+ call.getArgs().add(classLit);
call.getArgs().add(typeIdLit);
call.getArgs().add(queryIdLit);
call.getArgs().add(dim);
@@ -137,18 +122,18 @@
ctx.replaceMe(call);
}
- private void processDims(JNewArray x, Context ctx, JArrayType arrayType,
- JLiteral litTypeName) {
+ private void processDims(JNewArray x, Context ctx, JArrayType arrayType) {
// override the type of the called method with the array's type
JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
initDims, arrayType);
+ JsonArray classLitList = new JsonArray(program);
JsonArray typeIdList = new JsonArray(program);
JsonArray queryIdList = new JsonArray(program);
JsonArray dimList = new JsonArray(program);
JType leafType = arrayType.getLeafType();
int outstandingDims = arrayType.getDims();
for (int i = 0; i < x.dims.size(); ++i) {
- JExpression dim = (JExpression) x.dims.get(i);
+ JExpression dim = x.dims.get(i);
if (dim instanceof JAbsentArrayDimension) {
break;
}
@@ -165,10 +150,16 @@
*
*/
JArrayType cur = program.getTypeArray(leafType, outstandingDims--);
+
+ JLiteral classLit = program.getLiteralClass(cur);
+ classLitList.exprs.add(classLit);
+
JLiteral typeIdLit = program.getLiteralInt(program.getTypeId(cur));
typeIdList.exprs.add(typeIdLit);
+
JLiteral queryIdLit = program.getLiteralInt(tryGetQueryId(cur));
queryIdList.exprs.add(queryIdLit);
+
dimList.exprs.add(dim);
}
JType targetType = leafType;
@@ -176,7 +167,7 @@
targetType = program.getTypeArray(targetType, outstandingDims);
}
- call.getArgs().add(litTypeName);
+ call.getArgs().add(classLitList);
call.getArgs().add(typeIdList);
call.getArgs().add(queryIdList);
call.getArgs().add(dimList);
@@ -185,17 +176,18 @@
}
private void processInitializers(JNewArray x, Context ctx,
- JArrayType arrayType, JLiteral litTypeName) {
+ JArrayType arrayType) {
// override the type of the called method with the array's type
JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
initValues, arrayType);
+ JLiteral classLit = program.getLiteralClass(arrayType);
JLiteral typeIdLit = program.getLiteralInt(program.getTypeId(arrayType));
JLiteral queryIdLit = program.getLiteralInt(tryGetQueryId(arrayType));
JsonArray initList = new JsonArray(program);
for (int i = 0; i < x.initializers.size(); ++i) {
initList.exprs.add(x.initializers.get(i));
}
- call.getArgs().add(litTypeName);
+ call.getArgs().add(classLit);
call.getArgs().add(typeIdLit);
call.getArgs().add(queryIdLit);
call.getArgs().add(initList);
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 93873ad..24f3df6 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
@@ -430,6 +430,17 @@
}
JReferenceType type = (JReferenceType) typeMap.get(binding);
try {
+ // Create an override for getClass().
+ if (type instanceof JClassType
+ && type != program.getTypeJavaLangObject()
+ && type != program.getIndexedType("Array")) {
+ JMethod getClassMethod = program.createMethod(null,
+ "getClass".toCharArray(), type, program.getTypeJavaLangClass(),
+ false, false, false, false, false);
+ assert (type.methods.get(2) == getClassMethod);
+ getClassMethod.freezeParamTypes();
+ }
+
if (binding.isNestedType() && !binding.isStatic()) {
// add synthetic fields for outer this and locals
assert (type instanceof JClassType);
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 a6e4313..e56caf1 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
@@ -31,6 +31,7 @@
import com.google.gwt.dev.jjs.ast.JCaseStatement;
import com.google.gwt.dev.jjs.ast.JCastOperation;
import com.google.gwt.dev.jjs.ast.JCharLiteral;
+import com.google.gwt.dev.jjs.ast.JClassLiteral;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JConditional;
import com.google.gwt.dev.jjs.ast.JContinueStatement;
@@ -47,6 +48,7 @@
import com.google.gwt.dev.jjs.ast.JIfStatement;
import com.google.gwt.dev.jjs.ast.JInstanceOf;
import com.google.gwt.dev.jjs.ast.JIntLiteral;
+import com.google.gwt.dev.jjs.ast.JInterfaceType;
import com.google.gwt.dev.jjs.ast.JLabel;
import com.google.gwt.dev.jjs.ast.JLabeledStatement;
import com.google.gwt.dev.jjs.ast.JLiteral;
@@ -361,6 +363,21 @@
}
}
+ // Write the body of the getClass() override.
+ if (currentClass instanceof JClassType
+ && currentClass != program.getTypeJavaLangObject()
+ && currentClass != program.getIndexedType("Array")) {
+ JMethod method = currentClass.methods.get(2);
+ assert ("getClass".equals(method.getName()));
+
+ tryFindUpRefs(method);
+
+ JMethodBody body = (JMethodBody) method.getBody();
+ JClassLiteral classLit = program.getLiteralClass(currentClass);
+ body.getStatements().add(
+ new JReturnStatement(program, null, classLit));
+ }
+
if (x.binding.isEnum()) {
processEnumType((JEnumType) currentClass);
}
@@ -2356,6 +2373,18 @@
}
/**
+ * For a given method, try to find all methods that it overrides/implements.
+ * An experimental version that doesn't use JDT. Right now it's only used to
+ * resolve upRefs for Object.getClass(), which is synthetic on everything
+ * other than object.
+ */
+ private void tryFindUpRefs(JMethod method) {
+ if (method.getEnclosingType() != null) {
+ tryFindUpRefsRecursive(method, method.getEnclosingType());
+ }
+ }
+
+ /**
* For a given method(and method binding), try to find all methods that it
* overrides/implements.
*/
@@ -2367,6 +2396,49 @@
* For a given method(and method binding), recursively try to find all
* methods that it overrides/implements.
*/
+ private void tryFindUpRefsRecursive(JMethod method,
+ JReferenceType searchThisType) {
+
+ // See if this class has any uprefs, unless this class is myself
+ if (method.getEnclosingType() != searchThisType) {
+ outer : for (JMethod upRef : searchThisType.methods) {
+ if (upRef.isStatic()) {
+ continue;
+ }
+ if (!upRef.getName().equals(method.getName())) {
+ continue;
+ }
+ if (upRef.params.size() != method.params.size()) {
+ continue;
+ }
+ for (int i = 0, c = upRef.params.size(); i < c; ++i) {
+ if (upRef.params.get(i).getType() != method.params.get(i).getType()) {
+ continue outer;
+ }
+ }
+
+ if (!method.overrides.contains(upRef)) {
+ method.overrides.add(upRef);
+ break;
+ }
+ }
+ }
+
+ // recurse super class
+ if (searchThisType.extnds != null) {
+ tryFindUpRefsRecursive(method, searchThisType.extnds);
+ }
+
+ // recurse super interfaces
+ for (JInterfaceType intf : searchThisType.implments) {
+ tryFindUpRefsRecursive(method, intf);
+ }
+ }
+
+ /**
+ * For a given method(and method binding), recursively try to find all
+ * methods that it overrides/implements.
+ */
private void tryFindUpRefsRecursive(JMethod method, MethodBinding binding,
ReferenceBinding searchThisType) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
index 447af14..8e32999 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
@@ -22,7 +22,6 @@
import com.google.gwt.dev.jjs.ast.JAbsentArrayDimension;
import com.google.gwt.dev.jjs.ast.JAbstractMethodBody;
import com.google.gwt.dev.jjs.ast.JArrayRef;
-import com.google.gwt.dev.jjs.ast.JArrayType;
import com.google.gwt.dev.jjs.ast.JAssertStatement;
import com.google.gwt.dev.jjs.ast.JBinaryOperation;
import com.google.gwt.dev.jjs.ast.JBinaryOperator;
@@ -118,7 +117,6 @@
import com.google.gwt.dev.js.ast.JsReturn;
import com.google.gwt.dev.js.ast.JsScope;
import com.google.gwt.dev.js.ast.JsStatement;
-import com.google.gwt.dev.js.ast.JsStringLiteral;
import com.google.gwt.dev.js.ast.JsSwitch;
import com.google.gwt.dev.js.ast.JsSwitchMember;
import com.google.gwt.dev.js.ast.JsThisRef;
@@ -143,8 +141,6 @@
import java.util.Map;
import java.util.Set;
import java.util.Stack;
-import java.util.TreeMap;
-import java.util.Map.Entry;
/**
* Creates a JavaScript AST from a <code>JProgram</code> node.
@@ -268,16 +264,6 @@
}
classScopes.put(x, myScope);
- // Make a name for my package if it doesn't already exist
- String packageName = getPackageName(x.getName());
- if (packageName != null && packageName.length() > 0) {
- if (packageNames.get(packageName) == null) {
- String ident = "package_" + packageName.replace('.', '_');
- JsName jsName = topScope.declareName(ident);
- packageNames.put(packageName, jsName);
- }
- }
-
push(myScope);
return true;
}
@@ -489,10 +475,13 @@
@Override
public void endVisit(JClassLiteral x, Context ctx) {
+ JsExpression classObjectAllocation = pop(); // classObjectAllocation
+
// My seed function name
String nameString = x.getRefType().getJavahSignatureName() + "_classlit";
JsName classLit = topScope.declareName(nameString);
classLits.put(x.getRefType(), classLit);
+ classObjects.put(classLit, classObjectAllocation);
push(classLit.makeRef());
}
@@ -596,6 +585,9 @@
if (x.constInitializer != null) {
// setup the constant value
accept(x.constInitializer);
+ } else if (x == program.getIndexedField("Cast.typeIdArray")) {
+ // magic: setup the type id table
+ push(generateTypeTable());
} else if (!x.hasInitializer()) {
// setup a default value
accept(x.getType().getDefaultValue());
@@ -981,10 +973,17 @@
}
generateGwtOnLoad(entryFuncs, globalStmts);
+ generateNullFunc(globalStmts);
- // a few more vars on the very end
+ // Add a few things onto the beginning.
+
+ // Reserve the "_" identifier.
JsVars vars = new JsVars();
- generateTypeTable(vars);
+ vars.add(new JsVar(globalTemp));
+ globalStmts.add(0, vars);
+
+ // Generate class objects.
+ vars = new JsVars();
generateClassLiterals(vars);
if (!vars.isEmpty()) {
globalStmts.add(vars);
@@ -1147,22 +1146,6 @@
}
@Override
- public boolean visit(JProgram x, Context ctx) {
- List<JsStatement> globalStatements = jsProgram.getGlobalBlock().getStatements();
-
- // declare some global vars
- JsVars vars = new JsVars();
-
- // reserve the "_" identifier
- vars.add(new JsVar(globalTemp));
- generatePackageNames(vars);
- globalStatements.add(vars);
-
- generateNullFunc(globalStatements);
- return true;
- }
-
- @Override
public boolean visit(JSwitchStatement x, Context ctx) {
/*
* What a pain.. JSwitchStatement and JsSwitch are modeled completely
@@ -1214,26 +1197,12 @@
}
private void generateClassLiterals(JsVars vars) {
- /*
- * Class literals are useless right now, just use String literals and the
- * Object methods will basically work.
- */
for (Object element : classLits.keySet()) {
JType type = (JType) element;
JsName jsName = classLits.get(type);
- String string;
- if (type instanceof JArrayType) {
- string = "class " + type.getJsniSignatureName().replace('/', '.');
- } else if (type instanceof JClassType) {
- string = "class " + type.getName();
- } else if (type instanceof JInterfaceType) {
- string = "interface " + type.getName();
- } else {
- string = type.getName();
- }
- JsStringLiteral stringLiteral = jsProgram.getStringLiteral(string);
+ JsExpression classObjectAlloc = classObjects.get(jsName);
JsVar var = new JsVar(jsName);
- var.setInitExpr(stringLiteral);
+ var.setInitExpr(classObjectAlloc);
vars.add(var);
}
}
@@ -1247,7 +1216,6 @@
generateToStringAlias(x, globalStmts);
}
- generateTypeName(x, globalStmts);
generateTypeId(x, globalStmts);
}
@@ -1325,16 +1293,6 @@
globalStatements.add(nullFunc.makeStmt());
}
- private void generatePackageNames(JsVars vars) {
- for (Entry<String, JsName> entry : packageNames.entrySet()) {
- String packageName = entry.getKey();
- JsName name = entry.getValue();
- JsVar jsVar = new JsVar(name);
- jsVar.setInitExpr(jsProgram.getStringLiteral(packageName));
- vars.add(jsVar);
- }
- }
-
private void generateSeedFuncAndPrototype(JClassType x,
List<JsStatement> globalStmts) {
if (x != program.getTypeJavaLangString()) {
@@ -1421,50 +1379,14 @@
}
}
- private void generateTypeName(JClassType x, List<JsStatement> globalStmts) {
- JField typeNameField = program.getIndexedField("Object.typeName");
- JsName typeNameName = names.get(typeNameField);
- if (typeNameName == null) {
- // Was pruned; this compilation must not use GWT.getTypeName().
- return;
- }
- JsNameRef lhs = typeNameName.makeRef();
- lhs.setQualifier(globalTemp.makeRef());
-
- // Split the full class name into package + class so package strings
- // can be merged.
- String className = getClassName(x.getName());
- String packageName = getPackageName(x.getName());
- JsExpression rhs;
- if (packageName.length() > 0) {
- // use "com.example.foo." + "Foo"
- JsNameRef packageRef = (packageNames.get(packageName)).makeRef();
- rhs = new JsBinaryOperation(JsBinaryOperator.ADD, packageRef,
- jsProgram.getStringLiteral(className));
- } else {
- // no package name could be split, just use the full name
- rhs = jsProgram.getStringLiteral(x.getName());
- }
- JsExpression asg = createAssignment(lhs, rhs);
- globalStmts.add(new JsExprStmt(asg));
- }
-
- private void generateTypeTable(JsVars vars) {
- JField typeIdArray = program.getIndexedField("Cast.typeIdArray");
- JsName typeIdArrayName = names.get(typeIdArray);
- if (typeIdArrayName == null) {
- // Was pruned; this compilation must have no dynamic casts.
- return;
- }
+ private JsExpression generateTypeTable() {
JsArrayLiteral arrayLit = new JsArrayLiteral();
for (int i = 0; i < program.getJsonTypeTable().size(); ++i) {
JsonObject jsonObject = program.getJsonTypeTable().get(i);
accept(jsonObject);
arrayLit.getExpressions().add((JsExpression) pop());
}
- JsVar var = new JsVar(typeIdArrayName);
- var.setInitExpr(arrayLit);
- vars.add(var);
+ return arrayLit;
}
private void generateVTables(JClassType x, List<JsStatement> globalStmts) {
@@ -1534,7 +1456,7 @@
private <T extends JsVisitable> List<T> popList(int count) {
List<T> list = new ArrayList<T>();
while (count > 0) {
- T item = this.<T>pop();
+ T item = this.<T> pop();
if (item != null) {
list.add(item);
}
@@ -1548,7 +1470,7 @@
int count) {
List<T> list = new ArrayList<T>();
while (count > 0) {
- T item = this.<T>pop();
+ T item = this.<T> pop();
if (item != null) {
list.add(item);
}
@@ -1658,18 +1580,9 @@
generateJavaScriptAST.execImpl();
}
- private static String getClassName(String fullName) {
- int pos = fullName.lastIndexOf(".");
- return fullName.substring(pos + 1);
- }
-
- private static String getPackageName(String fullName) {
- int pos = fullName.lastIndexOf(".");
- return fullName.substring(0, pos + 1);
- }
-
private final Map<JBlock, JsCatch> catchMap = new IdentityHashMap<JBlock, JsCatch>();
private final Map<JType, JsName> classLits = new IdentityHashMap<JType, JsName>();
+ private final Map<JsName, JsExpression> classObjects = new IdentityHashMap<JsName, JsExpression>();
private final Map<JClassType, JsScope> classScopes = new IdentityHashMap<JClassType, JsScope>();
/**
@@ -1689,7 +1602,6 @@
* and toString. All other class scopes have this scope as an ultimate parent.
*/
private final JsScope objectScope;
- private final Map<String, JsName> packageNames = new TreeMap<String, JsName>();
private final Map<JMethod, JsName> polymorphicNames = new IdentityHashMap<JMethod, JsName>();
private final JProgram program;
@@ -1739,6 +1651,7 @@
specialObfuscatedTypes.add(program.getIndexedType("Array"));
// Object polymorphic
+ specialObfuscatedIdents.put("getClass", "gC");
specialObfuscatedIdents.put("hashCode", "hC");
specialObfuscatedIdents.put("equals", "eQ");
specialObfuscatedIdents.put("toString", "tS");
@@ -1755,6 +1668,7 @@
specialObfuscatedIdents.put("subSequence", "sS");
// Array magic field
+ specialObfuscatedIdents.put("arrayClass", "aC");
specialObfuscatedIdents.put("queryId", "qI");
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectCaster.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectCaster.java
index 4ffd2fd..62c87dc 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectCaster.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectCaster.java
@@ -32,7 +32,7 @@
import com.google.gwt.dev.jjs.ast.JReturnStatement;
import com.google.gwt.dev.jjs.ast.JType;
-import java.util.ArrayList;
+import java.util.List;
/**
* Synthesize casts for JavaScriptObject types in cases where dynamic type
@@ -47,7 +47,7 @@
private JMethod currentMethod;
- // @Override
+ @Override
public void endVisit(JBinaryOperation x, Context ctx) {
if (x.isAssignment()) {
JType lhsType = x.getLhs().getType();
@@ -67,7 +67,7 @@
}
}
- // @Override
+ @Override
public void endVisit(JConditional x, Context ctx) {
JExpression newThen = checkAndReplaceJso(x.getThenExpr(), x.getType());
JExpression newElse = checkAndReplaceJso(x.getElseExpr(), x.getType());
@@ -78,7 +78,7 @@
}
}
- // @Override
+ @Override
public void endVisit(JLocalDeclarationStatement x, Context ctx) {
JExpression newInst = x.getInitializer();
if (newInst != null) {
@@ -91,17 +91,17 @@
}
}
- // @Override
+ @Override
public void endVisit(JMethod x, Context ctx) {
currentMethod = null;
}
- // @Override
+ @Override
public void endVisit(JMethodCall x, Context ctx) {
for (int i = 0; i < x.getTarget().params.size(); ++i) {
- JParameter param = (JParameter) x.getTarget().params.get(i);
- JExpression newArg = checkAndReplaceJso(
- (JExpression) x.getArgs().get(i), param.getType());
+ JParameter param = x.getTarget().params.get(i);
+ JExpression newArg = checkAndReplaceJso(x.getArgs().get(i),
+ param.getType());
x.getArgs().set(i, newArg);
}
if (!x.getTarget().isStatic()) {
@@ -117,13 +117,12 @@
}
}
- // @Override
+ @Override
public void endVisit(JNewArray x, Context ctx) {
- JType leafType = x.getArrayType().getElementType();
- ArrayList initializers = x.initializers;
+ List<JExpression> initializers = x.initializers;
if (initializers != null) {
for (int i = 0; i < initializers.size(); ++i) {
- JExpression intializer = (JExpression) initializers.get(i);
+ JExpression intializer = initializers.get(i);
JExpression newInitializer = checkAndReplaceJsoArrayStore(intializer,
x.getArrayType().getLeafType());
if (intializer != newInitializer) {
@@ -134,7 +133,7 @@
}
}
- // @Override
+ @Override
public void endVisit(JReturnStatement x, Context ctx) {
if (x.getExpr() != null) {
JExpression newExpr = checkAndReplaceJso(x.getExpr(),
@@ -147,7 +146,7 @@
}
}
- // @Override
+ @Override
public boolean visit(JMethod x, Context ctx) {
currentMethod = x;
return true;
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
index ad688a5..5832632 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
@@ -21,7 +21,6 @@
import com.google.gwt.dev.jjs.ast.JArrayType;
import com.google.gwt.dev.jjs.ast.JBinaryOperation;
import com.google.gwt.dev.jjs.ast.JBinaryOperator;
-import com.google.gwt.dev.jjs.ast.JClassLiteral;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JExpression;
import com.google.gwt.dev.jjs.ast.JField;
@@ -323,14 +322,6 @@
}
@Override
- public boolean visit(JClassLiteral literal, Context ctx) {
- // rescue and instantiate java.lang.Class
- // JLS 12.4.1: do not rescue the target type
- rescue(program.getTypeJavaLangClass(), true, true);
- return true;
- }
-
- @Override
public boolean visit(JClassType type, Context ctx) {
assert (referencedTypes.contains(type));
boolean isInstantiated = instantiatedTypes.contains(type);
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
index 2bb0bfc..1581836 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
@@ -43,7 +43,7 @@
public static <T> T[] cloneSubrange(T[] array, int fromIndex, int toIndex) {
Array a = asArrayType(array);
Array result = arraySlice(a, fromIndex, toIndex);
- initValues(a.typeName, a.typeId, a.queryId, result);
+ initValues(a.getClass(), a.typeId, a.queryId, result);
return asArray(result);
}
@@ -54,7 +54,7 @@
public static <T> T[] clonify(T[] array, int length) {
Array a = asArrayType(array);
Array result = createFromSeed(NULL_SEED_TYPE, length);
- initValues(a.typeName, a.typeId, a.queryId, result);
+ initValues(a.getClass(), a.typeId, a.queryId, result);
return asArray(result);
}
@@ -62,17 +62,17 @@
* Creates an array like "new T[a][b][c][][]" by passing in a native JSON
* array, [a, b, c].
*
- * @param typeName the typeName of the array
+ * @param arrayClass the class of the array
* @param typeId the typeId of the array
* @param queryId the queryId of the array
* @param length the length of the array
* @param seedType the primitive type of the array; 0: null; 1: zero; 2: false
* @return the new array
*/
- public static Array initDim(String typeName, int typeId, int queryId,
+ public static Array initDim(Class arrayClass, int typeId, int queryId,
int length, int seedType) {
Array result = createFromSeed(seedType, length);
- initValues(typeName, typeId, queryId, result);
+ initValues(arrayClass, typeId, queryId, result);
return result;
}
@@ -80,16 +80,16 @@
* Creates an array like "new T[a][b][c][][]" by passing in a native JSON
* array, [a, b, c].
*
- * @param typeName the typeName of the array
+ * @param arrayClasses the class of each dimension of the array
* @param typeIdExprs the typeId at each dimension, from highest to lowest
* @param queryIdExprs the queryId at each dimension, from highest to lowest
* @param dimExprs the length at each dimension, from highest to lower
* @param seedType the primitive type of the array; 0: null; 1: zero; 2: false
* @return the new array
*/
- public static Array initDims(String typeName, int[] typeIdExprs,
+ public static Array initDims(Class arrayClasses[], int[] typeIdExprs,
int[] queryIdExprs, int[] dimExprs, int seedType) {
- return initDims(typeName, typeIdExprs, queryIdExprs, dimExprs, 0,
+ return initDims(arrayClasses, typeIdExprs, queryIdExprs, dimExprs, 0,
dimExprs.length, seedType);
}
@@ -97,19 +97,19 @@
* Creates an array like "new T[][]{a,b,c,d}" by passing in a native JSON
* array, [a, b, c, d].
*
- * @param typeName the typeName of the array
+ * @param arrayClass the class of the array
* @param typeId the typeId of the array
* @param queryId the queryId of the array
* @param array the JSON array that will be transformed into a GWT array
* @return values; having wrapped it for GWT
*/
- public static final Array initValues(String typeName, int typeId,
+ public static final Array initValues(Class arrayClass, int typeId,
int queryId, Array array) {
if (protoTypeArray == null) {
protoTypeArray = new Array();
}
wrapArray(array, protoTypeArray);
- array.typeName = typeName;
+ array.arrayClass = arrayClass;
array.typeId = typeId;
array.queryId = queryId;
return array;
@@ -168,7 +168,7 @@
return blankArray;
}-*/;
- private static Array initDims(String typeName, int[] typeIdExprs,
+ private static Array initDims(Class arrayClasses[], int[] typeIdExprs,
int[] queryIdExprs, int[] dimExprs, int index, int count, int seedType) {
int length = dimExprs[index];
if (length < 0) {
@@ -178,14 +178,13 @@
boolean isLastDim = (index == (count - 1));
Array result = createFromSeed(isLastDim ? seedType : NULL_SEED_TYPE, length);
- initValues(typeName, typeIdExprs[index], queryIdExprs[index], result);
+ initValues(arrayClasses[index], typeIdExprs[index], queryIdExprs[index], result);
if (!isLastDim) {
// Recurse to next dimension.
++index;
- typeName = typeName.substring(1);
for (int i = 0; i < length; ++i) {
- set(result, i, initDims(typeName, typeIdExprs, queryIdExprs, dimExprs,
+ set(result, i, initDims(arrayClasses, typeIdExprs, queryIdExprs, dimExprs,
index, count, seedType));
}
}
@@ -218,5 +217,11 @@
* wrapArray(Array, Array).
*/
public int length = 0;
+ protected Class arrayClass = null;
protected int queryId = 0;
+
+ @Override
+ public Class getClass() {
+ return arrayClass;
+ }
}
diff --git a/user/src/com/google/gwt/core/client/GWT.java b/user/src/com/google/gwt/core/client/GWT.java
index 75a1279..a38907c 100644
--- a/user/src/com/google/gwt/core/client/GWT.java
+++ b/user/src/com/google/gwt/core/client/GWT.java
@@ -23,7 +23,7 @@
public final class GWT {
/*
* This is the web mode version of this class. Because it's so special,
- * there's also a hosted mode version. See GWT.java-hosted.
+ * there's also a hosted mode version. See GWT.java-hosted.
*/
/**
@@ -107,9 +107,9 @@
* @return the class name of the specified object, or <code>null</code> if
* <code>o</code> is <code>null</code>
*/
- public static native String getTypeName(Object o) /*-{
- return (o == null) ? null : o.@java.lang.Object::typeName;
- }-*/;
+ public static String getTypeName(Object o) {
+ return (o == null) ? null : o.getClass().getName();
+ }
/**
* Returns the currently active uncaughtExceptionHandler. "Top level" methods
diff --git a/user/super/com/google/gwt/emul/java/lang/Class.java b/user/super/com/google/gwt/emul/java/lang/Class.java
index dc9b322..1e4f83b 100644
--- a/user/super/com/google/gwt/emul/java/lang/Class.java
+++ b/user/super/com/google/gwt/emul/java/lang/Class.java
@@ -21,18 +21,53 @@
*
* @param <T> the type of the object
*/
-public class Class<T> {
+public final class Class<T> {
+
+ private static final int PRIMITIVE = 0x00000001;
+ private static final int INTERFACE = 0x00000002;
+ private static final int ARRAY = 0x00000004;
+ private static final int ENUM = 0x00000008;
+
+ private final String typeName;
+ private final int modifiers;
/**
- * Not instantiable.
+ * Not publicly instantiable.
*
* @skip
*/
- private Class() {
+ Class(String typeName, int modifiers) {
+ this.typeName = typeName;
+ this.modifiers = modifiers;
}
public T[] getEnumConstants() {
- throw new UnsupportedOperationException(
- "Class.getEnumConstants() not yet implemented");
+ // TODO
+ return null;
+ }
+
+ public String getName() {
+ return typeName;
+ }
+
+ public boolean isArray() {
+ return (modifiers & ARRAY) != 0;
+ }
+
+ public boolean isEnum() {
+ return (modifiers & ENUM) != 0;
+ }
+
+ public boolean isInterface() {
+ return (modifiers & INTERFACE) != 0;
+ }
+
+ public boolean isPrimitive() {
+ return (modifiers & PRIMITIVE) != 0;
+ }
+
+ public String toString() {
+ return (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
+ + getName();
}
}
diff --git a/user/super/com/google/gwt/emul/java/lang/Object.java b/user/super/com/google/gwt/emul/java/lang/Object.java
index 0624089..fc9b233 100644
--- a/user/super/com/google/gwt/emul/java/lang/Object.java
+++ b/user/super/com/google/gwt/emul/java/lang/Object.java
@@ -29,23 +29,25 @@
*/
protected transient int typeId;
- /**
- * magic magic magic.
- *
- * @skip
- */
- protected transient String typeName;
-
public native boolean equals(Object other) /*-{
return this === other;
}-*/;
+ /*
+ * Magic; unlike the real JDT, we don't spec this method as final. The
+ * compiler will generate a polymorphic override on every other class which
+ * will return the correct class object.
+ */
+ public Class<? extends Object> getClass() {
+ return Object.class;
+ }
+
public int hashCode() {
return System.identityHashCode(this);
}
public String toString() {
- return typeName + "@" + hashCode();
+ return getClass().getName() + "@" + hashCode();
}
/**
diff --git a/user/super/com/google/gwt/emul/java/lang/Throwable.java b/user/super/com/google/gwt/emul/java/lang/Throwable.java
index 0510635..23649d4 100644
--- a/user/super/com/google/gwt/emul/java/lang/Throwable.java
+++ b/user/super/com/google/gwt/emul/java/lang/Throwable.java
@@ -104,7 +104,7 @@
if (currentCause != this) {
msg.append("Caused by: ");
}
- msg.append(currentCause.typeName);
+ msg.append(currentCause.getClass().getName());
msg.append(": ");
msg.append(causeMessage == null ? "(No exception detail)" : causeMessage);
msg.append("\n");