Updated rpc generator result caching to support full cacheability Also added support for changes to relevant properties and custom field serializers Review at http://gwt-code-reviews.appspot.com/1464802 git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10357 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/rebind/rpc/CachedRpcTypeInformation.java b/user/src/com/google/gwt/user/rebind/rpc/CachedRpcTypeInformation.java new file mode 100644 index 0000000..24b2fa7 --- /dev/null +++ b/user/src/com/google/gwt/user/rebind/rpc/CachedRpcTypeInformation.java
@@ -0,0 +1,202 @@ +/* + * 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 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.user.rebind.rpc; + +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.typeinfo.JArrayType; +import com.google.gwt.core.ext.typeinfo.JPrimitiveType; +import com.google.gwt.core.ext.typeinfo.JRawType; +import com.google.gwt.core.ext.typeinfo.JRealClassType; +import com.google.gwt.core.ext.typeinfo.JType; +import com.google.gwt.core.ext.typeinfo.TypeOracle; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * A container for type information, for use with generator result caching. + */ +public class CachedRpcTypeInformation implements Serializable { + private final Map<String, Long> lastModifiedTimes = new HashMap<String, Long>(); + private final Set<String> instantiableFromBrowser = new HashSet<String>(); + private final Set<String> instantiableToBrowser = new HashSet<String>(); + private final Set<String> serializableFromBrowser = new HashSet<String>(); + private final Set<String> serializableToBrowser = new HashSet<String>(); + private final Set<String> typesNotUsingCustomSerializer = new HashSet<String>(); + private final Set<String> customSerializerTypes = new HashSet<String>(); + + public CachedRpcTypeInformation(SerializableTypeOracle typesFromBrowser, + SerializableTypeOracle typesToBrowser, Set<JType> customSerializersUsed, + Set<JType> typesNotUsingCustomSerializers) { + + recordTypes(serializableFromBrowser, instantiableFromBrowser, typesFromBrowser); + recordTypes(serializableToBrowser, instantiableToBrowser, typesToBrowser); + + for (JType type : customSerializersUsed) { + addCustomSerializerType(type); + } + + for (JType type : typesNotUsingCustomSerializers) { + addTypeNotUsingCustomSerializer(type); + } + } + + public void addCustomSerializerType(JType type) { + String sourceName = type.getQualifiedSourceName(); + lastModifiedTimes.put(sourceName, getLastModifiedTime(type)); + customSerializerTypes.add(sourceName); + } + + public void addTypeNotUsingCustomSerializer(JType type) { + String sourceName = type.getQualifiedSourceName(); + typesNotUsingCustomSerializer.add(sourceName); + } + + public boolean checkLastModifiedTime(JType type) { + Long cachedTime = lastModifiedTimes.get(type.getQualifiedSourceName()); + if (cachedTime == null) { + return false; + } + return cachedTime == getLastModifiedTime(type); + } + + public boolean checkTypeInformation(TreeLogger logger, TypeOracle typeOracle, + SerializableTypeOracle typesFromBrowser, SerializableTypeOracle typesToBrowser) { + + JType[] typesFrom = typesFromBrowser.getSerializableTypes(); + if (typesFrom.length != serializableFromBrowser.size()) { + if (logger.isLoggable(TreeLogger.TRACE)) { + logger.log(TreeLogger.TRACE, + "The number of serializable types sent from the browser has changed"); + logDifferencesBetweenCurrentAndCachedTypes(logger, typesFrom, serializableFromBrowser); + } + return false; + } + + JType[] typesTo = typesToBrowser.getSerializableTypes(); + if (typesTo.length != serializableToBrowser.size()) { + if (logger.isLoggable(TreeLogger.TRACE)) { + logger.log(TreeLogger.TRACE, + "The number of serializable types sent to the browser has changed"); + logDifferencesBetweenCurrentAndCachedTypes(logger, typesTo, serializableToBrowser); + } + return false; + } + + if (!checkTypes(logger, serializableFromBrowser, instantiableFromBrowser, typesFromBrowser) + || !checkTypes(logger, serializableToBrowser, instantiableToBrowser, typesToBrowser)) { + return false; + } + + for (String customSerializerType : customSerializerTypes) { + JType currType = typeOracle.findType(customSerializerType); + if (currType == null) { + logger.log(TreeLogger.TRACE, "Custom serializer no longer available: " + + customSerializerType); + return false; + } + if (!checkLastModifiedTime(currType)) { + logger.log(TreeLogger.TRACE, "A change was detected in custom serializer: " + + customSerializerType); + return false; + } + } + + for (String sourceName : typesNotUsingCustomSerializer) { + String fieldSerializerName = + SerializableTypeOracleBuilder.getCustomFieldSerializerName(sourceName); + if (SerializableTypeOracleBuilder.findCustomFieldSerializer(typeOracle, fieldSerializerName) != null) { + logger.log(TreeLogger.TRACE, "A new custom serializer is available " + sourceName); + return false; + } + } + + return true; + } + + public boolean checkTypeNotUsingCustomSerializer(JType type) { + return typesNotUsingCustomSerializer.contains(type.getQualifiedSourceName()); + } + + /* + * Finds a last modified time for a type, for testing cacheability. + */ + public long getLastModifiedTime(JType type) { + JType typeToCheck; + if (type instanceof JArrayType) { + typeToCheck = type.getLeafType(); + } else if (type instanceof JRawType) { + typeToCheck = ((JRawType) type).getGenericType(); + } else { + assert type instanceof JRealClassType; + typeToCheck = type; + } + + if (typeToCheck instanceof JRealClassType) { + return ((JRealClassType) typeToCheck).getLastModifiedTime(); + } else { + // we have a type that is an array with a primitive leafType + assert typeToCheck instanceof JPrimitiveType; + // this type is never out of date + return Long.MAX_VALUE; + } + } + + private boolean checkTypes(TreeLogger logger, Set<String> serializable, Set<String> instantiable, + SerializableTypeOracle sto) { + for (JType type : sto.getSerializableTypes()) { + String sourceName = type.getQualifiedSourceName(); + if (sto.isSerializable(type) != serializable.contains(sourceName) + || sto.maybeInstantiated(type) != instantiable.contains(sourceName) + || !checkLastModifiedTime(type)) { + logger.log(TreeLogger.TRACE, "A change was detected in type " + sourceName); + return false; + } + } + return true; + } + + private void logDifferencesBetweenCurrentAndCachedTypes(TreeLogger logger, JType[] currentTypes, + Set<String> cachedTypes) { + + Set<String> remainingCachedTypes = new HashSet<String>(cachedTypes); + for (JType currentType : currentTypes) { + String sourceName = currentType.getQualifiedSourceName(); + if (!remainingCachedTypes.remove(sourceName)) { + logger.log(TreeLogger.TRACE, "New type " + sourceName + " not in cached list"); + } + } + + for (String remainingCachedType : remainingCachedTypes) { + logger.log(TreeLogger.TRACE, "Cached type " + remainingCachedType + " not in new list"); + } + } + + private void recordTypes(Set<String> serializable, Set<String> instantiable, + SerializableTypeOracle sto) { + for (JType type : sto.getSerializableTypes()) { + String sourceName = type.getQualifiedSourceName(); + lastModifiedTimes.put(sourceName, getLastModifiedTime(type)); + serializable.add(sourceName); + if (sto.maybeInstantiated(type)) { + instantiable.add(sourceName); + } + } + } +}
diff --git a/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java b/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java index 8446a30..71acaee 100644 --- a/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java +++ b/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java
@@ -37,6 +37,10 @@ import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.dev.generator.NameFactory; import com.google.gwt.dev.javac.rebind.CachedClientDataMap; +import com.google.gwt.dev.javac.rebind.CachedPropertyInformation; +import com.google.gwt.dev.javac.rebind.CachedRebindResult; +import com.google.gwt.dev.javac.rebind.RebindResult; +import com.google.gwt.dev.javac.rebind.RebindStatus; import com.google.gwt.dev.util.Util; import com.google.gwt.dev.util.log.speedtracer.CompilerEventType; import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger; @@ -71,6 +75,7 @@ import java.io.UnsupportedEncodingException; import java.io.Writer; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -83,16 +88,42 @@ */ public class ProxyCreator { /** + * Some keys for storing cached information for use with generator result + * caching. + */ + public static final String CACHED_PROPERTY_INFO_KEY = "cached-property-info"; + public static final String CACHED_TYPE_INFO_KEY = "cached-type-info"; + + /** * The directory within which RPC manifests are placed for individual * permutations. */ public static final String MANIFEST_ARTIFACT_DIR = "rpcPolicyManifest/manifests"; - private static final Map<JPrimitiveType, ResponseReader> JPRIMITIVETYPE_TO_RESPONSEREADER = - new HashMap<JPrimitiveType, ResponseReader>(); + /** + * Properties which need to be checked to determine cacheability. + */ + private static final Collection<String> configPropsToCheck = Arrays.asList( + TypeSerializerCreator.GWT_ELIDE_TYPE_NAMES_FROM_RPC, Shared.RPC_ENHANCED_CLASSES); + private static final Collection<String> selectionPropsToCheck = Arrays + .asList(Shared.RPC_PROP_SUPPRESS_NON_STATIC_FINAL_FIELD_WARNINGS); private static final String PROXY_SUFFIX = "_Proxy"; + private static final Map<JPrimitiveType, ResponseReader> JPRIMITIVETYPE_TO_RESPONSEREADER = + new HashMap<JPrimitiveType, ResponseReader>(); + static { + JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.BOOLEAN, ResponseReader.BOOLEAN); + JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.BYTE, ResponseReader.BYTE); + JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.CHAR, ResponseReader.CHAR); + JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.DOUBLE, ResponseReader.DOUBLE); + JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.FLOAT, ResponseReader.FLOAT); + JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.INT, ResponseReader.INT); + JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.LONG, ResponseReader.LONG); + JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.SHORT, ResponseReader.SHORT); + JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.VOID, ResponseReader.VOID); + } + /** * Adds a root type for each type that appears in the RemoteService interface * methods. @@ -196,7 +227,7 @@ for (JType[] a : types) { typesList.addAll(Arrays.asList(a)); } - JType[] serializableTypes = typesList.toArray(new JType[0]); + JType[] serializableTypes = typesList.toArray(new JType[typesList.size()]); Arrays.sort(serializableTypes, SerializableTypeOracleBuilder.JTYPE_COMPARATOR); return serializableTypes; } @@ -205,24 +236,13 @@ private boolean elideTypeNames; - private Map<String, Long> cachedTypeLastModifiedTimes = null; - /** * The possibly obfuscated type signatures used to represent a type. */ private Map<JType, String> typeStrings; - { - JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.BOOLEAN, ResponseReader.BOOLEAN); - JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.BYTE, ResponseReader.BYTE); - JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.CHAR, ResponseReader.CHAR); - JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.DOUBLE, ResponseReader.DOUBLE); - JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.FLOAT, ResponseReader.FLOAT); - JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.INT, ResponseReader.INT); - JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.LONG, ResponseReader.LONG); - JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.SHORT, ResponseReader.SHORT); - JPRIMITIVETYPE_TO_RESPONSEREADER.put(JPrimitiveType.VOID, ResponseReader.VOID); - } + private Set<JType> customSerializersUsed; + private Set<JType> typesNotUsingCustomSerializers; public ProxyCreator(JClassType serviceIntf) { assert (serviceIntf.isInterface() != null); @@ -234,7 +254,7 @@ * * @throws UnableToCompleteException */ - public String create(TreeLogger logger, GeneratorContextExt context) + public RebindResult create(TreeLogger logger, GeneratorContextExt context) throws UnableToCompleteException { TypeOracle typeOracle = context.getTypeOracle(); @@ -247,9 +267,8 @@ throw new UnableToCompleteException(); } - SourceWriter srcWriter = getSourceWriter(logger, context, serviceAsync); - if (srcWriter == null) { - return getProxyQualifiedName(); + if (checkAlreadyGenerated(typeOracle, serviceIntf)) { + return new RebindResult(RebindStatus.USE_EXISTING, getProxyQualifiedName()); } // Make sure that the async and synchronous versions of the RemoteService @@ -265,15 +284,52 @@ // Determine the set of serializable types Event event = SpeedTracerLogger.start(CompilerEventType.GENERATOR_RPC_STOB); + SerializableTypeOracle typesSentFromBrowser; + SerializableTypeOracle typesSentToBrowser; + String rpcLog; + try { + SerializableTypeOracleBuilder typesSentFromBrowserBuilder = + new SerializableTypeOracleBuilder(logger, propertyOracle, context); + typesSentFromBrowserBuilder.setTypeFilter(blacklistTypeFilter); + SerializableTypeOracleBuilder typesSentToBrowserBuilder = + new SerializableTypeOracleBuilder(logger, propertyOracle, context); + typesSentToBrowserBuilder.setTypeFilter(blacklistTypeFilter); - SerializableTypeOracleBuilder typesSentFromBrowserBuilder = - new SerializableTypeOracleBuilder(logger, propertyOracle, context); - typesSentFromBrowserBuilder.setTypeFilter(blacklistTypeFilter); - SerializableTypeOracleBuilder typesSentToBrowserBuilder = - new SerializableTypeOracleBuilder(logger, propertyOracle, context); - typesSentToBrowserBuilder.setTypeFilter(blacklistTypeFilter); + addRoots(logger, typeOracle, typesSentFromBrowserBuilder, typesSentToBrowserBuilder); - addRoots(logger, typeOracle, typesSentFromBrowserBuilder, typesSentToBrowserBuilder); + // Decide what types to send in each direction. + // Log the decisions to a string that will be written later in this method + { + StringWriter stringWriter = new StringWriter(); + PrintWriter writer = new PrintWriter(stringWriter); + + typesSentFromBrowserBuilder.setLogOutputWriter(writer); + typesSentToBrowserBuilder.setLogOutputWriter(writer); + + writer.write("====================================\n"); + writer.write("Types potentially sent from browser:\n"); + writer.write("====================================\n\n"); + writer.flush(); + typesSentFromBrowser = typesSentFromBrowserBuilder.build(logger); + + writer.write("===================================\n"); + writer.write("Types potentially sent from server:\n"); + writer.write("===================================\n\n"); + writer.flush(); + typesSentToBrowser = typesSentToBrowserBuilder.build(logger); + + writer.close(); + rpcLog = stringWriter.toString(); + } + } finally { + event.end(); + } + + // Check generator result cacheability, to see if we can return now + if (checkGeneratorResultCacheability(logger, context, typesSentFromBrowser, typesSentToBrowser)) { + logger.log(TreeLogger.TRACE, "Reusing all cached artifacts for " + getProxyQualifiedName()); + return new RebindResult(RebindStatus.USE_ALL_CACHED, getProxyQualifiedName()); + } try { ConfigurationProperty prop = @@ -287,34 +343,12 @@ throw new UnableToCompleteException(); } - // Decide what types to send in each direction. - // Log the decisions to a string that will be written later in this method - SerializableTypeOracle typesSentFromBrowser; - SerializableTypeOracle typesSentToBrowser; - String rpcLog; - { - StringWriter stringWriter = new StringWriter(); - PrintWriter writer = new PrintWriter(stringWriter); - - typesSentFromBrowserBuilder.setLogOutputWriter(writer); - typesSentToBrowserBuilder.setLogOutputWriter(writer); - - writer.write("====================================\n"); - writer.write("Types potentially sent from browser:\n"); - writer.write("====================================\n\n"); - writer.flush(); - typesSentFromBrowser = typesSentFromBrowserBuilder.build(logger); - - writer.write("===================================\n"); - writer.write("Types potentially sent from server:\n"); - writer.write("===================================\n\n"); - writer.flush(); - typesSentToBrowser = typesSentToBrowserBuilder.build(logger); - - writer.close(); - rpcLog = stringWriter.toString(); + SourceWriter srcWriter = getSourceWriter(logger, context, serviceAsync); + if (srcWriter == null) { + // don't expect this to occur, but could happen if an instance was + // recently generated but not yet committed + return new RebindResult(RebindStatus.USE_EXISTING, getProxyQualifiedName()); } - event.end(); generateTypeHandlers(logger, context, typesSentFromBrowser, typesSentToBrowser); @@ -344,12 +378,26 @@ serializationPolicyStrongName, rpcLog)); } - return getProxyQualifiedName(); - } + if (context.isGeneratorResultCachingEnabled()) { + // Remember the type info that we care about for cacheability testing. + CachedClientDataMap clientData = new CachedClientDataMap(); + CachedRpcTypeInformation cti = + new CachedRpcTypeInformation(typesSentFromBrowser, typesSentToBrowser, + customSerializersUsed, typesNotUsingCustomSerializers); + clientData.put(CACHED_TYPE_INFO_KEY, cti); + CachedPropertyInformation cpi = + new CachedPropertyInformation(logger, context.getPropertyOracle(), selectionPropsToCheck, + configPropsToCheck); + clientData.put(CACHED_PROPERTY_INFO_KEY, cpi); - public void updateResultCacheData(CachedClientDataMap clientData) { - if (cachedTypeLastModifiedTimes != null) { - clientData.put(TypeSerializerCreator.CACHED_TYPE_INFO_KEY, cachedTypeLastModifiedTimes); + /* + * Return with RebindStatus.USE_PARTIAL_CACHED, since we are allowing + * generator result caching for field serializers, but other generated + * types cannot be cached effectively. + */ + return new RebindResult(RebindStatus.USE_PARTIAL_CACHED, getProxyQualifiedName(), clientData); + } else { + return new RebindResult(RebindStatus.USE_ALL_NEW_WITH_NO_CACHING, getProxyQualifiedName()); } } @@ -655,7 +703,8 @@ typeStrings = new HashMap<JType, String>(tsc.getTypeStrings()); typeStrings.put(serviceIntf, TypeNameObfuscator.SERVICE_INTERFACE_ID); - cachedTypeLastModifiedTimes = tsc.getTypeLastModifiedTimeMap(); + customSerializersUsed = tsc.getCustomSerializersUsed(); + typesNotUsingCustomSerializers = tsc.getTypesNotUsingCustomSerializers(); } protected String getProxySimpleName() { @@ -777,6 +826,44 @@ } } + private boolean checkAlreadyGenerated(TypeOracle typeOracle, JClassType serviceAsync) { + JPackage serviceIntfPkg = serviceAsync.getPackage(); + String packageName = serviceIntfPkg == null ? "" : serviceIntfPkg.getName(); + return typeOracle.findType(packageName, getProxySimpleName()) != null; + } + + private boolean checkGeneratorResultCacheability(TreeLogger logger, GeneratorContextExt ctx, + SerializableTypeOracle typesSentFromBrowser, SerializableTypeOracle typesSentToBrowser) { + + CachedRebindResult lastResult = ctx.getCachedGeneratorResult(); + if (lastResult == null || !ctx.isGeneratorResultCachingEnabled()) { + return false; + } + + CachedPropertyInformation cpi = + (CachedPropertyInformation) lastResult.getClientData(CACHED_PROPERTY_INFO_KEY); + if (cpi == null) { + return false; + } + + CachedRpcTypeInformation cti = + (CachedRpcTypeInformation) lastResult.getClientData(CACHED_TYPE_INFO_KEY); + if (cti == null) { + return false; + } + + if (!cti.checkTypeInformation(logger, ctx.getTypeOracle(), typesSentFromBrowser, + typesSentToBrowser)) { + return false; + } + + if (!cpi.checkPropertiesWithPropertyOracle(logger, ctx.getPropertyOracle())) { + return false; + } + + return true; + } + private void emitPolicyFileArtifact(TreeLogger logger, GeneratorContextExt context, String partialPath) throws UnableToCompleteException { try {
diff --git a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java index 5673994..22437ff 100644 --- a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java +++ b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
@@ -404,7 +404,20 @@ return null; } - String customFieldSerializerName = type.getQualifiedSourceName() + "_CustomFieldSerializer"; + String customFieldSerializerName = getCustomFieldSerializerName(type.getQualifiedSourceName()); + return findCustomFieldSerializer(typeOracle, customFieldSerializerName); + } + + /** + * Finds the custom field serializer for a given qualified source name. + * + * @param typeOracle + * @param customFieldSerializerName + * @return the custom field serializer for a type of <code>null</code> if + * there is not one + */ + public static JClassType findCustomFieldSerializer(TypeOracle typeOracle, + String customFieldSerializerName) { JClassType customSerializer = typeOracle.findType(customFieldSerializerName); if (customSerializer == null) { // If the type is in the java.lang or java.util packages then it will be @@ -416,6 +429,16 @@ return customSerializer; } + /** + * Returns the name for a custom field serializer, given a source name. + * + * @param sourceName + * @return the custom field serializer type name for a given source name. + */ + public static String getCustomFieldSerializerName(String sourceName) { + return sourceName + "_CustomFieldSerializer"; + } + static JRealClassType getBaseType(JClassType type) { if (type.isParameterized() != null) { return type.isParameterized().getBaseType();
diff --git a/user/src/com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java b/user/src/com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java index c49244c..60435de 100644 --- a/user/src/com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java +++ b/user/src/com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java
@@ -21,9 +21,7 @@ import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.core.ext.typeinfo.JClassType; import com.google.gwt.core.ext.typeinfo.TypeOracle; -import com.google.gwt.dev.javac.rebind.CachedClientDataMap; import com.google.gwt.dev.javac.rebind.RebindResult; -import com.google.gwt.dev.javac.rebind.RebindStatus; /** * Generator for producing the asynchronous version of a @@ -57,23 +55,7 @@ logger.branch(TreeLogger.DEBUG, "Generating client proxy for remote service interface '" + remoteService.getQualifiedSourceName() + "'", null); - String returnTypeName = proxyCreator.create(proxyLogger, ctx); - - if (ctx.isGeneratorResultCachingEnabled()) { - // Remember the type info that we care about for cacheability testing. - CachedClientDataMap clientData = new CachedClientDataMap(); - proxyCreator.updateResultCacheData(clientData); - - /* - * Return with RebindStatus.USE_PARTIAL_CACHED, since we are allowing - * generator result caching for field serializers, but other generated - * types cannot be cached effectively. - */ - return new RebindResult(RebindStatus.USE_PARTIAL_CACHED, returnTypeName, clientData); - } else { - // If we can't be cacheable, don't return a cacheable result - return new RebindResult(RebindStatus.USE_ALL_NEW_WITH_NO_CACHING, returnTypeName); - } + return proxyCreator.create(proxyLogger, ctx); } protected ProxyCreator createProxyCreator(JClassType remoteService) {
diff --git a/user/src/com/google/gwt/user/rebind/rpc/Shared.java b/user/src/com/google/gwt/user/rebind/rpc/Shared.java index 4c710d1..7db70ae 100644 --- a/user/src/com/google/gwt/user/rebind/rpc/Shared.java +++ b/user/src/com/google/gwt/user/rebind/rpc/Shared.java
@@ -37,7 +37,7 @@ * Property used to control whether or not the RPC system will emit warnings * when a type has final fields. */ - private static final String RPC_PROP_SUPPRESS_NON_STATIC_FINAL_FIELD_WARNINGS = + public static final String RPC_PROP_SUPPRESS_NON_STATIC_FINAL_FIELD_WARNINGS = "gwt.suppressNonStaticFinalFieldWarnings"; /** @@ -45,7 +45,7 @@ * (potentially) enhanced with server-only fields, to be handled specially by * RPC. */ - private static final String RPC_ENHANCED_CLASSES = "rpc.enhancedClasses"; + public static final String RPC_ENHANCED_CLASSES = "rpc.enhancedClasses"; /** * Capitalizes a name.
diff --git a/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java b/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java index 288b7cc..7489b7b 100644 --- a/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java +++ b/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
@@ -24,13 +24,9 @@ import com.google.gwt.core.ext.GeneratorContextExt; import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.UnableToCompleteException; -import com.google.gwt.core.ext.typeinfo.JArrayType; import com.google.gwt.core.ext.typeinfo.JClassType; import com.google.gwt.core.ext.typeinfo.JMethod; import com.google.gwt.core.ext.typeinfo.JParameterizedType; -import com.google.gwt.core.ext.typeinfo.JPrimitiveType; -import com.google.gwt.core.ext.typeinfo.JRawType; -import com.google.gwt.core.ext.typeinfo.JRealClassType; import com.google.gwt.core.ext.typeinfo.JType; import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.dev.javac.rebind.CachedRebindResult; @@ -63,12 +59,6 @@ public class TypeSerializerCreator { /** - * A key for storing cached type information for use with generator result - * caching. - */ - public static final String CACHED_TYPE_INFO_KEY = "cached-type-info"; - - /** * Configuration property to use type indices instead of type signatures. */ public static final String GWT_ELIDE_TYPE_NAMES_FROM_RPC = "gwt.elideTypeNamesFromRPC"; @@ -127,10 +117,12 @@ private final String typeSerializerSimpleName; - private final Map<String, Long> typeLastModifiedTimeMap; - private final Map<JType, String> typeStrings = new IdentityHashMap<JType, String>(); + private final Set<JType> typesNotUsingCustomFieldSerializers; + + private final Set<JType> customFieldSerializersUsed; + public TypeSerializerCreator(TreeLogger logger, SerializableTypeOracle serializationOracle, SerializableTypeOracle deserializationOracle, GeneratorContextExt context, String typeSerializerClassName, String typeSerializerSimpleName) @@ -169,14 +161,20 @@ } if (context.isGeneratorResultCachingEnabled()) { - typeLastModifiedTimeMap = new HashMap<String, Long>(); + typesNotUsingCustomFieldSerializers = new HashSet<JType>(); + customFieldSerializersUsed = new HashSet<JType>(); } else { - typeLastModifiedTimeMap = null; + typesNotUsingCustomFieldSerializers = null; + customFieldSerializersUsed = null; } } - public Map<String, Long> getTypeLastModifiedTimeMap() { - return typeLastModifiedTimeMap; + public Set<JType> getCustomSerializersUsed() { + return customFieldSerializersUsed; + } + + public Set<JType> getTypesNotUsingCustomSerializers() { + return typesNotUsingCustomFieldSerializers; } public Map<JType, String> getTypeStrings() { @@ -246,12 +244,21 @@ */ assert (type.isClass() != null || type.isArray() != null); + // get custom field serializer, if available + JClassType customFieldSerializer = + SerializableTypeOracleBuilder.findCustomFieldSerializer(typeOracle, type); + if (ctx.isGeneratorResultCachingEnabled()) { - // get the last modified time for our type, and remember it - typeLastModifiedTimeMap.put(type.getQualifiedSourceName(), getLastModifiedTime(type)); + // update cacheable info for next iteration + if (customFieldSerializer != null) { + customFieldSerializersUsed.add(customFieldSerializer); + } else { + typesNotUsingCustomFieldSerializers.add(type); + } // check the cache for a valid field serializer for the current type - if (findCacheableFieldSerializerAndMarkForReuseIfAvailable(logger, ctx, type)) { + if (findCacheableFieldSerializerAndMarkForReuseIfAvailable(logger, ctx, type, + customFieldSerializer)) { // we can skip re-generation of the field serializer for the current // type return; @@ -259,8 +266,6 @@ } // generate a new field serializer - JClassType customFieldSerializer = - SerializableTypeOracleBuilder.findCustomFieldSerializer(typeOracle, type); FieldSerializerCreator creator = new FieldSerializerCreator(context, serializationOracle, deserializationOracle, (JClassType) type, customFieldSerializer); @@ -290,7 +295,7 @@ * return false. */ private boolean findCacheableFieldSerializerAndMarkForReuseIfAvailable(TreeLogger logger, - GeneratorContextExt ctx, JType type) { + GeneratorContextExt ctx, JType type, JType customFieldSerializer) { CachedRebindResult lastResult = ctx.getCachedGeneratorResult(); if (lastResult == null || !ctx.isGeneratorResultCachingEnabled()) { @@ -302,6 +307,12 @@ if (type instanceof JClassType) { // check that it is available for reuse if (!lastResult.isTypeCached(fieldSerializerName)) { + if (logger.isLoggable(TreeLogger.TRACE)) { + if (ctx.getTypeOracle().findType(fieldSerializerName) == null) { + logger.log(TreeLogger.TRACE, "No cached field serializer available for " + + type.getQualifiedSourceName()); + } + } return false; } } else { @@ -309,14 +320,15 @@ } @SuppressWarnings("unchecked") - Map<String, Long> cachedLastModifiedTimes = - (Map<String, Long>) lastResult.getClientData(CACHED_TYPE_INFO_KEY); - String sourceName = type.getQualifiedSourceName(); + CachedRpcTypeInformation cachedTypeInfo = + (CachedRpcTypeInformation) lastResult.getClientData(ProxyCreator.CACHED_TYPE_INFO_KEY); - assert cachedLastModifiedTimes != null; - assert typeLastModifiedTimeMap.get(sourceName) != null; + assert cachedTypeInfo != null; boolean foundMatch = false; - if (typeLastModifiedTimeMap.get(sourceName).equals(cachedLastModifiedTimes.get(sourceName))) { + if (cachedTypeInfo.checkLastModifiedTime(type) + && ((customFieldSerializer != null && cachedTypeInfo + .checkLastModifiedTime(customFieldSerializer)) || (customFieldSerializer == null && cachedTypeInfo + .checkTypeNotUsingCustomSerializer(type)))) { // use cached version, if available foundMatch = ctx.reuseTypeFromCacheIfAvailable(fieldSerializerName); } @@ -334,29 +346,6 @@ return foundMatch; } - private long getLastModifiedTime(JType type) { - JType typeToCheck; - if (type instanceof JArrayType) { - typeToCheck = ((JArrayType) type).getLeafType(); - } else if (type instanceof JRawType) { - typeToCheck = ((JRawType) type).getGenericType(); - } else { - assert type instanceof JRealClassType; - typeToCheck = type; - } - - long lastModifiedTime; - if (typeToCheck instanceof JRealClassType) { - lastModifiedTime = ((JRealClassType) typeToCheck).getLastModifiedTime(); - } else { - // we have a type that is an array with a primitive leafType - assert typeToCheck instanceof JPrimitiveType; - lastModifiedTime = Long.MAX_VALUE; - } - - return lastModifiedTime; - } - private String[] getPackageAndClassName(String fullClassName) { String className = fullClassName; String packageName = "";