Removed use of a global table (typeIdArray) for testing castability between types. This information is now stored per class prototype as a castableMap.
Review at http://gwt-code-reviews.appspot.com/750801
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@8548 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/CastableTypeMap.java b/dev/core/src/com/google/gwt/core/ext/linker/CastableTypeMap.java
new file mode 100644
index 0000000..62f0b50
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/linker/CastableTypeMap.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2010 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.core.ext.linker;
+
+import java.io.Serializable;
+
+/**
+ * An encapsulation of a JSON map containing a set of castable type ids.
+ */
+public interface CastableTypeMap extends Serializable {
+
+ /**
+ * Returns an eval-able JSON object.
+ */
+ String toJs();
+}
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/SymbolData.java b/dev/core/src/com/google/gwt/core/ext/linker/SymbolData.java
index 5216fbf..c286a54 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/SymbolData.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/SymbolData.java
@@ -79,6 +79,11 @@
return o1.getJsniIdent().compareTo(o2.getJsniIdent());
}
}
+
+ /**
+ * Returns a JSON map of castableTypes
+ */
+ CastableTypeMap getCastableTypeMap();
/**
* Returns the name of the type or enclosing type if the symbol is a method or
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCastableTypeMap.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCastableTypeMap.java
new file mode 100644
index 0000000..0313d5d
--- /dev/null
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCastableTypeMap.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2010 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.core.ext.linker.impl;
+
+import com.google.gwt.core.ext.linker.CastableTypeMap;
+
+/**
+ * The standard implementation of {@link CastableTypeMap}.
+ */
+public class StandardCastableTypeMap implements CastableTypeMap {
+
+ final String jsonData;
+ public StandardCastableTypeMap(String jsonData) {
+ this.jsonData = jsonData;
+ }
+
+ public String toJs() {
+ return jsonData;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardSymbolData.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardSymbolData.java
index 68ebda2..0688a03 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardSymbolData.java
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardSymbolData.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.core.ext.linker.impl;
+import com.google.gwt.core.ext.linker.CastableTypeMap;
import com.google.gwt.core.ext.linker.SymbolData;
import java.io.File;
@@ -31,15 +32,15 @@
public class StandardSymbolData implements SymbolData {
public static StandardSymbolData forClass(String className, String uriString,
- int lineNumber, int typeId) {
+ int lineNumber, int typeId, CastableTypeMap castableTypeMap) {
return new StandardSymbolData(className, null, null, uriString, lineNumber,
- typeId);
+ typeId, castableTypeMap);
}
public static StandardSymbolData forMember(String className,
String memberName, String methodSig, String uriString, int lineNumber) {
return new StandardSymbolData(className, memberName, methodSig, uriString,
- lineNumber, 0);
+ lineNumber, 0, null);
}
public static String toUriString(String fileName) {
@@ -62,9 +63,11 @@
private String sourceUri;
private String symbolName;
private int typeId;
+ private CastableTypeMap castableTypeMap;
private StandardSymbolData(String className, String memberName,
- String methodSig, String sourceUri, int sourceLine, int typeId) {
+ String methodSig, String sourceUri, int sourceLine, int typeId,
+ CastableTypeMap castableTypeMap) {
assert className != null && className.length() > 0 : "className";
assert memberName != null || methodSig == null : "methodSig without memberName";
assert sourceLine >= -1 : "sourceLine: " + sourceLine;
@@ -75,6 +78,11 @@
this.sourceUri = sourceUri;
this.sourceLine = sourceLine;
this.typeId = typeId;
+ this.castableTypeMap = castableTypeMap;
+ }
+
+ public CastableTypeMap getCastableTypeMap() {
+ return castableTypeMap;
}
public String getClassName() {
@@ -152,6 +160,7 @@
sourceUri = (String) in.readObject();
symbolName = in.readUTF();
typeId = in.readInt();
+ castableTypeMap = (CastableTypeMap) in.readObject();
}
/**
@@ -179,5 +188,6 @@
out.writeObject(sourceUri);
out.writeUTF(symbolName);
out.writeInt(typeId);
+ out.writeObject(castableTypeMap);
}
}
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 0e85647..397f6f5 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
@@ -318,7 +318,7 @@
*/
private final SourceInfo intrinsic;
- private List<JsonObject> jsonTypeTable;
+ private List<JsonObject> jsonCastableTypeMaps;
private Map<JReferenceType, JNonNullType> nonNullTypes = new IdentityHashMap<JReferenceType, JNonNullType>();
@@ -766,6 +766,20 @@
return allEntryMethods;
}
+ public JsonObject getCastableTypeMap(int typeId) {
+ // ensure jsonCastableTypeMaps has been initialized
+ // it might not have been if the CastNormalizer has not been run
+ if (jsonCastableTypeMaps == null) {
+ jsonCastableTypeMaps = new ArrayList<JsonObject>();
+ // ensure the always-false (typeId == 0) entry is present
+ jsonCastableTypeMaps.add(new JsonObject(createSourceInfoSynthetic(
+ JProgram.class, "always-false typeinfo entry"),
+ getJavaScriptObject()));
+ }
+
+ return jsonCastableTypeMaps.get(typeId);
+ }
+
public CorrelationFactory getCorrelator() {
return correlator;
}
@@ -827,10 +841,6 @@
return typeSpecialJavaScriptObject;
}
- public List<JsonObject> getJsonTypeTable() {
- return jsonTypeTable;
- }
-
public JExpression getLiteralAbsentArrayDimension() {
return JAbsentArrayDimension.INSTANCE;
}
@@ -1161,7 +1171,7 @@
for (int i = 0, c = types.size(); i < c; ++i) {
typeIdMap.put(types.get(i), Integer.valueOf(i));
}
- this.jsonTypeTable = jsonObjects;
+ this.jsonCastableTypeMaps = jsonObjects;
}
public boolean isJavaLangString(JType type) {
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 14f1f2a..20b2993 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
@@ -35,6 +35,7 @@
import com.google.gwt.dev.jjs.ast.JReferenceType;
import com.google.gwt.dev.jjs.ast.JType;
import com.google.gwt.dev.jjs.ast.js.JsonArray;
+import com.google.gwt.dev.jjs.ast.js.JsonObject;
/**
* Replace array accesses and instantiations with calls to the Array class.
@@ -123,11 +124,15 @@
JMethodCall call = new JMethodCall(x.getSourceInfo(), null, initDim,
arrayType);
JLiteral classLit = x.getClassLiteral();
- JLiteral typeIdLit = program.getLiteralInt(program.getTypeId(arrayType));
+
+ int typeId = program.getTypeId(arrayType);
+ JLiteral typeIdLit = program.getLiteralInt(typeId);
+ JsonObject castableTypeMap = program.getCastableTypeMap(typeId);
+
JLiteral queryIdLit = program.getLiteralInt(tryGetQueryId(arrayType));
JExpression dim = x.dims.get(0);
JType elementType = arrayType.getElementType();
- call.addArgs(classLit, typeIdLit, queryIdLit, dim,
+ call.addArgs(classLit, typeIdLit, castableTypeMap, queryIdLit, dim,
getSeedTypeLiteralFor(elementType));
ctx.replaceMe(call);
}
@@ -142,6 +147,8 @@
program.getJavaScriptObject());
JsonArray typeIdList = new JsonArray(sourceInfo,
program.getJavaScriptObject());
+ JsonArray castableTypeMapList = new JsonArray(sourceInfo,
+ program.getJavaScriptObject());
JsonArray queryIdList = new JsonArray(sourceInfo,
program.getJavaScriptObject());
JsonArray dimList = new JsonArray(sourceInfo,
@@ -154,8 +161,12 @@
JLiteral classLit = x.getClassLiterals().get(i);
classLitList.exprs.add(classLit);
- JLiteral typeIdLit = program.getLiteralInt(program.getTypeId(curArrayType));
+ int typeId = program.getTypeId(curArrayType);
+ JLiteral typeIdLit = program.getLiteralInt(typeId);
typeIdList.exprs.add(typeIdLit);
+
+ JsonObject castableTypeMap = program.getCastableTypeMap(typeId);
+ castableTypeMapList.exprs.add(castableTypeMap);
JLiteral queryIdLit = program.getLiteralInt(tryGetQueryId(curArrayType));
queryIdList.exprs.add(queryIdLit);
@@ -163,8 +174,8 @@
dimList.exprs.add(x.dims.get(i));
cur = curArrayType.getElementType();
}
- call.addArgs(classLitList, typeIdList, queryIdList, dimList,
- program.getLiteralInt(dims), getSeedTypeLiteralFor(cur));
+ call.addArgs(classLitList, typeIdList, castableTypeMapList, queryIdList,
+ dimList, program.getLiteralInt(dims), getSeedTypeLiteralFor(cur));
ctx.replaceMe(call);
}
@@ -176,14 +187,18 @@
JMethodCall call = new JMethodCall(sourceInfo, null, initValues,
arrayType);
JLiteral classLit = x.getClassLiteral();
- JLiteral typeIdLit = program.getLiteralInt(program.getTypeId(arrayType));
+
+ int typeId = program.getTypeId(arrayType);
+ JLiteral typeIdLit = program.getLiteralInt(typeId);
+ JsonObject castableTypeMap = program.getCastableTypeMap(typeId);
+
JLiteral queryIdLit = program.getLiteralInt(tryGetQueryId(arrayType));
JsonArray initList = new JsonArray(sourceInfo,
program.getJavaScriptObject());
for (int i = 0; i < x.initializers.size(); ++i) {
initList.exprs.add(x.initializers.get(i));
}
- call.addArgs(classLit, typeIdLit, queryIdLit, initList);
+ call.addArgs(classLit, typeIdLit, castableTypeMap, queryIdLit, initList);
ctx.replaceMe(call);
}
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 e1d1910..0d2b50f 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
@@ -16,6 +16,8 @@
package com.google.gwt.dev.jjs.impl;
import com.google.gwt.core.ext.PropertyOracle;
+import com.google.gwt.core.ext.linker.CastableTypeMap;
+import com.google.gwt.core.ext.linker.impl.StandardCastableTypeMap;
import com.google.gwt.core.ext.linker.impl.StandardSymbolData;
import com.google.gwt.dev.jjs.HasSourceInfo;
import com.google.gwt.dev.jjs.InternalCompilerException;
@@ -444,9 +446,13 @@
private void recordSymbol(JReferenceType x, JsName jsName) {
int typeId = program.getTypeId(x);
+
+ JsonObject castableTypeMapObj = program.getCastableTypeMap(typeId);
+ CastableTypeMap castableTypeMap = new StandardCastableTypeMap(castableTypeMapObj.toString());
+
StandardSymbolData symbolData = StandardSymbolData.forClass(x.getName(),
x.getSourceInfo().getFileName(), x.getSourceInfo().getStartLine(),
- typeId);
+ typeId, castableTypeMap);
assert !symbolTable.containsKey(symbolData);
symbolTable.put(symbolData, jsName);
}
@@ -766,9 +772,6 @@
if (x.getLiteralInitializer() != null) {
// setup the constant value
accept(x.getLiteralInitializer());
- } else if (x == program.getIndexedField("Cast.typeIdArray")) {
- // magic: setup the type id table
- push(generateTypeTable());
} else if (!x.hasInitializer()
&& x.getEnclosingType() != program.getTypeJavaLangObject()) {
// setup a default value
@@ -1496,7 +1499,36 @@
return new JsBinaryOperation(lhs.getSourceInfo(), JsBinaryOperator.COMMA,
lhs, rhs);
}
-
+
+ private void generateCastableTypeIds(JClassType x, List<JsStatement> globalStmts) {
+ int typeId = program.getTypeId(x);
+ if (typeId >= 0) {
+ JField castableTypeMapField = program.getIndexedField("Object.castableTypeMap");
+ JsName castableTypeMapName = names.get(castableTypeMapField);
+ if (castableTypeMapName == null) {
+ // Was pruned; this compilation must have no dynamic casts.
+ return;
+ }
+
+ SourceInfo sourceInfo = jsProgram.createSourceInfoSynthetic(
+ GenerateJavaScriptAST.class, "Castable type map");
+
+ JsonObject jsonObject = program.getCastableTypeMap(typeId);
+ accept(jsonObject);
+ JsExpression objExpr = pop();
+
+ // Generate castableTypeMap for each type prototype
+ // _.castableTypeMap$ = {2:1, 4:1, 12:1};
+ JsNameRef fieldRef = castableTypeMapName.makeRef(sourceInfo);
+ fieldRef.setQualifier(globalTemp.makeRef(sourceInfo));
+ JsExpression asg = createAssignment(fieldRef, objExpr);
+
+ JsExprStmt asgStmt = asg.makeStmt();
+ globalStmts.add(asgStmt);
+ typeForStatMap.put(asgStmt, x);
+ }
+ }
+
private void generateClassLiteral(JDeclarationStatement decl, JsVars vars) {
JField field = (JField) decl.getVariableRef().getTarget();
JsName jsName = names.get(field);
@@ -1533,6 +1565,7 @@
}
generateTypeId(x, globalStmts);
+ generateCastableTypeIds(x, globalStmts);
}
private void generateGwtOnLoad(List<JsFunction> entryFuncs,
@@ -1793,19 +1826,7 @@
globalStmts.add(stmt);
typeForStatMap.put(stmt, program.getTypeJavaLangObject());
}
-
- private JsExpression generateTypeTable() {
- JsArrayLiteral arrayLit = new JsArrayLiteral(
- jsProgram.createSourceInfoSynthetic(GenerateJavaScriptAST.class,
- "Type table"));
- for (int i = 0; i < program.getJsonTypeTable().size(); ++i) {
- JsonObject jsonObject = program.getJsonTypeTable().get(i);
- accept(jsonObject);
- arrayLit.getExpressions().add((JsExpression) pop());
- }
- return arrayLit;
- }
-
+
private void generateVTables(JClassType x, List<JsStatement> globalStmts) {
for (JMethod method : x.getMethods()) {
SourceInfo sourceInfo = method.getSourceInfo().makeChild(
@@ -2137,6 +2158,7 @@
specialObfuscatedIdents.put("expando", "eX");
specialObfuscatedIdents.put("typeId", "tI");
specialObfuscatedIdents.put("typeMarker", "tM");
+ specialObfuscatedIdents.put("castableTypeMap", "cM");
// String polymorphic
specialObfuscatedIdents.put("charAt", "cA");
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 832dc9b..89a5246 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
@@ -15,6 +15,8 @@
*/
package com.google.gwt.lang;
+import com.google.gwt.core.client.JavaScriptObject;
+
/**
* This is a magic class the compiler uses as a base class for injected array
* classes.
@@ -95,7 +97,8 @@
public static <T> T[] cloneSubrange(T[] array, int fromIndex, int toIndex) {
Array a = asArrayType(array);
Array result = arraySlice(a, fromIndex, toIndex);
- initValues(a.getClass(), Util.getTypeId(a), a.queryId, result);
+ initValues(a.getClass(), Util.getTypeId(a),
+ Util.getCastableTypeMap(a), a.queryId, result);
// implicit type arg not inferred (as of JDK 1.5.0_07)
return Array.<T> asArray(result);
}
@@ -114,7 +117,8 @@
public static <T> T[] createFrom(T[] array, int length) {
Array a = asArrayType(array);
Array result = createFromSeed(NULL_SEED_TYPE, length);
- initValues(a.getClass(), Util.getTypeId(a), a.queryId, result);
+ initValues(a.getClass(), Util.getTypeId(a),
+ Util.getCastableTypeMap(a), a.queryId, result);
// implicit type arg not inferred (as of JDK 1.5.0_07)
return Array.<T> asArray(result);
}
@@ -125,15 +129,17 @@
*
* @param arrayClass the class of the array
* @param typeId the typeId of the array
+ * @param castableTypeMap the map of types to which this array can be casted,
+ * in the form of a JSON map object
* @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(Class<?> arrayClass, int typeId, int queryId,
- int length, int seedType) {
+ public static Array initDim(Class<?> arrayClass, int typeId,
+ JavaScriptObject castableTypeMap, int queryId, int length, int seedType) {
Array result = createFromSeed(seedType, length);
- initValues(arrayClass, typeId, queryId, result);
+ initValues(arrayClass, typeId, castableTypeMap, queryId, result);
return result;
}
@@ -142,16 +148,19 @@
* array, [a, b, c].
*
* @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 typeIdExprs the typeId of each dimension, from highest to lowest
+ * @param castableTypeMapExprs the JSON castableTypeMap of each dimension,
+ * from highest to lowest
+ * @param queryIdExprs the queryId of each dimension, from highest to lowest
+ * @param dimExprs the length of 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(Class<?> arrayClasses[], int[] typeIdExprs,
- int[] queryIdExprs, int[] dimExprs, int count, int seedType) {
- return initDims(arrayClasses, typeIdExprs, queryIdExprs, dimExprs, 0,
- count, seedType);
+ JavaScriptObject[] castableTypeMapExprs, int[] queryIdExprs, int[] dimExprs,
+ int count, int seedType) {
+ return initDims(arrayClasses, typeIdExprs, castableTypeMapExprs, queryIdExprs,
+ dimExprs, 0, count, seedType);
}
/**
@@ -160,15 +169,18 @@
*
* @param arrayClass the class of the array
* @param typeId the typeId of the array
+ * @param castableTypeMap the map of types to which this array can be casted,
+ * in the form of a JSON map object
* @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 Array initValues(Class<?> arrayClass, int typeId, int queryId,
- Array array) {
+ public static Array initValues(Class<?> arrayClass, int typeId,
+ JavaScriptObject castableTypeMap, int queryId, Array array) {
ExpandoWrapper.wrapArray(array);
array.arrayClass = arrayClass;
Util.setTypeId(array, typeId);
+ Util.setCastableTypeMap(array, castableTypeMap);
array.queryId = queryId;
return array;
}
@@ -178,7 +190,7 @@
*/
public static Object setCheck(Array array, int index, Object value) {
if (value != null) {
- if (array.queryId > 0 && !Cast.canCastUnsafe(Util.getTypeId(value), array.queryId)) {
+ if (array.queryId > 0 && !Cast.canCastUnsafe(value, array.queryId)) {
throw new ArrayStoreException();
}
if (array.queryId < 0 && Cast.isJavaObject(value)) {
@@ -236,19 +248,22 @@
}-*/;
private static Array initDims(Class<?> arrayClasses[], int[] typeIdExprs,
- int[] queryIdExprs, int[] dimExprs, int index, int count, int seedType) {
+ JavaScriptObject[] castableTypeMapExprs, int[] queryIdExprs, int[] dimExprs,
+ int index, int count, int seedType) {
+
int length = dimExprs[index];
boolean isLastDim = (index == (count - 1));
Array result = createFromSeed(isLastDim ? seedType : NULL_SEED_TYPE, length);
- initValues(arrayClasses[index], typeIdExprs[index], queryIdExprs[index], result);
+ initValues(arrayClasses[index], typeIdExprs[index],
+ castableTypeMapExprs[index], queryIdExprs[index], result);
if (!isLastDim) {
// Recurse to next dimension.
++index;
for (int i = 0; i < length; ++i) {
- set(result, i, initDims(arrayClasses, typeIdExprs, queryIdExprs, dimExprs,
- index, count, seedType));
+ set(result, i, initDims(arrayClasses, typeIdExprs, castableTypeMapExprs,
+ queryIdExprs, dimExprs, index, count, seedType));
}
}
return result;
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
index 6310a50..ff10bf4 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
@@ -25,19 +25,18 @@
*/
final class Cast {
- // magic magic magic
- protected static Object typeIdArray;
-
- static native boolean canCast(int srcId, int dstId) /*-{
- return srcId && !!@com.google.gwt.lang.Cast::typeIdArray[srcId][dstId];
+ static native boolean canCast(Object src, int dstId) /*-{
+ return src.@java.lang.Object::typeId &&
+ !!src.@java.lang.Object::castableTypeMap[dstId];
}-*/;
/**
* Danger: value not coerced to boolean; use the result only in a boolean
* context.
*/
- static native boolean canCastUnsafe(int srcId, int dstId) /*-{
- return srcId && @com.google.gwt.lang.Cast::typeIdArray[srcId][dstId];
+ static native boolean canCastUnsafe(Object src, int dstId) /*-{
+ return src.@java.lang.Object::typeId &&
+ src.@java.lang.Object::castableTypeMap[dstId];
}-*/;
static native String charToString(char x) /*-{
@@ -45,7 +44,7 @@
}-*/;
static Object dynamicCast(Object src, int dstId) {
- if (src != null && !canCastUnsafe(Util.getTypeId(src), dstId)) {
+ if (src != null && !canCastUnsafe(src, dstId)) {
throw new ClassCastException();
}
return src;
@@ -56,7 +55,7 @@
*/
static Object dynamicCastAllowJso(Object src, int dstId) {
if (src != null && !isJavaScriptObject(src) &&
- !canCastUnsafe(Util.getTypeId(src), dstId)) {
+ !canCastUnsafe(src, dstId)) {
throw new ClassCastException();
}
return src;
@@ -73,7 +72,7 @@
}
static boolean instanceOf(Object src, int dstId) {
- return (src != null) && canCast(Util.getTypeId(src), dstId);
+ return (src != null) && canCast(src, dstId);
}
/**
@@ -89,7 +88,7 @@
*/
static boolean instanceOfOrJso(Object src, int dstId) {
return (src != null) &&
- (isJavaScriptObject(src) || canCast(Util.getTypeId(src), dstId));
+ (isJavaScriptObject(src) || canCast(src, dstId));
}
static boolean isJavaObject(Object src) {
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Util.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Util.java
index facd2b8..a705c12 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Util.java
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Util.java
@@ -22,6 +22,10 @@
* fields.
*/
final class Util {
+
+ static native JavaScriptObject getCastableTypeMap(Object o) /*-{
+ return o.@java.lang.Object::castableTypeMap;
+ }-*/;
static native int getTypeId(Object o) /*-{
return o.@java.lang.Object::typeId;
@@ -31,6 +35,10 @@
return o.@java.lang.Object::typeMarker;
}-*/;
+ static native void setCastableTypeMap(Object o, JavaScriptObject castableTypeMap) /*-{
+ o.@java.lang.Object::castableTypeMap = castableTypeMap;
+ }-*/;
+
static native void setTypeId(Object o, int typeId) /*-{
o.@java.lang.Object::typeId = typeId;
}-*/;
diff --git a/tools/api-checker/config/gwt20_21userApi.conf b/tools/api-checker/config/gwt20_21userApi.conf
index 5e6b26f..7d58b57 100644
--- a/tools/api-checker/config/gwt20_21userApi.conf
+++ b/tools/api-checker/config/gwt20_21userApi.conf
@@ -142,6 +142,11 @@
# Array.length is now intrinsic to the compiler
com.google.gwt.lang.Array::length MISSING
+# Array initialization modified to include castableTypeMap arg
+com.google.gwt.lang.Array::initDim(Ljava/lang/Class;IIII) MISSING
+com.google.gwt.lang.Array::initDims([Ljava/lang/Class;[I[I[III) MISSING
+com.google.gwt.lang.Array::initValues(Ljava/lang/Class;IILcom/google/gwt/lang/Array;) MISSING
+
# Add DateTimeFormatInfo, PredefinedFormat overrides
com.google.gwt.i18n.client.DateTimeFormat::DateTimeFormat(Ljava/lang/String;Lcom/google/gwt/i18n/client/constants/DateTimeConstants;) OVERLOADED_METHOD_CALL
com.google.gwt.i18n.client.DateTimeFormat::getFormat(Ljava/lang/String;) OVERLOADED_METHOD_CALL
diff --git a/user/src/com/google/gwt/rpc/linker/CastableTypeDataImpl.java b/user/src/com/google/gwt/rpc/linker/CastableTypeDataImpl.java
new file mode 100644
index 0000000..b9e4c6e
--- /dev/null
+++ b/user/src/com/google/gwt/rpc/linker/CastableTypeDataImpl.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2010 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.rpc.linker;
+
+import com.google.gwt.core.ext.linker.CastableTypeMap;
+import com.google.gwt.rpc.server.CastableTypeData;
+
+/**
+ * Implementation of a wrapped castableTypeMap.
+ */
+public class CastableTypeDataImpl implements CastableTypeData {
+
+ private final CastableTypeMap castableTypeMap;
+
+ public CastableTypeDataImpl(CastableTypeMap castableTypeMap) {
+ this.castableTypeMap = castableTypeMap;
+ }
+
+ public String toJs() {
+ return castableTypeMap.toJs();
+ }
+
+}
diff --git a/user/src/com/google/gwt/rpc/linker/ClientOracleLinker.java b/user/src/com/google/gwt/rpc/linker/ClientOracleLinker.java
index 1727296..619f06c 100644
--- a/user/src/com/google/gwt/rpc/linker/ClientOracleLinker.java
+++ b/user/src/com/google/gwt/rpc/linker/ClientOracleLinker.java
@@ -71,7 +71,8 @@
for (SymbolData symbolData : result.getSymbolMap()) {
builder.add(symbolData.getSymbolName(), symbolData.getJsniIdent(),
symbolData.getClassName(), symbolData.getMemberName(),
- symbolData.getTypeId());
+ symbolData.getTypeId(),
+ new CastableTypeDataImpl(symbolData.getCastableTypeMap()));
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
diff --git a/user/src/com/google/gwt/rpc/server/CastableTypeData.java b/user/src/com/google/gwt/rpc/server/CastableTypeData.java
new file mode 100644
index 0000000..c2c2e63
--- /dev/null
+++ b/user/src/com/google/gwt/rpc/server/CastableTypeData.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2010 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.rpc.server;
+
+import java.io.Serializable;
+
+/**
+ * An encapsulation of a JSON object containing castable type information.
+ */
+public interface CastableTypeData extends Serializable {
+
+ /**
+ * Returns an eval-able JSON object.
+ */
+ String toJs();
+}
diff --git a/user/src/com/google/gwt/rpc/server/ClientOracle.java b/user/src/com/google/gwt/rpc/server/ClientOracle.java
index e1ab08e..754dbd8 100644
--- a/user/src/com/google/gwt/rpc/server/ClientOracle.java
+++ b/user/src/com/google/gwt/rpc/server/ClientOracle.java
@@ -51,6 +51,11 @@
public abstract String createUnusedIdent(String ident);
/**
+ * Returns the Json castableType data for a given type.
+ */
+ public abstract CastableTypeData getCastableTypeData(Class<?> clazz);
+
+ /**
* Given a base type and the unobfuscated field name, find the obfuscated name
* for the field in the client. This will search superclasses as well for the
* first matching field.
diff --git a/user/src/com/google/gwt/rpc/server/DelegatingClientOracle.java b/user/src/com/google/gwt/rpc/server/DelegatingClientOracle.java
index 9dd5e0d..3bfa131 100644
--- a/user/src/com/google/gwt/rpc/server/DelegatingClientOracle.java
+++ b/user/src/com/google/gwt/rpc/server/DelegatingClientOracle.java
@@ -44,6 +44,11 @@
}
@Override
+ public CastableTypeData getCastableTypeData(Class<?> clazz) {
+ return delegate.getCastableTypeData(clazz);
+ }
+
+ @Override
public String getFieldId(Class<?> clazz, String fieldName) {
return delegate.getFieldId(clazz, fieldName);
}
diff --git a/user/src/com/google/gwt/rpc/server/HostedModeClientOracle.java b/user/src/com/google/gwt/rpc/server/HostedModeClientOracle.java
index 968dd15..cdc05b3 100644
--- a/user/src/com/google/gwt/rpc/server/HostedModeClientOracle.java
+++ b/user/src/com/google/gwt/rpc/server/HostedModeClientOracle.java
@@ -57,6 +57,11 @@
public String createUnusedIdent(String ident) {
return unimplemented();
}
+
+ @Override
+ public CastableTypeData getCastableTypeData(Class<?> clazz) {
+ return unimplemented();
+ }
/**
* Unimplemented.
diff --git a/user/src/com/google/gwt/rpc/server/WebModeClientOracle.java b/user/src/com/google/gwt/rpc/server/WebModeClientOracle.java
index 0fbbdfc..786d20f 100644
--- a/user/src/com/google/gwt/rpc/server/WebModeClientOracle.java
+++ b/user/src/com/google/gwt/rpc/server/WebModeClientOracle.java
@@ -52,10 +52,11 @@
private WebModeClientOracle oracle = new WebModeClientOracle();
public void add(String jsIdent, String jsniIdent, String className,
- String memberName, int typeId) {
+ String memberName, int typeId, CastableTypeData castableTypeData) {
oracle.idents.add(jsIdent);
ClassData data = oracle.getClassData(className);
data.typeId = typeId;
+ data.castableTypeData = castableTypeData;
if (jsniIdent == null || jsniIdent.length() == 0) {
data.typeName = className;
data.seedName = jsIdent;
@@ -108,15 +109,16 @@
}
private static class ClassData implements Serializable {
- private static final long serialVersionUID = 3L;
+ private static final long serialVersionUID = 4L;
+ public CastableTypeData castableTypeData;
public final Map<String, String> fieldIdentsToNames = new HashMap<String, String>();
public final Map<String, String> fieldNamesToIdents = new HashMap<String, String>();
public final Map<String, String> methodJsniNamesToIdents = new HashMap<String, String>();
public String seedName;
public List<String> serializableFields = Collections.emptyList();
- public String typeName;
public int typeId;
+ public String typeName;
}
/**
@@ -230,6 +232,18 @@
}
return ident;
}
+
+ @Override
+ public CastableTypeData getCastableTypeData(Class<?> clazz) {
+ while (clazz != null) {
+ CastableTypeData toReturn = getCastableTypeData(canonicalName(clazz));
+ if (toReturn != null) {
+ return toReturn;
+ }
+ clazz = clazz.getSuperclass();
+ }
+ return null;
+ }
@Override
public String getFieldId(Class<?> clazz, String fieldName) {
@@ -395,6 +409,11 @@
return clazz.getName();
}
}
+
+ private CastableTypeData getCastableTypeData(String className) {
+ ClassData data = getClassData(className);
+ return data.castableTypeData;
+ }
private ClassData getClassData(String className) {
ClassData toReturn = classData.get(className);
diff --git a/user/src/com/google/gwt/rpc/server/WebModePayloadSink.java b/user/src/com/google/gwt/rpc/server/WebModePayloadSink.java
index 714e378..ff6a19a 100644
--- a/user/src/com/google/gwt/rpc/server/WebModePayloadSink.java
+++ b/user/src/com/google/gwt/rpc/server/WebModePayloadSink.java
@@ -533,7 +533,8 @@
String initValuesId = clientOracle.getMethodId(
"com.google.gwt.lang.Array", "initValues", "Ljava/lang/Class;", "I",
- "I", "Lcom/google/gwt/lang/Array;");
+ "Lcom/google/gwt/core/client/JavaScriptObject;", "I",
+ "Lcom/google/gwt/lang/Array;");
assert initValuesId != null : "Could not find initValues";
String classLitId = clientOracle.getFieldId(
@@ -546,12 +547,16 @@
constructorFunctions.put(targetClass, functionName);
/*
- * Set the typeIds and queryIds to exact values, or fall back to acting
- * like a plain Object[] array.
+ * Set the typeIds, castableTypeData, and queryIds to exact values,
+ * or fall back to acting like a plain Object[] array.
*/
+ CastableTypeData castableTypeData;
int typeId = clientOracle.getTypeId(targetClass);
- if (typeId == 0) {
+ if (typeId != 0) {
+ castableTypeData = clientOracle.getCastableTypeData(targetClass);
+ } else {
typeId = clientOracle.getTypeId(Object[].class);
+ castableTypeData = clientOracle.getCastableTypeData(Object[].class);
}
int queryId = clientOracle.getTypeId(x.getComponentType());
@@ -575,6 +580,8 @@
comma();
push(String.valueOf(typeId));
comma();
+ push(castableTypeData.toJs());
+ comma();
push(String.valueOf(queryId));
comma();
push(ident);
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 4979a83..46aa0ae 100644
--- a/user/super/com/google/gwt/emul/java/lang/Object.java
+++ b/user/super/com/google/gwt/emul/java/lang/Object.java
@@ -41,6 +41,14 @@
*/
@SuppressWarnings("unused")
private transient int typeId;
+
+ /**
+ * A JavaScript Json map for looking up castability between types.
+ *
+ * @skip
+ */
+ @SuppressWarnings("unused")
+ private transient JavaScriptObject castableTypeMap;
/**
* magic magic magic.
@@ -48,7 +56,7 @@
* @skip
*/
@SuppressWarnings("unused")
- private transient Object typeMarker;
+ private transient JavaScriptObject typeMarker;
public boolean equals(Object other) {
return this == other;