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(); }