Segment the code generation in loadMethodsJava and loadSignaturesJava Change-Id: I3ef33f32ba67a849c679eb90351507f89ffc1d5c Review-Link: https://gwt-review.googlesource.com/#/c/2731/
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 753d5f0..7079db5 100644 --- a/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java +++ b/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
@@ -47,6 +47,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -82,6 +83,16 @@ private static int shardSize = -1; + /** + * The maximum number of bytes that should be used in the source code of a method body. + * The absolute maximum limit is 64k (or it will fail to compile) however 8k is the limit + * for the JIT compiler (HotSpot) and methods over this limit will run slower. We will leave a 1k + * buffer and set the limit at 7k. + */ + private static final int MAX_BYTES_PER_METHOD = 7168; + private static final String LOAD_METHODS_JAVA_HELPER_PREFIX = "populateLoadMethodsJavaMap"; + private static final String LOAD_SIGNATURES_JAVA_HELPER_PREFIX = "populateLoadSignaturesJavaMap"; + private static void computeShardSize(TreeLogger logger) throws UnableToCompleteException { String shardSizeProperty = System.getProperty(GWT_CREATEMETHODMAP_SHARD_SIZE, DEFAULT_CREATEMETHODMAP_SHARD_SIZE); @@ -422,25 +433,20 @@ /** * Writes a method to produce a map of type string -> class name of - * {@link TypeHandler} for Java. + * {@link TypeHandler} for Java. We are forced to use repeated helper methods to populate the map + * because of the limit on Java method size. * * <pre> * private static Map<String, String> loadMethodsJava() { * Map<String, String> result = new HashMap<String, String>(); - * result.put( - * "java.lang.String/2004016611", - * "com.google.gwt.user.client.rpc.core.java.lang.String_FieldSerializer" + * populateLoadMethodsJavaMap0(result); + * populateLoadMethodsJavaMap1(result); * ... * return result; * } * </pre> */ private void writeLoadMethodsJava() { - srcWriter.println("@SuppressWarnings(\"deprecation\")"); - srcWriter.println("private static Map<String, String> loadMethodsJava() {"); - srcWriter.indent(); - srcWriter.println("Map<String, String> result = new HashMap<String, String>();"); - List<JType> filteredTypes = new ArrayList<JType>(); JType[] types = getSerializableTypes(); int n = types.length; @@ -452,11 +458,23 @@ } } - for (JType type : filteredTypes) { - String typeString = typeStrings.get(type); - assert typeString != null : "Missing type signature for " + type.getQualifiedSourceName(); - srcWriter.println("result.put(\"" + typeString + "\", \"" - + SerializationUtils.getStandardSerializerName((JClassType) type) + "\");"); + // Write out as many helper methods as necessary. + Iterator<JType> filteredTypesIter = filteredTypes.iterator(); + int numHelpers = 0; + while (filteredTypesIter.hasNext()) { + writeLoadMethodsJavaHelper(filteredTypesIter, Integer.toString(numHelpers)); + numHelpers++; + } + + srcWriter.println("@SuppressWarnings(\"deprecation\")"); + srcWriter.println("private static Map<String, String> loadMethodsJava() {"); + srcWriter.indent(); + srcWriter.println("Map<String, String> result = new HashMap<String, String>();"); + + // Call all the helper methods to populate the map. + for (int helperNum = 0; helperNum < numHelpers; helperNum++) { + srcWriter.println(LOAD_METHODS_JAVA_HELPER_PREFIX + Integer.toString(helperNum) + + "(result);"); } srcWriter.println("return result;"); @@ -466,6 +484,42 @@ } /** + * Writes a helper method to add the type signatures for the specified types to the result map. + * Adds as many of the types as possible by destructively modifying the iterator but may + * finish with elements still left. + * + * <pre> + * private static void populateLoadMethodsJavaMap#(Map<String, String> result) { + * result.put( + * "java.lang.String/2004016611", + * "com.google.gwt.user.client.rpc.core.java.lang.String_FieldSerializer"); + * ... + * } + * </pre> + */ + private void writeLoadMethodsJavaHelper(Iterator<JType> iter, String methodSuffix) { + srcWriter.println("private static void " + LOAD_METHODS_JAVA_HELPER_PREFIX + methodSuffix); + srcWriter.println("(Map<String, String> result) {"); + srcWriter.indent(); + + int totalBytesEstimate = 0; + while (iter.hasNext() && totalBytesEstimate < MAX_BYTES_PER_METHOD) { + JType type = iter.next(); + String typeString = typeStrings.get(type); + assert typeString != null : "Missing type signature for " + type.getQualifiedSourceName(); + + String line = "result.put(\"" + typeString + "\", \"" + + SerializationUtils.getStandardSerializerName((JClassType) type) + "\");"; + totalBytesEstimate += line.getBytes().length; + srcWriter.println(line); + } + + srcWriter.outdent(); + srcWriter.println("}"); + srcWriter.println(); + } + + /** * Writes a method to produce a native map of type string -> handler funcs. * * <pre> @@ -536,25 +590,69 @@ /** * Writes a method to produce a map of class name to type string for Java. - * + * * <pre> * private static Map<String<?>, String> loadSignaturesJava() { * Map<String<?>, String> result = new HashMap<String<?>, String>(); - * result.put( - * com.google.gwt.user.client.rpc.core.java.lang.String_FieldSerializer.concreteType(), - * "java.lang.String/2004016611"); + * populateLoadSignaturesJavaMap0(result); + * populateLoadSignaturesJavaMap1(result); * ... * return result; * } * </pre> */ private void writeLoadSignaturesJava() { + + List<JType> allTypes = Arrays.asList(getSerializableTypes()); + Iterator<JType> allTypesIter = allTypes.iterator(); + + // Write out as many helper methods as necessary. + int numHelpers = 0; + while (allTypesIter.hasNext()) { + writeLoadSignaturesJavaHelper(allTypesIter, Integer.toString(numHelpers)); + numHelpers++; + } + srcWriter.println("@SuppressWarnings(\"deprecation\")"); srcWriter.println("private static Map<String, String> loadSignaturesJava() {"); srcWriter.indent(); srcWriter.println("Map<String, String> result = new HashMap<String, String>();"); - for (JType type : getSerializableTypes()) { + // Call all the helper methods to populate the map. + for (int helperNum = 0; helperNum < numHelpers; helperNum++) { + srcWriter.println(LOAD_SIGNATURES_JAVA_HELPER_PREFIX + + Integer.toString(helperNum) + "(result);"); + } + + srcWriter.println("return result;"); + srcWriter.outdent(); + srcWriter.println("}"); + srcWriter.println(); + } + + /** + * Writes a helper method to produce a map of class name to type string for Java. Adds as many of + * the signatures as possible by destructively modifying the iterator but may finish with elements + * still left. + * + * <pre> + * private static void populateLoadSignaturesJavaMap#(Map<String<?>, String> result) { + * result.put( + * com.google.gwt.user.client.rpc.core.java.lang.String_FieldSerializer.concreteType(), + * "java.lang.String/2004016611"); + * ... + * } + * </pre> + */ + private void writeLoadSignaturesJavaHelper(Iterator<JType> iter, String methodSuffix) { + srcWriter.println("private static void " + LOAD_SIGNATURES_JAVA_HELPER_PREFIX + + methodSuffix); + srcWriter.println("(Map<String, String> result) {"); + srcWriter.indent(); + + int totalBytesEstimate = 0; + while (iter.hasNext() && totalBytesEstimate < MAX_BYTES_PER_METHOD) { + JType type = iter.next(); String typeString = typeStrings.get(type); if (!serializationOracle.maybeInstantiated(type) @@ -572,10 +670,11 @@ typeRef = '"' + SerializationUtils.getRpcTypeName(type) + '"'; } - srcWriter.println("result.put(" + typeRef + ", \"" + typeString + "\");"); + String line = "result.put(" + typeRef + ", \"" + typeString + "\");"; + totalBytesEstimate += line.getBytes().length; + srcWriter.println(line); } - srcWriter.println("return result;"); srcWriter.outdent(); srcWriter.println("}"); srcWriter.println(); @@ -755,3 +854,4 @@ srcWriter.outdent(); } } +