Simplifations wrt unboxed types and devirtualization
Initial motivation is to get rid of reliance on
castSucceedsTrivially for detecting super classes for unboxed
types. Otherwise native JsType interfaces will be incorrectly
considered as super for String, Boolean etc.
Change-Id: Ib1ca0bd9d81fc69d8da5886f39424c0d47b947fb
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 3f7607e..b78a8d8 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
@@ -370,10 +370,6 @@
private JClassType typeString;
- private JClassType typeDouble;
-
- private JClassType typeBoolean;
-
private FragmentPartitioningResult fragmentPartitioningResult;
private Map<JClassType, DispatchType> dispatchTypeByNativeType;
@@ -441,12 +437,6 @@
case "java.lang.String":
typeString = (JClassType) type;
break;
- case "java.lang.Double":
- typeDouble = (JClassType) type;
- break;
- case "java.lang.Boolean":
- typeBoolean = (JClassType) type;
- break;
case "java.lang.Class":
typeClass = (JClassType) type;
break;
@@ -479,7 +469,8 @@
public Map<JClassType, DispatchType> getRepresentedAsNativeTypesDispatchMap() {
if (dispatchTypeByNativeType == null) {
- ImmutableMap.Builder builder = new ImmutableMap.Builder();
+ ImmutableMap.Builder<JClassType, DispatchType> builder =
+ new ImmutableMap.Builder<JClassType, DispatchType>();
for (DispatchType dispatchType : DispatchType.values()) {
if (dispatchType.getclassName() == null) {
continue;
@@ -521,8 +512,8 @@
continue;
}
- if (typeOracle.isInstantiatedType(potentialNativeDispatchType) &&
- typeOracle.castSucceedsTrivially(potentialNativeDispatchType, type)) {
+ if (typeOracle.isInstantiatedType(potentialNativeDispatchType)
+ && typeOracle.isSuperClassOrInterface(potentialNativeDispatchType, type)) {
dispatchSet.add(getRepresentedAsNativeTypesDispatchMap().get(potentialNativeDispatchType));
dispatchSet.add(DispatchType.HAS_JAVA_VIRTUAL_DISPATCH);
}
@@ -806,8 +797,8 @@
/**
* Returns an expression that evaluates to an array class literal at runtime.
* <p>
- * Note: This version can only be called after {@link ImplementClassLiteralsAsFields} has been
- * run.
+ * Note: This version can only be called after {@link
+ * com.google.gwt.dev.jjs.impl.ImplementClassLiteralsAsFields} has been run.
*/
public JExpression createArrayClassLiteralExpression(SourceInfo sourceInfo,
JClassLiteral leafTypeClassLiteral, int dimensions) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
index 20df880..c0bcd3b 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
@@ -542,25 +542,8 @@
return castSucceedsTrivially((JArrayType) fromType, toType);
}
- if (fromType instanceof JClassType) {
- return castSucceedsTrivially((JClassType) fromType, toType);
- }
- if (fromType instanceof JInterfaceType && toType instanceof JInterfaceType) {
- return extendsInterface((JInterfaceType) fromType, (JInterfaceType) toType);
- }
-
- return false;
- }
-
- private boolean castSucceedsTrivially(JClassType fromType, JReferenceType toType) {
- if (toType instanceof JClassType) {
- return isSuperClass(fromType, toType);
- }
- if (toType instanceof JInterfaceType) {
- return implementsInterface(fromType, toType);
- }
- return false;
+ return isSuperClassOrInterface(fromType, toType);
}
private boolean castSucceedsTrivially(JArrayType fromArrayType, JReferenceType toType) {
@@ -853,6 +836,11 @@
return isSuperClass(type.getName(), possibleSuperClass.getName());
}
+ public boolean isSuperClassOrInterface(JReferenceType fromType, JReferenceType toType) {
+ return isSuperClass(fromType, toType) || implementsInterface(fromType, toType)
+ || extendsInterface(fromType, toType);
+ }
+
/**
* This method should be called after altering the types that are live in the
* associated JProgram.
@@ -1128,14 +1116,6 @@
}
/**
- * Returns true if type extends the interface represented by qType, either
- * directly or indirectly.
- */
- private boolean extendsInterface(JInterfaceType type, JInterfaceType qType) {
- return superInterfacesByInterface.containsEntry(type.getName(), qType.getName());
- }
-
- /**
* Returns an iterable set of types for the given iterable set of type names.
* <p>
* Incremental builds will not have all type instances available, so users of this function should
@@ -1256,6 +1236,14 @@
}
/**
+ * Returns true if type extends the interface represented by qType, either
+ * directly or indirectly.
+ */
+ private boolean extendsInterface(JReferenceType type, JReferenceType qType) {
+ return superInterfacesByInterface.containsEntry(type.getName(), qType.getName());
+ }
+
+ /**
* Returns true if type implements the interface represented by interfaceType, either
* directly or indirectly.
*/
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/Devirtualizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/Devirtualizer.java
index b8e630f..7743fe2 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/Devirtualizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/Devirtualizer.java
@@ -18,7 +18,6 @@
import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.ast.AccessModifier;
import com.google.gwt.dev.jjs.ast.Context;
-import com.google.gwt.dev.jjs.ast.JArrayType;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JConditional;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
@@ -107,25 +106,18 @@
@Override
public void endVisit(JMethodCall x, Context ctx) {
JMethod method = x.getTarget();
- if (!mightNeedDevirtualization(method)) {
+ if (!method.needsVtable()) {
return;
}
- JType instanceType = x.getInstance().getType().getUnderlyingType();
- // If the instance can't possibly be a JSO, String, Number, or an interface implemented by
- // either, do not devirtualize.
- if (instanceType != program.getTypeJavaLangObject()
- && !program.typeOracle.canBeJavaScriptObject(instanceType)
- // not a string
- && !(program.isRepresentedAsNativeJsPrimitive(instanceType))
- // not an array
- && !(instanceType instanceof JArrayType)
- // not an interface of String, e.g. CharSequence or Comparable
- && !isSuperOfRepresentedAsNativeType(instanceType)
- // it is a super.m() call and the superclass is not a JSO. (this case is NOT reached if
- // MakeCallsStatic was called).
- || x.isStaticDispatchOnly()
- && !method.getEnclosingType().isJsoType()) {
+ JReferenceType instanceType = (JReferenceType) x.getInstance().getType().getUnderlyingType();
+ if (!mightNeedDevirtualization(method, instanceType)) {
+ return;
+ }
+
+ // it is a super.m() call and the superclass is not a JSO. (this case is NOT reached if
+ // MakeCallsStatic was called).
+ if (x.isStaticDispatchOnly() && !method.getEnclosingType().isJsoType()) {
return;
}
@@ -197,29 +189,20 @@
}
private boolean mightNeedDevirtualization(JMethod method) {
- JDeclaredType targetType = method.getEnclosingType();
-
- if (targetType == null || !method.needsVtable()) {
- return false;
- } else if (devirtualMethodByMethod.containsKey(method)
- || targetType.isJsoType()
- || program.typeOracle.isSingleJsoImpl(targetType)
- || program.typeOracle.isDualJsoInterface(targetType)
- || targetType == program.getTypeJavaLangObject()
- || isSuperOfRepresentedAsNativeType(targetType)) {
- return true;
- }
- return false;
+ return mightNeedDevirtualization(method, method.getEnclosingType());
}
- private boolean isSuperOfRepresentedAsNativeType(JType targetType) {
- for (JClassType type : program.getRepresentedAsNativeTypes()) {
- if (program.typeOracle.isInstantiatedType(type) &&
- program.typeOracle.castSucceedsTrivially(type, targetType)) {
- return true;
- }
+ private boolean mightNeedDevirtualization(JMethod method, JReferenceType instanceType) {
+ // todo remove instance check
+ if (instanceType == null || !method.needsVtable()) {
+ return false;
}
- return false;
+ if (devirtualMethodByMethod.containsKey(method)) {
+ return true;
+ }
+ EnumSet<DispatchType> dispatchType = program.getDispatchType(instanceType);
+ dispatchType.remove(DispatchType.HAS_JAVA_VIRTUAL_DISPATCH);
+ return !dispatchType.isEmpty();
}
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/EqualityNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/EqualityNormalizer.java
index 30e0bcb..e3a325b 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/EqualityNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/EqualityNormalizer.java
@@ -150,7 +150,7 @@
} else {
for (Map.Entry<JClassType, DispatchType> nativeDispatchType :
program.getRepresentedAsNativeTypesDispatchMap().entrySet()) {
- if (program.typeOracle.castSucceedsTrivially(type, nativeDispatchType.getKey())) {
+ if (type.getUnderlyingType() == nativeDispatchType.getKey()) {
switch (nativeDispatchType.getValue()) {
case DOUBLE:
return UnboxedTypeStatus.DOUBLE;
@@ -159,7 +159,7 @@
case STRING:
return UnboxedTypeStatus.STRING;
default:
- throw new IllegalStateException("Shouldn't happen");
+ throw new AssertionError("Shouldn't happen");
}
} else if (!program.typeOracle.castFailsTrivially(type, nativeDispatchType.getKey())) {
return UnboxedTypeStatus.UNKNOWN;