manual sync to P2 @20180037
git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/2.3@9874 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 19bbba7..cfc2998 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -82,7 +82,6 @@
import com.google.gwt.dev.jjs.impl.GenerateJavaScriptAST;
import com.google.gwt.dev.jjs.impl.HandleCrossFragmentReferences;
import com.google.gwt.dev.jjs.impl.ImplementClassLiteralsAsFields;
-import com.google.gwt.dev.jjs.impl.JavaScriptObjectNormalizer;
import com.google.gwt.dev.jjs.impl.JavaToJavaScriptMap;
import com.google.gwt.dev.jjs.impl.JsFunctionClusterer;
import com.google.gwt.dev.jjs.impl.JsIEBlockTextTransformer;
@@ -620,9 +619,6 @@
// Resolve entry points, rebinding non-static entry points.
findEntryPoints(logger, rpo, declEntryPts, jprogram);
- // Replace references to JSO subtypes with JSO itself.
- JavaScriptObjectNormalizer.exec(jprogram);
-
ImplementClassLiteralsAsFields.exec(jprogram);
/*
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 09291fb..6be467b 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
@@ -25,6 +25,7 @@
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -280,6 +281,19 @@
this.program = program;
}
+ /**
+ * True if the type is a JSO or interface implemented by JSO..
+ * @param type
+ * @return
+ */
+ public boolean canBeJavaScriptObject(JType type) {
+ if (type instanceof JNonNullType) {
+ type = ((JNonNullType) type).getUnderlyingType();
+ }
+ return program.isJavaScriptObject(type)
+ || program.typeOracle.isSingleJsoImpl(type);
+ }
+
public boolean canTheoreticallyCast(JReferenceType type, JReferenceType qType) {
if (!type.canBeNull() && qType == program.getTypeNull()) {
// Cannot cast non-nullable to null
@@ -295,6 +309,14 @@
return true;
}
+ /**
+ * Cross-cast allowed in theory, prevents TypeTightener from turning
+ * cross-casts into null-casts.
+ */
+ if (canBeJavaScriptObject(type) && canBeJavaScriptObject(qType)) {
+ return true;
+ }
+
if (canTriviallyCast(type, qType)) {
return true;
}
@@ -401,12 +423,6 @@
if (isSuperClass(cType, qcType)) {
return true;
}
- // All JavaScriptObject types can be freely cast to each other.
- JClassType jsoType = program.getJavaScriptObject();
- if (jsoType != null) {
- return isSameOrSuper(cType, jsoType)
- && isSameOrSuper(qcType, jsoType);
- }
} else if (qType instanceof JInterfaceType) {
return implementsInterface(cType, (JInterfaceType) qType);
}
@@ -458,20 +474,17 @@
}
}
- /*
- * Now that the basic type hierarchy is computed, move all interfaces that
- * are implemented by overlay types onto JavaScriptObject itself before
- * building the full maps.
+ /*
+ * Now that the basic type hierarchy is computed, compute which
+ * JSOs implement interfaces singlely or dually.
*/
JClassType jsoType = program.getJavaScriptObject();
List<JClassType> jsoSubTypes = Lists.create();
if (jsoType != null) {
- assert jsoType.getImplements().size() == 0;
jsoSubTypes = new ArrayList<JClassType>(get(subClassMap, jsoType));
Collections.sort(jsoSubTypes, new HasNameSort());
for (JClassType jsoSubType : jsoSubTypes) {
for (JInterfaceType intf : jsoSubType.getImplements()) {
- jsoType.addImplements(intf);
jsoSingleImpls.put(intf, jsoSubType);
for (JInterfaceType superIntf : get(superInterfaceMap, intf)) {
if (!jsoSingleImpls.containsKey(superIntf)) {
@@ -499,14 +512,13 @@
}
// Create dual mappings for any jso interface with a Java implementor.
- int totalJsoTypes = jsoSubTypes.size() + 1;
for (JInterfaceType jsoIntf : jsoSingleImpls.keySet()) {
Set<JClassType> implementors = get(isImplementedMap, jsoIntf);
- if (implementors.size() == totalJsoTypes) {
- assert implementors.contains(jsoType);
- } else {
- assert implementors.size() > totalJsoTypes;
- dualImpls.add(jsoIntf);
+ for (JClassType implementor : implementors) {
+ if (!program.isJavaScriptObject(implementor)) {
+ dualImpls.add(jsoIntf);
+ break;
+ }
}
}
}
@@ -538,6 +550,10 @@
return results;
}
+ public Set<JClassType> getAllSubClasses(JReferenceType type) {
+ return subClassMap.get(type);
+ }
+
/**
* Returns the set of methods the given method virtually overrides. A virtual
* override is an association between a concrete method and an unrelated
@@ -574,10 +590,33 @@
return dualImpls.contains(maybeDualImpl.getUnderlyingType());
}
+ /**
+ * True if either a JSO, or is an interface that is ONLY
+ * implemented by a JSO.
+ */
+ public boolean isEffectivelyJavaScriptObject(JType type) {
+ if (type instanceof JReferenceType) {
+ JReferenceType refType = (JReferenceType) type;
+ return program.isJavaScriptObject(refType) ||
+ (isSingleJsoImpl(refType) && !isDualJsoInterface(refType));
+ } else {
+ return false;
+ }
+ }
+
public boolean isInstantiatedType(JReferenceType type) {
return isInstantiatedType(type, instantiatedTypes);
}
+ public boolean isSameOrSuper(JClassType type, JClassType qType) {
+ return (type == qType || isSuperClass(type, qType));
+ }
+
+ public boolean isSingleJsoImpl(JType type) {
+ return type instanceof JReferenceType
+ && getSingleJsoImpl((JReferenceType) type) != null;
+ }
+
/**
* Returns true if qType is a subclass of type, directly or indirectly.
*/
@@ -598,9 +637,32 @@
*/
public void recomputeAfterOptimizations() {
Set<JDeclaredType> computed = new IdentityHashSet<JDeclaredType>();
+
for (JDeclaredType type : program.getDeclaredTypes()) {
computeClinitTarget(type, computed);
}
+ nextDual: for (Iterator<JInterfaceType> it = dualImpls.iterator();
+ it.hasNext();) {
+ JInterfaceType dualIntf = it.next();
+ Set<JClassType> implementors = get(isImplementedMap, dualIntf);
+ for (JClassType implementor : implementors) {
+ if (isInstantiatedType(implementor)
+ && !program.isJavaScriptObject(implementor)) {
+ // This dual is still implemented by a Java class.
+ continue nextDual;
+ }
+ }
+ // No Java implementors.
+ it.remove();
+ }
+
+ // Prune jsoSingleImpls when implementor isn't live
+ Iterator<JClassType> jit = jsoSingleImpls.values().iterator();
+ while (jit.hasNext()) {
+ if (!isInstantiatedType(jit.next())) {
+ jit.remove();
+ }
+ }
}
public void setInstantiatedTypes(Set<JReferenceType> instantiatedTypes) {
@@ -912,10 +974,6 @@
return instantiatedTypes.contains(type);
}
- private boolean isSameOrSuper(JClassType type, JClassType qType) {
- return (type == qType || isSuperClass(type, qType));
- }
-
/**
* Record the all of my super classes (and myself as a subclass of them).
*/
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
index 9cbbf1a..be297b4 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
@@ -191,6 +191,24 @@
recordCast(x.getTestType(), x.getExpr());
}
+ private boolean canTriviallyCastJsoSemantics(JReferenceType type,
+ JReferenceType qType) {
+ type = type.getUnderlyingType();
+ qType = qType.getUnderlyingType();
+
+ if (type instanceof JArrayType && qType instanceof JArrayType) {
+ JArrayType aType = (JArrayType) type;
+ JArrayType aqType = (JArrayType) qType;
+ return program.typeOracle.canTriviallyCast(type, qType)
+ || (program.isJavaScriptObject(aType.getLeafType())
+ && program.isJavaScriptObject(aqType.getLeafType()));
+ }
+
+ return program.typeOracle.canTriviallyCast(type, qType)
+ || (program.isJavaScriptObject(type)
+ && program.isJavaScriptObject(qType));
+ }
+
/**
* Create the data for JSON table to capture the mapping from a class to its
* query types.
@@ -221,11 +239,16 @@
for (JReferenceType qType : queriedTypes.keySet()) {
Set<JReferenceType> querySet = queriedTypes.get(qType);
- if (program.typeOracle.canTriviallyCast(type, qType)) {
+ /**
+ * Handles JSO[] -> JSO[] case now that canCastTrivially doesn't deal
+ * with JSO cross-casts anymore.
+ */
+ if (canTriviallyCastJsoSemantics(type, qType)) {
for (JReferenceType argType : querySet) {
- if (program.typeOracle.canTriviallyCast(type, argType)) {
+ if (canTriviallyCastJsoSemantics(type, argType) ||
+ program.isJavaScriptObject(qType)) {
if (yesSet == null) {
yesSet = new HashSet<JReferenceType>();
}
@@ -422,13 +445,16 @@
JExpression curExpr = expr;
JReferenceType refType = ((JReferenceType) toType).getUnderlyingType();
JReferenceType argType = (JReferenceType) expr.getType();
- if (program.typeOracle.canTriviallyCast(argType, refType)) {
+ if (program.typeOracle.canTriviallyCast(argType, refType)
+ || (program.typeOracle.isEffectivelyJavaScriptObject(argType)
+ && program.typeOracle.isEffectivelyJavaScriptObject(refType))) {
// just remove the cast
replaceExpr = curExpr;
} else {
JMethod method;
- boolean isJsoCast = program.isJavaScriptObject(refType);
+ boolean isJsoCast =
+ program.typeOracle.isEffectivelyJavaScriptObject(refType);
if (isJsoCast) {
// A cast to a concrete JSO subtype
method = program.getIndexedMethod("Cast.dynamicCastJso");
@@ -537,7 +563,10 @@
JReferenceType toType = x.getTestType();
// Only tests on run-time types are supported
assert (toType == toType.getUnderlyingType());
- if (program.typeOracle.canTriviallyCast(argType, toType)) {
+ if (program.typeOracle.canTriviallyCast(argType, toType)
+ // don't depend on type-tightener having run
+ || (program.typeOracle.isEffectivelyJavaScriptObject(argType)
+ && program.typeOracle.isEffectivelyJavaScriptObject(toType))) {
// trivially true if non-null; replace with a null test
JNullLiteral nullLit = program.getLiteralNull();
JBinaryOperation eq = new JBinaryOperation(x.getSourceInfo(),
@@ -547,9 +576,9 @@
} else {
JMethod method;
boolean isJsoCast = false;
- if (program.typeOracle.getSingleJsoImpl(toType) != null) {
+ if (program.typeOracle.isDualJsoInterface(toType)) {
method = program.getIndexedMethod("Cast.instanceOfOrJso");
- } else if (program.isJavaScriptObject(toType)) {
+ } else if (program.typeOracle.isEffectivelyJavaScriptObject(toType)) {
isJsoCast = true;
method = program.getIndexedMethod("Cast.instanceOfJso");
} else {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
index 1ebe42e..d66ca40 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
@@ -182,10 +182,25 @@
public boolean visit(JCastOperation x, Context ctx) {
// Rescue any JavaScriptObject type that is the target of a cast.
JType targetType = x.getCastType();
- if (program.isJavaScriptObject(targetType)) {
+ if (program.typeOracle.canBeJavaScriptObject(targetType)) {
rescue((JReferenceType) targetType, true, true);
+ JType exprType = x.getExpr().getType();
+ if (program.typeOracle.isSingleJsoImpl(targetType)) {
+ /*
+ * It's a JSO interface, check if the source expr can be a live JSO
+ * 1) source is java.lang.Object (JSO could have been assigned to it)
+ * 2) source is JSO
+ * 3) source is SingleJSO interface whose implementor is live
+ */
+ if (program.getTypeJavaLangObject() == exprType
+ || program.typeOracle.canBeJavaScriptObject(exprType)) {
+ // source is JSO or SingleJso interface whose implementor is live
+ JClassType jsoImplementor =
+ program.typeOracle.getSingleJsoImpl((JReferenceType) targetType);
+ rescue(jsoImplementor, true, true);
+ }
+ }
}
-
return true;
}
@@ -294,7 +309,6 @@
}
rescueMethodsIfInstantiable(type);
-
return false;
}
@@ -486,7 +500,8 @@
*/
private void maybeRescueJavaScriptObjectPassingIntoJava(JType type) {
boolean doIt = false;
- if (program.isJavaScriptObject(type) || program.isJavaLangString(type)) {
+ if (program.typeOracle.canBeJavaScriptObject(type)
+ || program.isJavaLangString(type)) {
doIt = true;
} else if (type instanceof JArrayType) {
/*
@@ -497,12 +512,17 @@
JType elementType = arrayType.getElementType();
if (elementType instanceof JPrimitiveType
|| program.isJavaLangString(elementType)
- || program.isJavaScriptObject(elementType)) {
+ || program.typeOracle.canBeJavaScriptObject(elementType)) {
doIt = true;
}
}
if (doIt) {
rescue((JReferenceType) type, true, true);
+ if (program.typeOracle.isSingleJsoImpl(type)) {
+ // Cast of JSO into SingleJso interface, rescue the implementor
+ rescue(program.typeOracle.getSingleJsoImpl((JReferenceType) type),
+ true, true);
+ }
}
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java
index 017e69b..a02032c 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java
@@ -273,6 +273,23 @@
return typeName;
}
+
+ private JType normalizeJsoType(JType type) {
+ if (program.isJavaScriptObject(type)) {
+ return program.getJavaScriptObject();
+ }
+
+ if (type instanceof JArrayType) {
+ JArrayType aType = (JArrayType) type;
+ if (program.isJavaScriptObject(aType.getLeafType())) {
+ return program.getTypeArray(program.getJavaScriptObject(),
+ aType.getDims());
+ }
+ }
+
+ return type;
+ }
+
/**
* Takes the form:
*
@@ -285,6 +302,7 @@
*/
private JField resolveClassLiteralField(JClassLiteral classLiteral) {
JType type = classLiteral.getRefType();
+ type = normalizeJsoType(type);
JField field = classLiteralFields.get(type);
if (field == null) {
// Create the allocation expression FIRST since this may be recursive on
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java
deleted file mode 100644
index 743b6b9..0000000
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * Copyright 2008 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.dev.jjs.impl;
-
-import com.google.gwt.dev.jjs.SourceInfo;
-import com.google.gwt.dev.jjs.ast.Context;
-import com.google.gwt.dev.jjs.ast.JArrayType;
-import com.google.gwt.dev.jjs.ast.JCastOperation;
-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.JDeclaredType;
-import com.google.gwt.dev.jjs.ast.JExpression;
-import com.google.gwt.dev.jjs.ast.JField;
-import com.google.gwt.dev.jjs.ast.JInstanceOf;
-import com.google.gwt.dev.jjs.ast.JLocal;
-import com.google.gwt.dev.jjs.ast.JLocalRef;
-import com.google.gwt.dev.jjs.ast.JMethod;
-import com.google.gwt.dev.jjs.ast.JMethodBody;
-import com.google.gwt.dev.jjs.ast.JMethodCall;
-import com.google.gwt.dev.jjs.ast.JModVisitor;
-import com.google.gwt.dev.jjs.ast.JNewArray;
-import com.google.gwt.dev.jjs.ast.JNonNullType;
-import com.google.gwt.dev.jjs.ast.JParameter;
-import com.google.gwt.dev.jjs.ast.JProgram;
-import com.google.gwt.dev.jjs.ast.JReferenceType;
-import com.google.gwt.dev.jjs.ast.JType;
-import com.google.gwt.dev.jjs.ast.js.JMultiExpression;
-import com.google.gwt.dev.util.log.speedtracer.CompilerEventType;
-import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger;
-import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event;
-
-import java.util.Stack;
-
-/**
- * Replace references to JSO subtypes with JSO itself.
- */
-public class JavaScriptObjectNormalizer {
- /**
- * Map types from JSO subtypes to JSO itself.
- */
- private class NormalizeVisitor extends JModVisitor {
-
- private final Stack<JMethodBody> currentMethodBody = new Stack<JMethodBody>();
-
- @Override
- public void endVisit(JCastOperation x, Context ctx) {
- JType newType = translate(x.getCastType());
- if (newType != x.getCastType()) {
- ctx.replaceMe(new JCastOperation(x.getSourceInfo(), newType,
- x.getExpr()));
- }
- }
-
- @Override
- public void endVisit(JClassLiteral x, Context ctx) {
- JType newType = translate(x.getRefType());
- if (newType != x.getRefType()) {
- ctx.replaceMe(new JClassLiteral(x.getSourceInfo(), newType));
- }
- }
-
- @Override
- public void endVisit(JField x, Context ctx) {
- x.setType(translate(x.getType()));
- }
-
- @Override
- public void endVisit(JInstanceOf x, Context ctx) {
- JReferenceType newType = (JReferenceType) translate(x.getTestType());
- if (newType != x.getTestType()) {
- ctx.replaceMe(new JInstanceOf(x.getSourceInfo(), newType, x.getExpr()));
- }
- }
-
- @Override
- public void endVisit(JLocal x, Context ctx) {
- x.setType(translate(x.getType()));
- }
-
- @Override
- public void endVisit(JMethod x, Context ctx) {
- x.setType(translate(x.getType()));
- }
-
- @Override
- public void endVisit(JMethodBody x, Context ctx) {
- if (currentMethodBody.pop() != x) {
- throw new RuntimeException("Unexpected JMethodBody popped");
- }
- }
-
- /**
- * Polymorphic dispatches to interfaces implemented by both a JSO and a
- * regular type require special dispatch handling. If the instance is not a
- * Java-derived object, the method from the single JSO implementation will
- * be invoked. Otherwise, a polymorphic dispatch to the Java-derived object
- * is made.
- */
- @Override
- public void endVisit(JMethodCall x, Context ctx) {
- JDeclaredType targetClass = x.getTarget().getEnclosingType();
- if (program.typeOracle.getSingleJsoImpl(targetClass) != null) {
-
- SourceInfo info = x.getSourceInfo();
-
- // Find the method in the JSO type
- JMethod jsoMethod = findJsoMethod(x.getTarget());
- assert jsoMethod != null;
-
- if (program.typeOracle.isDualJsoInterface(targetClass)) {
- /*
- * This is the special-case code to handle interfaces.
- */
- JMultiExpression multi = new JMultiExpression(info);
- JExpression instance = maybeMakeTempAssignment(multi, x.getInstance());
-
- // instance.method(arg, arg)
- JMethodCall localCall = new JMethodCall(info, instance, x.getTarget());
- localCall.addArgs(x.getArgs());
-
- // We need a second copy of the arguments for the else expression
- CloneExpressionVisitor cloner = new CloneExpressionVisitor();
-
- // instance.jsoMethod(arg, arg)
- JMethodCall jsoCall = new JMethodCall(info,
- cloner.cloneExpression(instance), jsoMethod);
- jsoCall.addArgs(cloner.cloneExpressions(x.getArgs()));
-
- // Cast.isJavaScriptObject() ? instance.jsoMethod() :
- // instance.method();
- JConditional newExpr = makeIsJsoConditional(info,
- cloner.cloneExpression(instance), x.getType(), jsoCall, localCall);
-
- multi.exprs.add(newExpr);
- // We may only have the ternary operation if there's no side-effect
- ctx.replaceMe(multi.exprs.size() == 1 ? multi.exprs.get(0) : multi);
- } else {
- /*
- * ... otherwise, if there's only a JSO implementation, we'll just
- * call that directly.
- */
- JMethodCall jsoCall = new JMethodCall(info, x.getInstance(),
- jsoMethod);
- jsoCall.addArgs(x.getArgs());
- ctx.replaceMe(jsoCall);
- }
- }
- }
-
- @Override
- public void endVisit(JNewArray x, Context ctx) {
- x.setType((JNonNullType) translate(x.getType()));
- }
-
- @Override
- public void endVisit(JParameter x, Context ctx) {
- x.setType(translate(x.getType()));
- }
-
- @Override
- public boolean visit(JMethodBody x, Context ctx) {
- currentMethodBody.push(x);
- return true;
- }
-
- private JMethod findConcreteImplementation(JMethod method,
- JClassType concreteType) {
- /*
- * Search supertypes for virtual overrides via subclass. See the javadoc
- * on JTypeOracle.getAllVirtualOverrides for an example.
- */
- while (concreteType != null) {
- for (JMethod m : concreteType.getMethods()) {
- if (program.typeOracle.getAllOverrides(m).contains(method)) {
- if (!m.isAbstract()) {
- return m;
- }
- }
- }
- concreteType = concreteType.getSuperClass();
- }
-
- return null;
- }
-
- private JMethod findJsoMethod(JMethod interfaceMethod) {
- JClassType jsoClass = program.typeOracle.getSingleJsoImpl(interfaceMethod.getEnclosingType());
- assert program.isJavaScriptObject(jsoClass);
- assert jsoClass != null;
-
- JMethod toReturn = findConcreteImplementation(interfaceMethod, jsoClass);
- assert toReturn != null;
- assert !toReturn.isAbstract();
- assert jsoClass.isFinal() || toReturn.isFinal();
-
- return toReturn;
- }
-
- private JConditional makeIsJsoConditional(SourceInfo info,
- JExpression instance, JType conditionalType, JExpression isJsoExpr,
- JExpression notJsoExpr) {
- // Cast.isJavaScriptObjectOrString(instance)
- JMethod isJavaScriptObjectMethod = program.getIndexedMethod("Cast.isJavaScriptObjectOrString");
- JMethodCall isJavaScriptObjectExpr = new JMethodCall(info, null,
- isJavaScriptObjectMethod);
- isJavaScriptObjectExpr.addArg(instance);
- return new JConditional(info, conditionalType, isJavaScriptObjectExpr,
- isJsoExpr, notJsoExpr);
- }
-
- private JExpression maybeMakeTempAssignment(JMultiExpression multi,
- JExpression instance) {
- if (instance.hasSideEffects()) {
- /*
- * It may be necessary to save off the instance expression into a local
- * variable if its evaluation would produce side-effects. The
- * multi-expression is used for this purpose.
- */
- SourceInfo info = instance.getSourceInfo();
- JLocal local = JProgram.createLocal(info, "maybeJsoInvocation",
- instance.getType(), true, currentMethodBody.peek());
- multi.exprs.add(JProgram.createAssignmentStmt(info,
- new JLocalRef(info, local), instance).getExpr());
-
- instance = new JLocalRef(info, local);
- }
- return instance;
- }
-
- private JType translate(JType type) {
- if (!(type instanceof JReferenceType)) {
- return type;
- }
- JReferenceType refType = (JReferenceType) type;
- boolean canBeNull = refType.canBeNull();
- refType = refType.getUnderlyingType();
-
- if (program.isJavaScriptObject(refType)) {
- refType = program.getJavaScriptObject();
- } else if (program.typeOracle.getSingleJsoImpl(refType) != null
- && !program.typeOracle.isDualJsoInterface(refType)) {
- // Optimization: narrow to JSO if it's not a dual impl.
- refType = program.getJavaScriptObject();
- } else if (refType instanceof JArrayType) {
- JArrayType arrayType = (JArrayType) refType;
- JType leafType = arrayType.getLeafType();
- JType replacement = translate(leafType);
- if (leafType != replacement) {
- refType = program.getTypeArray(replacement, arrayType.getDims());
- }
- }
- return canBeNull ? refType : refType.getNonNull();
- }
- }
-
- public static void exec(JProgram program) {
- Event normalizerEvent = SpeedTracerLogger.start(CompilerEventType.NORMALIZER);
- new JavaScriptObjectNormalizer(program).execImpl();
- normalizerEvent.end();
- }
-
- private final JProgram program;
-
- private JavaScriptObjectNormalizer(JProgram program) {
- this.program = program;
- }
-
- private void execImpl() {
- NormalizeVisitor visitor = new NormalizeVisitor();
- visitor.accept(program);
- }
-}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java
index 84cc483..c399579 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java
@@ -20,6 +20,10 @@
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JConditional;
+import com.google.gwt.dev.jjs.ast.JDeclaredType;
+import com.google.gwt.dev.jjs.ast.JExpression;
+import com.google.gwt.dev.jjs.ast.JLocal;
+import com.google.gwt.dev.jjs.ast.JLocalRef;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JMethodBody;
import com.google.gwt.dev.jjs.ast.JMethodCall;
@@ -28,12 +32,13 @@
import com.google.gwt.dev.jjs.ast.JParameterRef;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JReturnStatement;
+import com.google.gwt.dev.jjs.ast.JType;
+import com.google.gwt.dev.jjs.ast.JTypeOracle;
+import com.google.gwt.dev.jjs.ast.js.JMultiExpression;
import com.google.gwt.dev.jjs.impl.MakeCallsStatic.CreateStaticImplsVisitor;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
-import java.util.Set;
/**
* All call sites that might result in virtual dispatch to a JSO must be
@@ -52,18 +57,66 @@
public void endVisit(JMethodCall x, Context ctx) {
JMethod method = x.getTarget();
JMethod newMethod;
- if (virtualJsoMethods.contains(method)) {
- /*
- * Force a JSO call to be static. Really, this should never be necessary
- * as long as MakeCallsStatic runs. However, we would rather not insist
- * that normalization depends on optimization having been done.
- */
- newMethod = program.getStaticImpl(method);
- } else if (objectMethodToJsoMethod.keySet().contains(method)) {
- /*
- * Map the object call to its appropriate devirtualizing method.
- */
- newMethod = objectMethodToJsoMethod.get(method);
+ /**
+ * A method call at this point can be one of5 things:
+ * 1) a dual dispatch interface
+ * 2) a single dispatch trough single-jso interface
+ * 3) a java.lang.Object override from JavaScriptObject
+ * 4) a regular dispatch (no JSOs involved or static JSO call)
+ * 5) in draftMode, a 'static' virtual JSO call that hasn't been
+ * made static yet.
+ */
+ JDeclaredType targetType = method.getEnclosingType();
+
+ if (targetType == null) {
+ return;
+ }
+ if (!method.needsVtable()) {
+ return;
+ }
+
+ JType instanceType = x.getInstance().getType();
+ // if the instance can't possibly be a JSO, don't devirtualize
+ if (instanceType != program.getTypeJavaLangObject()
+ && !program.typeOracle.canBeJavaScriptObject(instanceType)) {
+ return;
+ }
+
+ if (polyMethodToJsoMethod.containsKey(method)) {
+ // already did this one before
+ newMethod = polyMethodToJsoMethod.get(method);
+ } else if (program.typeOracle.isDualJsoInterface(targetType)) {
+ JMethod overridingMethod = findOverridingMethod(method,
+ program.typeOracle.getSingleJsoImpl(targetType));
+ assert overridingMethod != null;
+
+ JMethod jsoStaticImpl = getStaticImpl(overridingMethod);
+ newMethod = getOrCreateDevirtualMethod(x, jsoStaticImpl);
+ polyMethodToJsoMethod.put(method, newMethod);
+ } else if (program.isJavaScriptObject(targetType)) {
+ // It's a virtual JSO dispatch, usually occurs in draftCompile
+ newMethod = getStaticImpl(method);
+ polyMethodToJsoMethod.put(method, newMethod);
+ } else if (program.typeOracle.isSingleJsoImpl(targetType)) {
+ // interface dispatch with single implementing JSO concrete type
+ JMethod overridingMethod = findOverridingMethod(method,
+ program.typeOracle.getSingleJsoImpl(targetType));
+ assert overridingMethod != null;
+ newMethod = getStaticImpl(overridingMethod);
+ polyMethodToJsoMethod.put(method, newMethod);
+ } else if (targetType == program.getTypeJavaLangObject()) {
+ // it's a java.lang.Object overriden method in JSO
+ JMethod overridingMethod = findOverridingMethod(method,
+ program.getJavaScriptObject());
+ if (overridingMethod != null) {
+ JMethod jsoStaticImpl = getStaticImpl(overridingMethod);
+ newMethod = getOrCreateDevirtualMethod(x, jsoStaticImpl);
+ polyMethodToJsoMethod.put(method, newMethod);
+ } else {
+ // else this method isn't overriden by JavaScriptObject
+ assert false : "Object method not overriden by JavaScriptObject";
+ return;
+ }
} else {
return;
}
@@ -74,7 +127,7 @@
@Override
public boolean visit(JMethod x, Context ctx) {
// Don't rewrite the polymorphic call inside of the devirtualizing method!
- if (objectMethodToJsoMethod.values().contains(x)) {
+ if (polyMethodToDevirtualMethods.containsValue(x)) {
return false;
}
return true;
@@ -89,19 +142,13 @@
* Maps each Object instance methods (ie, {@link Object#equals(Object)}) onto
* its corresponding devirtualizing method.
*/
- protected Map<JMethod, JMethod> objectMethodToJsoMethod = new HashMap<JMethod, JMethod>();
-
- /**
- * Contains the set of live instance methods on JavaScriptObject; typically
- * overrides of Object methods.
- */
- protected Set<JMethod> virtualJsoMethods = new HashSet<JMethod>();
+ protected Map<JMethod, JMethod> polyMethodToJsoMethod = new HashMap<JMethod, JMethod>();
/**
* Contains the set of devirtualizing methods that replace polymorphic calls
* to Object methods.
*/
- private Set<JMethod> devirtualMethods = new HashSet<JMethod>();
+ private Map<JMethod, JMethod> polyMethodToDevirtualMethods = new HashMap<JMethod, JMethod>();
/**
* Contains the Cast.isJavaObject method.
@@ -110,67 +157,12 @@
private final JProgram program;
+ private final CreateStaticImplsVisitor staticImplCreator;
+
private JsoDevirtualizer(JProgram program) {
this.program = program;
this.isJavaObjectMethod = program.getIndexedMethod("Cast.isJavaObject");
- }
-
- /**
- * Create a conditional method to discriminate between static and virtual
- * dispatch.
- *
- * <pre>
- * static boolean equals__devirtual$(Object this, Object other) {
- * return Cast.isJavaObject(this) ? this.equals(other) : JavaScriptObject.equals$(this, other);
- * }
- * </pre>
- */
- private JMethod createDevirtualMethod(JMethod objectMethod, JMethod jsoImpl) {
- JClassType jsoType = program.getJavaScriptObject();
- SourceInfo sourceInfo = jsoType.getSourceInfo().makeChild(SourceOrigin.UNKNOWN);
-
- // Create the new method.
- String name = objectMethod.getName() + "__devirtual$";
- JMethod newMethod = program.createMethod(sourceInfo, name, jsoType,
- objectMethod.getType(), false, true, true, false, false);
- newMethod.setSynthetic();
-
- // Setup parameters.
- JParameter thisParam = JProgram.createParameter(sourceInfo, "this$static",
- program.getTypeJavaLangObject(), true, true, newMethod);
- for (JParameter oldParam : objectMethod.getParams()) {
- JProgram.createParameter(sourceInfo, oldParam.getName(),
- oldParam.getType(), true, false, newMethod);
- }
- newMethod.freezeParamTypes();
- newMethod.addThrownExceptions(objectMethod.getThrownExceptions());
- sourceInfo.addCorrelation(sourceInfo.getCorrelator().by(newMethod));
-
- // Build from bottom up.
- JMethodCall condition = new JMethodCall(sourceInfo, null,
- isJavaObjectMethod);
- condition.addArg(new JParameterRef(sourceInfo, thisParam));
-
- JMethodCall thenValue = new JMethodCall(sourceInfo, new JParameterRef(
- sourceInfo, thisParam), objectMethod);
- for (JParameter param : newMethod.getParams()) {
- if (param != thisParam) {
- thenValue.addArg(new JParameterRef(sourceInfo, param));
- }
- }
-
- JMethodCall elseValue = new JMethodCall(sourceInfo, null, jsoImpl);
- for (JParameter param : newMethod.getParams()) {
- elseValue.addArg(new JParameterRef(sourceInfo, param));
- }
-
- JConditional conditional = new JConditional(sourceInfo, objectMethod.getType(),
- condition, thenValue, elseValue);
-
- JReturnStatement returnStatement = new JReturnStatement(sourceInfo,
- conditional);
- ((JMethodBody) newMethod.getBody()).getBlock().addStmt(returnStatement);
- return newMethod;
+ staticImplCreator = new CreateStaticImplsVisitor(program);
}
private void execImpl() {
@@ -179,54 +171,136 @@
return;
}
- for (JMethod method : jsoType.getMethods()) {
- if (method.needsVtable()) {
- virtualJsoMethods.add(method);
- }
- }
-
- if (virtualJsoMethods.isEmpty()) {
- return;
- }
-
- CreateStaticImplsVisitor creator = new CreateStaticImplsVisitor(program);
- for (JMethod method : virtualJsoMethods) {
- // Ensure staticImpls exist for any instance methods.
- JMethod jsoStaticImpl = program.getStaticImpl(method);
- if (jsoStaticImpl == null) {
- creator.accept(method);
- jsoStaticImpl = program.getStaticImpl(method);
- assert (jsoStaticImpl != null);
- }
-
- // Find the object method this instance method overrides.
- JMethod objectOverride = findObjectOverride(method);
- if (objectOverride != null) {
- JMethod devirtualizer = createDevirtualMethod(objectOverride,
- jsoStaticImpl);
- devirtualMethods.add(devirtualizer);
- objectMethodToJsoMethod.put(objectOverride, devirtualizer);
- }
- }
-
RewriteVirtualDispatches rewriter = new RewriteVirtualDispatches();
rewriter.accept(program);
assert (rewriter.didChange());
}
/**
- * Finds the object method this method overrides.
+ * Finds the method that overrides this method, starting with the target
+ * class.
*/
- private JMethod findObjectOverride(JMethod method) {
- Set<JMethod> overrides = program.typeOracle.getAllRealOverrides(method);
- JMethod objectOverride = null;
- for (JMethod override : overrides) {
- if (override.getEnclosingType() == program.getTypeJavaLangObject()) {
- objectOverride = override;
- break;
+ private JMethod findOverridingMethod(JMethod method, JClassType target) {
+ if (target == null) {
+ return null;
+ }
+ for (JMethod overridingMethod : target.getMethods()) {
+ if (JTypeOracle.methodsDoMatch(method, overridingMethod)) {
+ return overridingMethod;
}
}
- return objectOverride;
+ return findOverridingMethod(method, target.getSuperClass());
}
+
+ /**
+ * Create a conditional method to discriminate between static and virtual
+ * dispatch.
+ *
+ * <pre>
+ * static boolean equals__devirtual$(Object this, Object other) {
+ * return Cast.isJavaObject(this) ? this.equals(other) : JavaScriptObject.equals$(this, other);
+ * }
+ * </pre>
+ */
+ private JMethod getOrCreateDevirtualMethod(JMethodCall polyMethodCall,
+ JMethod jsoImpl) {
+ JMethod polyMethod = polyMethodCall.getTarget();
+ /**
+ * TODO(cromwellian) generate a inlined expression instead of Method
+ * Because devirtualization happens after optimization, the devirtual
+ * methods don't optimize well in the JS pass. Consider "inlining" a
+ * hand optimized devirtual method at callsites instead of a JMethodCall.
+ * As a bonus, the inlined code can be specialized for each callsite, for
+ * example, if there are no side effects, then there's no need for a
+ * temporary. Or, if the instance can't possibly be java.lang.String,
+ * then the JSO check becomes a cheaper check for typeMarker.
+ */
+ if (polyMethodToDevirtualMethods.containsKey(polyMethod)) {
+ return polyMethodToDevirtualMethods.get(polyMethod);
+ }
+
+
+ JClassType jsoType = program.getJavaScriptObject();
+ SourceInfo sourceInfo = jsoType.getSourceInfo()
+ .makeChild(SourceOrigin.UNKNOWN);
+
+ // Create the new method.
+ String name = polyMethod.getName() + "__devirtual$";
+ JMethod newMethod = program.createMethod(sourceInfo, name, jsoType,
+ polyMethod.getType(), false, true, true, false, false);
+ newMethod.setSynthetic();
+
+ // Setup parameters.
+ JParameter thisParam = JProgram.createParameter(sourceInfo, "this$static",
+ program.getTypeJavaLangObject(), true, true, newMethod);
+ for (JParameter oldParam : polyMethod.getParams()) {
+ JProgram.createParameter(sourceInfo, oldParam.getName(),
+ oldParam.getType(), true, false, newMethod);
+ }
+ newMethod.freezeParamTypes();
+ newMethod.addThrownExceptions(polyMethod.getThrownExceptions());
+ sourceInfo.addCorrelation(sourceInfo.getCorrelator().by(newMethod));
+
+ // maybeJsoInvocation = this$static
+ JExpression instance = polyMethodCall.getInstance();
+ JLocal temp = JProgram.createLocal(sourceInfo, "maybeJsoInvocation",
+ thisParam.getType(), true, (JMethodBody) newMethod.getBody());
+ JMultiExpression multi = new JMultiExpression(sourceInfo);
+
+ // (maybeJsoInvocation = this$static, )
+ multi.exprs.add(JProgram.createAssignmentStmt(sourceInfo,
+ new JLocalRef(sourceInfo, temp),
+ new JParameterRef(sourceInfo, thisParam)).getExpr());
+
+ // Build from bottom up.
+ // isJavaObject(temp)
+ JMethodCall condition = new JMethodCall(sourceInfo, null,
+ isJavaObjectMethod);
+ condition.addArg(new JLocalRef(sourceInfo, temp));
+
+ // temp.method(args)
+ JMethodCall thenValue = new JMethodCall(sourceInfo, new JLocalRef(
+ sourceInfo, temp), polyMethod);
+ for (JParameter param : newMethod.getParams()) {
+ if (param != thisParam) {
+ thenValue.addArg(new JParameterRef(sourceInfo, param));
+ }
+ }
+
+ // jso$method(temp, args)
+ JMethodCall elseValue = new JMethodCall(sourceInfo, null, jsoImpl);
+ elseValue.addArg(new JLocalRef(sourceInfo, temp));
+ for (JParameter param : newMethod.getParams()) {
+ if (param != thisParam) {
+ elseValue.addArg(new JParameterRef(sourceInfo, param));
+ }
+ }
+
+ // isJavaObject(temp) ? temp.method(args) : jso$method(temp, args)
+ JConditional conditional = new JConditional(sourceInfo,
+ polyMethod.getType(),
+ condition, thenValue, elseValue);
+
+
+ multi.exprs.add(conditional);
+
+ JReturnStatement returnStatement = new JReturnStatement(sourceInfo,
+ multi);
+ ((JMethodBody) newMethod.getBody()).getBlock().addStmt(returnStatement);
+ polyMethodToDevirtualMethods.put(polyMethod, newMethod);
+
+ return newMethod;
+ }
+
+ private JMethod getStaticImpl(JMethod method) {
+ assert !method.isStatic();
+ JMethod staticImpl = program.getStaticImpl(method);
+ if (staticImpl == null) {
+ staticImplCreator.accept(method);
+ staticImpl = program.getStaticImpl(method);
+ }
+ return staticImpl;
+ }
}
+
diff --git a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
index f96623d..10db7b3 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
@@ -33,7 +33,6 @@
import com.google.gwt.dev.jjs.impl.TypeLinker;
import com.google.gwt.dev.jjs.impl.FixAssignmentToUnbox;
import com.google.gwt.dev.jjs.impl.GenerateJavaAST;
-import com.google.gwt.dev.jjs.impl.JavaScriptObjectNormalizer;
import com.google.gwt.dev.jjs.impl.TypeMap;
import com.google.gwt.dev.js.ast.JsProgram;
@@ -273,8 +272,6 @@
}
}
}
- // Replace references to JSO subtypes with JSO itself.
- JavaScriptObjectNormalizer.exec(jprogram);
ImplementClassLiteralsAsFields.exec(jprogram);
diff --git a/dev/core/test/com/google/gwt/dev/jjs/JjsTypeTest.java b/dev/core/test/com/google/gwt/dev/jjs/JjsTypeTest.java
index 03d7460..21f979d 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/JjsTypeTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/JjsTypeTest.java
@@ -60,6 +60,7 @@
private JInterfaceType intfI;
private JInterfaceType intfIBase;
private JInterfaceType intfJ;
+ private JInterfaceType intfK;
private JProgram program;
private SourceInfo synthSource;
private JReferenceType typeNull;
@@ -136,11 +137,16 @@
assertTrue(typeOracle.canTriviallyCast(arrayOfArrayOfB, arrayOfObject));
assertFalse(typeOracle.canTriviallyCast(arrayOfObject, arrayOfArrayOfB));
- assertTrue(typeOracle.canTriviallyCast(classJso1, classJso2));
- assertTrue(typeOracle.canTriviallyCast(classJso2, classJso1));
+ assertTrue(typeOracle.canTheoreticallyCast(classJso1, classJso2));
+ assertTrue(typeOracle.canTheoreticallyCast(classJso2, classJso1));
- assertTrue(typeOracle.canTriviallyCast(classJso, classJso1));
- assertTrue(typeOracle.canTriviallyCast(classJso, classJso1));
+ assertTrue(typeOracle.canTheoreticallyCast(classJso1, intfK));
+ assertTrue(typeOracle.canTheoreticallyCast(intfK, classJso1));
+
+ assertTrue(typeOracle.canTheoreticallyCast(intfJ, intfK));
+ assertTrue(typeOracle.canTheoreticallyCast(intfK, intfJ));
+
+ assertTrue(typeOracle.canTriviallyCast(classJso1, classJso));
assertTrue(typeOracle.canTriviallyCast(arrayOfA, intfSerializable));
assertFalse(typeOracle.canTriviallyCast(intfSerializable, arrayOfA));
@@ -150,15 +156,13 @@
/*
* Test that two types cannot both be trivially castable to each other,
- * unless they are the same type. Or, unless they are both JSOs.
+ * unless they are the same type.
*/
for (JReferenceType type1 : severalTypes()) {
for (JReferenceType type2 : severalTypes()) {
if (type1 != type2) {
- if (!isJso(type1) || !isJso(type2)) {
- assertFalse(typeOracle.canTriviallyCast(type1, type2)
- && typeOracle.canTriviallyCast(type2, type1));
- }
+ assertFalse(typeOracle.canTriviallyCast(type1, type2)
+ && typeOracle.canTriviallyCast(type2, type1));
}
}
}
@@ -246,6 +250,7 @@
intfI.addImplements(intfIBase);
intfJ = createInterface("J");
+ intfK = createInterface("K");
classBase = createClass("Base", classObject, false, false);
@@ -260,8 +265,10 @@
classBSub = createClass("BSub", classB, false, false);
classJso1 = createClass("Jso1", classJso, false, false);
+ classJso1.addImplements(intfJ);
classJso2 = createClass("Jso2", classJso, false, false);
-
+ classJso2.addImplements(intfK);
+
program.typeOracle.computeBeforeAST();
// Save off some miscellaneous types to test against
@@ -289,10 +296,6 @@
return program.generalizeTypes(types);
}
- private boolean isJso(JReferenceType type) {
- return typeOracle.canTriviallyCast(type, classJso);
- }
-
/**
* Return several types, for exhaustively testing basic properties.
*/
@@ -313,6 +316,7 @@
types.add(classString);
types.add(intfI);
types.add(intfJ);
+ types.add(intfK);
types.add(intfIBase);
types.add(classJso1);
types.add(classJso2);
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzerTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzerTest.java
index 15406c0..6291398 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzerTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzerTest.java
@@ -19,6 +19,8 @@
import com.google.gwt.dev.javac.impl.MockJavaResource;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
import com.google.gwt.dev.jjs.ast.JField;
+import com.google.gwt.dev.jjs.ast.JMethod;
+import com.google.gwt.dev.jjs.ast.JNode;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.util.Empty;
@@ -63,6 +65,21 @@
assertEquals(expectedSet, cfa.getInstantiatedTypes());
}
+ public void assertOnlyLiveFieldsAndMethods(String... expected) {
+ Set<JNode> expectedSet = new HashSet<JNode>();
+ for (String expectedRef : expected) {
+ JField field = findField(program, expectedRef);
+ if (field != null) {
+ expectedSet.add(field);
+ } else {
+ JMethod method = findQualifiedMethod(program, expectedRef);
+ assertNotNull(method);
+ expectedSet.add(method);
+ }
+ }
+ assertEquals(expectedSet, cfa.getLiveFieldsAndMethods());
+ }
+
public void assertOnlyLiveStrings(String... expectedStrings) {
Set<String> expectedSet = new HashSet<String>();
Collections.addAll(expectedSet, expectedStrings);
@@ -86,6 +103,76 @@
* circumstances where values can pass from JS into Java.
*/
public void testRescueJavaScriptObjectFromJsni() throws Exception {
+ sourceOracle.addOrReplace(new MockJavaResource("test.JsoIntf") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package test;");
+ code.append("import com.google.gwt.core.client.JavaScriptObject;\n");
+ code.append("public interface JsoIntf {");
+ code.append(" public int getAny();");
+ code.append("}");
+ return code;
+ }
+ });
+
+ sourceOracle.addOrReplace(new MockJavaResource("test.UpRefIntf") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package test;");
+ code.append("import com.google.gwt.core.client.JavaScriptObject;\n");
+ code.append("public interface UpRefIntf {");
+ code.append(" public int getFoo();");
+ code.append("}");
+ return code;
+ }
+ });
+
+ sourceOracle.addOrReplace(new MockJavaResource("test.NonImplementor") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package test;");
+ code.append("import com.google.gwt.core.client.JavaScriptObject;\n");
+ code.append("public class NonImplementor extends JavaScriptObject {");
+ code.append(" protected NonImplementor() {}");
+ code.append(" final public native int getFoo() /*-{ return 0; }-*/;");
+ code.append("}");
+ return code;
+ }
+ });
+
+ sourceOracle.addOrReplace(new MockJavaResource("test.VirtualUpRef") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package test;");
+ code.append("import com.google.gwt.core.client.JavaScriptObject;\n");
+ code.append("final public class VirtualUpRef extends NonImplementor implements UpRefIntf {");
+ code.append(" protected VirtualUpRef() {}");
+ code.append(" public static native VirtualUpRef create() /*-{ return {}; }-*/;");
+ code.append("}");
+ return code;
+ }
+ });
+
+ sourceOracle.addOrReplace(new MockJavaResource("test.SingleJso") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package test;");
+ code.append("import com.google.gwt.core.client.JavaScriptObject;\n");
+ code.append("final public class SingleJso extends JavaScriptObject implements JsoIntf {");
+ code.append(" protected SingleJso() {}");
+ code.append(" public native int getAny() /*-{ return 1; }-*/;");
+ code.append(" public static native JsoIntf returnsJsoIntf() /*-{ return {}; }-*/;");
+ code.append(" public static native SingleJso returnsJso() /*-{ return {}; }-*/;");
+ code.append("}");
+ return code;
+ }
+ });
+
sourceOracle.addOrReplace(new MockJavaResource("test.Foo") {
@Override
protected CharSequence getContent() {
@@ -122,6 +209,28 @@
// Passing a parameter from JS to Java rescues.
analyzeSnippet("Foo.passesJsoParam();").assertOnlyInstantiatedTypes(
"JavaScriptObject", "Object");
+
+ // Returning a JSO subType instantiates it
+ analyzeSnippet("SingleJso.returnsJso();").assertOnlyInstantiatedTypes(
+ "SingleJso", "JavaScriptObject", "Object", "JsoIntf");
+
+ // Returning a JSO SingleJsoImpl instantiates it and the implementor
+ analyzeSnippet("SingleJso.returnsJsoIntf();").assertOnlyInstantiatedTypes(
+ "SingleJso", "JavaScriptObject", "Object", "JsoIntf");
+
+ // A virtual upref should still be rescued
+ analyzeSnippet("VirtualUpRef.create().getFoo();").assertOnlyInstantiatedTypes(
+ "VirtualUpRef", "NonImplementor", "JavaScriptObject", "Object", "UpRefIntf");
+
+ // and its methods
+ analyzeSnippet("VirtualUpRef.create().getFoo();").assertOnlyLiveFieldsAndMethods(
+ "VirtualUpRef.$clinit", "VirtualUpRef.create",
+ "NonImplementor.$clinit","NonImplementor.getFoo",
+ "UpRefIntf.$clinit",
+ "JavaScriptObject.$clinit",
+ "EntryPoint.$clinit",
+ "EntryPoint.onModuleLoad",
+ "Object.$clinit");
}
private Result analyzeSnippet(String codeSnippet)
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/JJSTestBase.java b/dev/core/test/com/google/gwt/dev/jjs/impl/JJSTestBase.java
index ce1328b..82f673f 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/JJSTestBase.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/JJSTestBase.java
@@ -109,6 +109,15 @@
return findMethod(mainType, methodName);
}
+ public static JMethod findQualifiedMethod(JProgram program, String methodName) {
+ int pos = methodName.lastIndexOf('.');
+ assertTrue(pos > 0);
+ String typeName = methodName.substring(0, pos);
+ String unqualMethodName = methodName.substring(pos + 1);
+ JDeclaredType type = findType(program, typeName);
+ return findMethod(type, unqualMethodName);
+ }
+
/**
* Finds a type by name. The type name may be short, e.g. <code>"Foo"</code>,
* or fully-qualified, e.g. <code>"com.google.example.Foo"</code>. If a short
diff --git a/plugins/webkit/English.lproj/InfoPlist.strings b/plugins/webkit/English.lproj/InfoPlist.strings
index 92beb1a..6260754 100644
--- a/plugins/webkit/English.lproj/InfoPlist.strings
+++ b/plugins/webkit/English.lproj/InfoPlist.strings
Binary files differ
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/Showcase.gwt.xml b/samples/showcase/src/com/google/gwt/sample/showcase/Showcase.gwt.xml
index f954c64..e429c36 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/Showcase.gwt.xml
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/Showcase.gwt.xml
@@ -25,4 +25,5 @@
<extend-property name="locale" values="zh"/>
<set-property-fallback name="locale" value="en"/>
<set-configuration-property name="locale.cookie" value="SHOWCASE_LOCALE"/>
+ <set-configuration-property name="locale.useragent" value="Y"/>
</module>
diff --git a/user/src/com/google/gwt/event/dom/DomEvent.gwt.xml b/user/src/com/google/gwt/event/dom/DomEvent.gwt.xml
index 1e761c5..12d921e 100644
--- a/user/src/com/google/gwt/event/dom/DomEvent.gwt.xml
+++ b/user/src/com/google/gwt/event/dom/DomEvent.gwt.xml
@@ -1,5 +1,6 @@
<module>
- <inherits name="com.google.gwt.event.EventBase" />
- <inherits name="com.google.gwt.dom.DOM" />
+ <inherits name="com.google.gwt.dom.DOM" />
+ <inherits name="com.google.gwt.event.EventBase" />
+ <inherits name="com.google.gwt.event.dom.TouchEvent" />
<source path="client"/>
</module>
diff --git a/user/src/com/google/gwt/event/dom/TouchEvent.gwt.xml b/user/src/com/google/gwt/event/dom/TouchEvent.gwt.xml
new file mode 100644
index 0000000..e2beb0b
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/TouchEvent.gwt.xml
@@ -0,0 +1,37 @@
+<!-- -->
+<!-- Copyright 2011 Google Inc. -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
+<!-- may not use this file except in compliance with the License. You may -->
+<!-- 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. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+<module>
+ <inherits name="com.google.gwt.user.User" />
+
+ <!-- Define the support property -->
+ <define-property name="touchEventSupport" values="maybe,no" />
+
+ <!--
+ Modern browsers either support touch events or will probably add touch
+ support in the future.
+ -->
+ <set-property name="touchEventSupport" value="maybe" />
+
+ <!-- Older browsers do not support touch events. -->
+ <set-property name="touchEventSupport" value="no">
+ <any>
+ <when-property-is name="user.agent" value="ie6" />
+ </any>
+ </set-property>
+
+ <replace-with class="com.google.gwt.event.dom.TouchEvent.TouchSupportDetectorNo">
+ <when-type-is class="com.google.gwt.event.dom.TouchEvent.TouchSupportDetector" />
+ <when-property-is name="touchEventSupport" value="no" />
+ </replace-with>
+</module>
diff --git a/user/src/com/google/gwt/event/dom/client/TouchEvent.java b/user/src/com/google/gwt/event/dom/client/TouchEvent.java
index e59c69d..556c3cb 100644
--- a/user/src/com/google/gwt/event/dom/client/TouchEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/TouchEvent.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.event.dom.client;
+import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.dom.client.Touch;
import com.google.gwt.event.shared.EventHandler;
@@ -29,6 +30,53 @@
extends HumanInputEvent<H> {
/**
+ * Dectector for browser support for touch events.
+ */
+ private static class TouchSupportDetector {
+
+ private final boolean isSupported = detectTouchSupport();
+
+ public boolean isSupported() {
+ return isSupported;
+ }
+
+ private native boolean detectTouchSupport() /*-{
+ var elem = document.createElement('div');
+ elem.setAttribute('ontouchstart', 'return;');
+ return (typeof elem.ontouchstart) == "function";
+ }-*/;
+ }
+
+ /**
+ * Detector for browsers that do not support touch events.
+ */
+ @SuppressWarnings("unused")
+ private static class TouchSupportDetectorNo extends TouchSupportDetector {
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+ }
+
+ /**
+ * The implementation singleton.
+ */
+ private static TouchSupportDetector impl;
+
+ /**
+ * Runtime check for whether touch scrolling is supported in this browser. Returns true if touch
+ * events are supported but touch based scrolling is not natively supported.
+ *
+ * @return true if touch events are supported, false if not
+ */
+ public static boolean isSupported() {
+ if (impl == null) {
+ impl = GWT.create(TouchSupportDetector.class);
+ }
+ return impl.isSupported();
+ }
+
+ /**
* Get an array of {@link Touch touches} which have changed since the last
* touch event fired. Note, that for {@link TouchEndEvent touch end events},
* the touch which has just ended will not be present in the array. Moreover,
diff --git a/user/src/com/google/gwt/i18n/linker/LocalePropertyProviderGenerator.java b/user/src/com/google/gwt/i18n/linker/LocalePropertyProviderGenerator.java
index d3a5eb8..cea76a1 100644
--- a/user/src/com/google/gwt/i18n/linker/LocalePropertyProviderGenerator.java
+++ b/user/src/com/google/gwt/i18n/linker/LocalePropertyProviderGenerator.java
@@ -280,9 +280,15 @@
+ "navigator.browserLanguage : navigator.language;");
body.println("if (language) {");
body.indent();
- body.println("locale = language.replace(/-/g, \"_\");");
+ body.println("var parts = language.split(/[-_]/);");
+ body.println("if (parts.length > 1) {");
+ body.indent();
+ body.println("parts[1] = parts[1].toUpperCase();");
body.outdent();
- body.println();
+ body.println("}");
+ body.println("locale = parts.join(\"_\");");
+ body.outdent();
+ body.println("}");
}
/**
diff --git a/user/src/com/google/gwt/touch/Touch.gwt.xml b/user/src/com/google/gwt/touch/Touch.gwt.xml
index 959061d..4e27ae4 100644
--- a/user/src/com/google/gwt/touch/Touch.gwt.xml
+++ b/user/src/com/google/gwt/touch/Touch.gwt.xml
@@ -13,25 +13,5 @@
<!-- limitations under the License. -->
<module>
<inherits name="com.google.gwt.user.User" />
-
- <!-- Define the support property -->
- <define-property name="touchEventSupport" values="maybe,no" />
-
- <!--
- Modern browsers either support touch events or will probably add touch
- support in the future.
- -->
- <set-property name="touchEventSupport" value="maybe" />
-
- <!-- Older browsers do not support touch events. -->
- <set-property name="touchEventSupport" value="no">
- <any>
- <when-property-is name="user.agent" value="ie6" />
- </any>
- </set-property>
-
- <replace-with class="com.google.gwt.touch.client.TouchScroller.TouchSupportDetectorNo">
- <when-type-is class="com.google.gwt.touch.client.TouchScroller.TouchSupportDetector" />
- <when-property-is name="touchEventSupport" value="no" />
- </replace-with>
+ <source path="client"/>
</module>
diff --git a/user/src/com/google/gwt/touch/client/TouchScroller.java b/user/src/com/google/gwt/touch/client/TouchScroller.java
index fd9967a..5c05a36 100644
--- a/user/src/com/google/gwt/touch/client/TouchScroller.java
+++ b/user/src/com/google/gwt/touch/client/TouchScroller.java
@@ -16,7 +16,6 @@
package com.google.gwt.touch.client;
import com.google.gwt.core.client.Duration;
-import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.RepeatingCommand;
@@ -43,6 +42,11 @@
/**
* Adds touch based scrolling to a scroll panel.
+ *
+ * <p>
+ * Touch based scrolling is only supported on devices that support touch events
+ * and do not implement native touch based scrolling.
+ * </p>
*/
@PartialSupport
public class TouchScroller {
@@ -138,35 +142,6 @@
}
/**
- * Dectector for browser support for touch events.
- */
- private static class TouchSupportDetector {
-
- private final boolean isSupported = detectTouchSupport();
-
- public boolean isSupported() {
- return isSupported;
- }
-
- private native boolean detectTouchSupport() /*-{
- var elem = document.createElement('div');
- elem.setAttribute('ontouchstart', 'return;');
- return (typeof elem.ontouchstart) == "function";
- }-*/;
- }
-
- /**
- * Detector for browsers that do not support touch events.
- */
- @SuppressWarnings("unused")
- private static class TouchSupportDetectorNo extends TouchSupportDetector {
- @Override
- public boolean isSupported() {
- return false;
- }
- }
-
- /**
* The number of frames per second the animation should run at.
*/
private static final double FRAMES_PER_SECOND = 60;
@@ -193,9 +168,10 @@
private static final int MS_PER_FRAME = (int) (1000 / FRAMES_PER_SECOND);
/**
- * The implementation singleton.
+ * A cached boolean indicating whether or not touch scrolling is supported.
+ * Set to a non-null value the first time {@link #isSupported()} is called.
*/
- private static TouchSupportDetector impl;
+ private static Boolean isSupported;
/**
* Return a new {@link TouchScroller}.
@@ -222,25 +198,35 @@
}
/**
- * Runtime check for whether touch events are supported in this browser.
+ * Runtime check for whether touch scrolling is supported in this browser.
+ * Returns true if touch events are supported but touch based scrolling is not
+ * natively supported.
*
- * @return true if touch events are is supported, false it not
+ * @return true if touch scrolling is supported, false if not
*/
public static boolean isSupported() {
- return impl().isSupported();
+ if (isSupported == null) {
+ /*
+ * Android 3.0 devices support touch scrolling natively.
+ *
+ * TODO(jlabanca): Find a more reliable way to detect if native touch
+ * scrolling is supported.
+ */
+ isSupported = TouchEvent.isSupported() && !isAndroid3();
+ }
+ return isSupported;
}
/**
- * Get the implementation of this widget.
+ * Check if the user agent is android 3.0 or greater.
*
- * @return the implementation
+ * @return true if android 3.0+
+ *
*/
- private static TouchSupportDetector impl() {
- if (impl == null) {
- impl = GWT.create(TouchSupportDetector.class);
- }
- return impl;
- }
+ private static native boolean isAndroid3() /*-{
+ var ua = navigator.userAgent.toLowerCase();
+ return /android ([3-9]+)\.([0-9]+)/.exec(ua) != null;
+ }-*/;
/**
* The registration for the preview handler used to bust click events.
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplTrident.java b/user/src/com/google/gwt/user/client/impl/DOMImplTrident.java
index 7bed0d0..36b1b26 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplTrident.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplTrident.java
@@ -31,6 +31,9 @@
private static JavaScriptObject callDispatchDblClickEvent;
@SuppressWarnings("unused")
+ private static JavaScriptObject callDispatchOnLoadEvent;
+
+ @SuppressWarnings("unused")
private static JavaScriptObject callDispatchUnhandledEvent;
/**
@@ -168,15 +171,18 @@
$wnd['__gwt_dispatchEvent_' + moduleName] = dispatchEvent;
@com.google.gwt.user.client.impl.DOMImplTrident::callDispatchEvent = new Function('w',
'return function() { w.__gwt_dispatchEvent_' + moduleName + '.call(this) }')($wnd);
-
+
$wnd['__gwt_dispatchDblClickEvent_' + moduleName] = dispatchDblClickEvent;
@com.google.gwt.user.client.impl.DOMImplTrident::callDispatchDblClickEvent = new Function('w',
'return function() { w.__gwt_dispatchDblClickEvent_' + moduleName + '.call(this)}')($wnd);
-
+
$wnd['__gwt_dispatchUnhandledEvent_' + moduleName] = dispatchUnhandledEvent;
@com.google.gwt.user.client.impl.DOMImplTrident::callDispatchUnhandledEvent = new Function('w',
'return function() { w.__gwt_dispatchUnhandledEvent_' + moduleName + '.call(this)}')($wnd);
+ @com.google.gwt.user.client.impl.DOMImplTrident::callDispatchOnLoadEvent = new Function('w',
+ 'return function() { w.__gwt_dispatchUnhandledEvent_' + moduleName + '.call(w.event.srcElement)}')($wnd);
+
// We need to create these delegate functions to fix up the 'this' context.
// Normally, 'this' is the firing element, but this is only true for
// 'onclick = ...' event handlers, not for handlers setup via attachEvent().
@@ -268,8 +274,18 @@
@com.google.gwt.user.client.impl.DOMImplTrident::callDispatchEvent : null;
if (chMask & 0x04000) elem.onscroll = (bits & 0x04000) ?
@com.google.gwt.user.client.impl.DOMImplTrident::callDispatchEvent : null;
- if (chMask & 0x08000) elem.onload = (bits & 0x08000) ?
- @com.google.gwt.user.client.impl.DOMImplTrident::callDispatchUnhandledEvent : null;
+ if (chMask & 0x08000) {
+ if (elem.nodeName == "IFRAME") {
+ if (bits & 0x08000) {
+ elem.attachEvent('onload', @com.google.gwt.user.client.impl.DOMImplTrident::callDispatchOnLoadEvent);
+ } else {
+ elem.detachEvent('onload', @com.google.gwt.user.client.impl.DOMImplTrident::callDispatchOnLoadEvent);
+ }
+ } else {
+ elem.onload = (bits & 0x08000) ?
+ @com.google.gwt.user.client.impl.DOMImplTrident::callDispatchUnhandledEvent : null;
+ }
+ }
if (chMask & 0x10000) elem.onerror = (bits & 0x10000) ?
@com.google.gwt.user.client.impl.DOMImplTrident::callDispatchEvent : null;
if (chMask & 0x20000) elem.onmousewheel = (bits & 0x20000) ?
diff --git a/user/src/com/google/gwt/user/client/ui/Frame.java b/user/src/com/google/gwt/user/client/ui/Frame.java
index c6b09da..cdd8b48 100644
--- a/user/src/com/google/gwt/user/client/ui/Frame.java
+++ b/user/src/com/google/gwt/user/client/ui/Frame.java
@@ -19,6 +19,10 @@
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.FrameElement;
import com.google.gwt.dom.client.IFrameElement;
+import com.google.gwt.event.dom.client.HasLoadHandlers;
+import com.google.gwt.event.dom.client.LoadEvent;
+import com.google.gwt.event.dom.client.LoadHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
/**
* A widget that wraps an IFRAME element, which can contain an arbitrary web
@@ -37,7 +41,7 @@
* <h3>Example</h3> {@example com.google.gwt.examples.FrameExample}
* </p>
*/
-public class Frame extends Widget {
+public class Frame extends Widget implements HasLoadHandlers {
static final String DEFAULT_STYLENAME = "gwt-Frame";
@@ -93,6 +97,17 @@
}
/**
+ * Adds a {@link LoadEvent} load handler which will be called when the frame
+ * loads.
+ *
+ * @param handler the load handler
+ * @return {@link HandlerRegistration} that can be used to remove this handler
+ */
+ public HandlerRegistration addLoadHandler(LoadHandler handler) {
+ return addDomHandler(handler, LoadEvent.getType());
+ }
+
+ /**
* Gets the URL of the frame's resource.
*
* @return the frame's URL
diff --git a/user/test/com/google/gwt/dom/DOMSuite.java b/user/test/com/google/gwt/dom/DOMSuite.java
index 42d0be6..231c3d8 100644
--- a/user/test/com/google/gwt/dom/DOMSuite.java
+++ b/user/test/com/google/gwt/dom/DOMSuite.java
@@ -18,6 +18,7 @@
import com.google.gwt.dom.client.DocumentTest;
import com.google.gwt.dom.client.ElementTest;
import com.google.gwt.dom.client.FormTests;
+import com.google.gwt.dom.client.FrameTests;
import com.google.gwt.dom.client.MapTests;
import com.google.gwt.dom.client.NodeTest;
import com.google.gwt.dom.client.SelectTests;
@@ -40,6 +41,7 @@
suite.addTestSuite(NodeTest.class);
suite.addTestSuite(ElementTest.class);
suite.addTestSuite(FormTests.class);
+ suite.addTestSuite(FrameTests.class);
suite.addTestSuite(MapTests.class);
suite.addTestSuite(SelectTests.class);
suite.addTestSuite(StyleInjectorTest.class);
diff --git a/user/test/com/google/gwt/dom/client/FrameTests.java b/user/test/com/google/gwt/dom/client/FrameTests.java
index 183ea9d..cb6226a 100644
--- a/user/test/com/google/gwt/dom/client/FrameTests.java
+++ b/user/test/com/google/gwt/dom/client/FrameTests.java
@@ -16,12 +16,20 @@
package com.google.gwt.dom.client;
import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Frame;
+import com.google.gwt.user.client.ui.RootPanel;
+
+import com.google.gwt.event.dom.client.LoadEvent;
+import com.google.gwt.event.dom.client.LoadHandler;
/**
* Tests for the FrameElement and IFrameElement classes.
*/
public class FrameTests extends GWTTestCase {
+ private static final int FRAME_LOAD_DELAY = 3000;
+
@Override
public String getModuleName() {
return "com.google.gwt.dom.DOMTest";
@@ -34,4 +42,52 @@
doc.getBody().appendChild(iframe);
assertNotNull(iframe.getContentDocument());
}
+
+ public void testOnLoadEventFiresWithBrowerEvent() {
+ delayTestFinish(FRAME_LOAD_DELAY);
+
+ Frame frame = new Frame() {
+ public void onBrowserEvent(Event event) {
+ if (event.getTypeInt() == Event.ONLOAD) {
+ finishTest();
+ }
+ super.onBrowserEvent(event);
+ }
+ };
+
+ frame.sinkEvents(Event.ONLOAD);
+ RootPanel.get().add(frame);
+ frame.setUrl("iframetest.html");
+ }
+
+ public void testOnLoadEventFiresWithLoadHandler() {
+ delayTestFinish(FRAME_LOAD_DELAY);
+
+ Frame frame = new Frame();
+ frame.addLoadHandler(new LoadHandler() {
+ public void onLoad(LoadEvent event) {
+ finishTest();
+ }
+ });
+
+ RootPanel.get().add(frame);
+ frame.setUrl("iframetest.html");
+ }
+
+ public void testOnLoadEventFiresWithDomLoadHandler() {
+ delayTestFinish(FRAME_LOAD_DELAY);
+
+ Frame frame = new Frame() {
+ {
+ addDomHandler(new LoadHandler() {
+ public void onLoad(LoadEvent event) {
+ finishTest();
+ }
+ }, LoadEvent.getType());
+ }
+ };
+
+ RootPanel.get().add(frame);
+ frame.setUrl("iframetest.html");
+ }
}
diff --git a/user/test/com/google/gwt/dom/public-test/iframetest.html b/user/test/com/google/gwt/dom/public-test/iframetest.html
new file mode 100644
index 0000000..0ebc59c
--- /dev/null
+++ b/user/test/com/google/gwt/dom/public-test/iframetest.html
@@ -0,0 +1,10 @@
+<html>
+ <head>
+ <title>
+ IFRAME TEST
+ </title>
+ </head>
+ <body>
+ IFRAME TEST
+ </body>
+</html>
diff --git a/user/test/com/google/gwt/touch/client/TouchScrollTest.java b/user/test/com/google/gwt/touch/client/TouchScrollTest.java
index 6b07f39..bcf035a 100644
--- a/user/test/com/google/gwt/touch/client/TouchScrollTest.java
+++ b/user/test/com/google/gwt/touch/client/TouchScrollTest.java
@@ -257,7 +257,7 @@
public void testCreateIfSupported() {
// createIfSupported()
TouchScroller scroller = TouchScroller.createIfSupported();
- if (isTouchSupported()) {
+ if (TouchScroller.isSupported()) {
assertNotNull("TouchScroll not created, but touch is supported", scroller);
assertNull(scroller.getTargetWidget());
@@ -268,7 +268,7 @@
// createIfSupported(HasScrolling)
HasScrolling target = new ScrollPanel();
scroller = TouchScroller.createIfSupported(target);
- if (isTouchSupported()) {
+ if (TouchScroller.isSupported()) {
assertNotNull("TouchScroll not created, but touch is supported", scroller);
assertEquals(target, scroller.getTargetWidget());
@@ -511,10 +511,4 @@
scrollPanel = null;
scroller = null;
}
-
- private native boolean isTouchSupported() /*-{
- var elem = document.createElement('div');
- elem.setAttribute('ontouchstart', 'return;');
- return (typeof elem.ontouchstart) == "function";
- }-*/;
}
diff --git a/user/test/org/hibernate/jsr303/tck/tests/constraints/constraintcomposition/ConstraintCompositionCompileTest.java b/user/test/org/hibernate/jsr303/tck/tests/constraints/constraintcomposition/ConstraintCompositionCompileTest.java
index f4637a8..338b25a 100644
--- a/user/test/org/hibernate/jsr303/tck/tests/constraints/constraintcomposition/ConstraintCompositionCompileTest.java
+++ b/user/test/org/hibernate/jsr303/tck/tests/constraints/constraintcomposition/ConstraintCompositionCompileTest.java
@@ -24,6 +24,7 @@
import org.hibernate.jsr303.tck.util.TckCompileTestCase;
+import javax.validation.ConstraintDefinitionException;
import javax.validation.UnexpectedTypeException;
/**
@@ -53,4 +54,30 @@
MustBeApplicableValidatorFactory.MustBeApplicableValidator.class,
Shoe.class);
}
+
+ /**
+ * Replacement for
+ * {@link ConstraintCompositionTest#testOverriddenAttributesMustMatchInType()}
+ *
+ * @throws UnableToCompleteException
+ */
+ public void testOverriddenAttributesMustMatchInType()
+ throws UnableToCompleteException {
+ UnitTestTreeLogger.Builder builder = new UnitTestTreeLogger.Builder();
+ builder.expect(Type.ERROR, "Unable to create a validator for "
+ + "org.hibernate.jsr303.tck.tests.constraints.constraintcomposition."
+ + "ConstraintCompositionTest.DummyEntityWithZipCode "
+ + "because The overriding type of a composite constraint must be "
+ + "identical to the overridden one. "
+ + "Expected int found class java.lang.String",
+ ConstraintDefinitionException.class);
+ builder.setLowestLogLevel(Type.INFO);
+ UnitTestTreeLogger testLogger = builder.createLogger();
+ assertModuleFails(
+ testLogger,
+ getFullyQaulifiedModuleName(getClass(),
+ "OverriddenAttributesMustMatchInTypeTest"),
+ OverriddenAttributesMustMatchInTypeValidatorFactory.OverriddenAttributesMustMatchInTypeValidator.class);
+ }
+
}
diff --git a/user/test/org/hibernate/jsr303/tck/tests/constraints/constraintcomposition/ConstraintCompositionGwtTest.java b/user/test/org/hibernate/jsr303/tck/tests/constraints/constraintcomposition/ConstraintCompositionGwtTest.java
index 5fee2ac..859183a 100644
--- a/user/test/org/hibernate/jsr303/tck/tests/constraints/constraintcomposition/ConstraintCompositionGwtTest.java
+++ b/user/test/org/hibernate/jsr303/tck/tests/constraints/constraintcomposition/ConstraintCompositionGwtTest.java
@@ -56,11 +56,6 @@
delegate.testOnlySingleConstraintViolation();
}
- @Failing(issue = 5799)
- public void testOverriddenAttributesMustMatchInType() {
- delegate.testOverriddenAttributesMustMatchInType();
- }
-
public void testPayloadPropagationInComposedConstraints() {
delegate.testPayloadPropagationInComposedConstraints();
}
diff --git a/user/test/org/hibernate/jsr303/tck/tests/constraints/constraintcomposition/OverriddenAttributesMustMatchInTypeTest.gwt.xml b/user/test/org/hibernate/jsr303/tck/tests/constraints/constraintcomposition/OverriddenAttributesMustMatchInTypeTest.gwt.xml
new file mode 100644
index 0000000..95895a8
--- /dev/null
+++ b/user/test/org/hibernate/jsr303/tck/tests/constraints/constraintcomposition/OverriddenAttributesMustMatchInTypeTest.gwt.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.0.1//EN" "http://google-web-toolkit.googlecode.com/svn/tags/2.0.1/distro-source/core/src/gwt-module.dtd">
+<!--
+ 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.
+-->
+<module>
+ <inherits name="org.hibernate.jsr303.tck.tests.ValidationTck" />
+ <source path="">
+ <include name="*.java" />
+ <exclude name="*CompileTest.java" />
+ </source>
+ <replace-with class="org.hibernate.jsr303.tck.tests.constraints.constraintcomposition.OverriddenAttributesMustMatchInTypeValidatorFactory">
+ <when-type-is class="javax.validation.ValidatorFactory"/>
+ </replace-with>
+</module>
\ No newline at end of file
diff --git a/user/test/org/hibernate/jsr303/tck/tests/constraints/constraintcomposition/OverriddenAttributesMustMatchInTypeValidatorFactory.java b/user/test/org/hibernate/jsr303/tck/tests/constraints/constraintcomposition/OverriddenAttributesMustMatchInTypeValidatorFactory.java
new file mode 100644
index 0000000..04be602
--- /dev/null
+++ b/user/test/org/hibernate/jsr303/tck/tests/constraints/constraintcomposition/OverriddenAttributesMustMatchInTypeValidatorFactory.java
@@ -0,0 +1,32 @@
+package org.hibernate.jsr303.tck.tests.constraints.constraintcomposition;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.validation.client.AbstractGwtValidatorFactory;
+import com.google.gwt.validation.client.GwtValidation;
+import com.google.gwt.validation.client.impl.AbstractGwtValidator;
+
+import org.hibernate.jsr303.tck.tests.constraints.constraintcomposition.ConstraintCompositionTest.DummyEntityWithZipCode;
+
+import javax.validation.Validator;
+
+/**
+ * {@link AbstractGwtValidatorFactory} implementation that uses
+ * {@link com.google.gwt.validation.client.GwtValidation GwtValidation}.
+ */
+public final class OverriddenAttributesMustMatchInTypeValidatorFactory extends
+ AbstractGwtValidatorFactory {
+
+ /**
+ * Validator for
+ * {@link ConstraintCompositionTest#testOverriddenAttributesMustMatchInType()}
+ */
+ @GwtValidation(value = {DummyEntityWithZipCode.class})
+ public static interface OverriddenAttributesMustMatchInTypeValidator extends
+ Validator {
+ }
+
+ @Override
+ public AbstractGwtValidator createValidator() {
+ return GWT.create(OverriddenAttributesMustMatchInTypeValidator.class);
+ }
+}
\ No newline at end of file
diff --git a/user/test/org/hibernate/jsr303/tck/util/TckCompileTestCase.java b/user/test/org/hibernate/jsr303/tck/util/TckCompileTestCase.java
index 71740ac..dd7f4da 100644
--- a/user/test/org/hibernate/jsr303/tck/util/TckCompileTestCase.java
+++ b/user/test/org/hibernate/jsr303/tck/util/TckCompileTestCase.java
@@ -39,7 +39,7 @@
@Override
protected void gwtTearDown() throws Exception {
- BeanHelper.clearBeanHelpersForTests();
+ BeanHelper.clearBeanHelpersForTests();
super.gwtTearDown();
}