Author: b...@google.com Date: Wed Feb 4 20:48:47 2009 New Revision: 4632 Added: changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/shell/SyntheticClassMember.java (contents, props changed) changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/client/rpc/impl/SerializerBase.java (contents, props changed) Modified: changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayType.java changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/js/JsInliner.java changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/js/rhino/TokenStream.java changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/shell/DispatchClassInfo.java changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/shell/JavaDispatchImpl.java changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/client/rpc/impl/ClientSerializationStreamWriter.java changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/client/rpc/impl/Serializer.java changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/server/rpc/RPC.java
Log: Removes the dependency of client-side code on type names. Allows JSNI references to class literals via @foo.Bar::class syntax. Modified: changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayType.java ============================================================================== --- changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayType.java (original) +++ changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayType.java Wed Feb 4 20:48:47 2009 @@ -87,6 +87,7 @@ public void traverse(JVisitor visitor, Context ctx) { if (visitor.visit(this, ctx)) { + visitor.acceptWithInsertRemove(fields); } visitor.endVisit(this, ctx); } Modified: changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java ============================================================================== --- changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java (original) +++ changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java Wed Feb 4 20:48:47 2009 @@ -574,7 +574,19 @@ public JReferenceType getFromTypeMap(String qualifiedBinaryOrSourceName) { String srcTypeName = qualifiedBinaryOrSourceName.replace('$', '.'); - return typeNameMap.get(srcTypeName); + + int dim = 0; + while (srcTypeName.endsWith("[]")) { + dim++; + srcTypeName = srcTypeName.substring(0, srcTypeName.length() - 2); + } + + JReferenceType toReturn = typeNameMap.get(srcTypeName); + if (toReturn == null || dim == 0) { + return toReturn; + } else { + return getTypeArray(toReturn, dim); + } } public JField getIndexedField(String string) { @@ -955,6 +967,7 @@ public void traverse(JVisitor visitor, Context ctx) { if (visitor.visit(this, ctx)) { visitor.accept(allTypes); + visitor.accept(new ArrayList<JArrayType>(allArrayTypes)); } visitor.endVisit(this, ctx); } Modified: changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java ============================================================================== --- changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java (original) +++ changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java Wed Feb 4 20:48:47 2009 @@ -31,6 +31,7 @@ import com.google.gwt.dev.jjs.ast.JCaseStatement; import com.google.gwt.dev.jjs.ast.JCastOperation; import com.google.gwt.dev.jjs.ast.JCharLiteral; +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.JContinueStatement; @@ -2828,6 +2829,9 @@ if (fieldName.equals("nullField")) { return program.getNullField(); } + } else if (fieldName.equals("class")) { + JClassLiteral lit = program.getLiteralClass(type); + return lit.getField(); } else { for (int i = 0; i < type.fields.size(); ++i) { JField field = type.fields.get(i); Modified: changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/js/JsInliner.java ============================================================================== --- changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/js/JsInliner.java (original) +++ changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/js/JsInliner.java Wed Feb 4 20:48:47 2009 @@ -837,6 +837,19 @@ return; } + /* + * Will see this with certain classes whose clinits are folded into the + * main JsProgram body. + */ + if (f.getBody() == null) { + if (ctx.canRemove()) { + ctx.removeMe(); + } else { + ctx.replaceMe(program.getUndefinedLiteral()); + } + return; + } + List<JsName> localVariableNames = new ArrayList<JsName>(); List<JsStatement> statements = new ArrayList<JsStatement>( f.getBody().getStatements()); Modified: changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/js/rhino/TokenStream.java ============================================================================== --- changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/js/rhino/TokenStream.java (original) +++ changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/js/rhino/TokenStream.java Wed Feb 4 20:48:47 2009 @@ -1506,6 +1506,17 @@ break; } } + + // Arrray-type reference + while (c == '[') { + if (']' == in.peek()) { + addToString('['); + addToString(in.read()); + c = in.read(); + } else { + break; + } + } // We have a non-ident char to classify. // Modified: changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java ============================================================================== --- changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java (original) +++ changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java Wed Feb 4 20:48:47 2009 @@ -39,6 +39,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; @@ -55,8 +56,8 @@ /** * An isolated {...@link ClassLoader} for running all user code. All user files are - * compiled from source code byte a {...@link ByteCodeCompiler}. After - * compilation, some byte code rewriting is performed to support + * compiled from source code byte a {...@link ByteCodeCompiler}. After compilation, + * some byte code rewriting is performed to support * <code>JavaScriptObject</code> and its subtypes. * * TODO: we should refactor this class to move the getClassInfoByDispId, @@ -172,7 +173,42 @@ */ private Class<?> getClassFromBinaryName(String binaryClassName) { try { - return Class.forName(binaryClassName, false, CompilingClassLoader.this); + int dims = 0; + while (binaryClassName.endsWith("[]")) { + dims++; + binaryClassName = binaryClassName.substring(0, + binaryClassName.length() - 2); + } + + Class<?> clazz; + if ("Z".equals(binaryClassName)) { + clazz = boolean.class; + } else if ("B".equals(binaryClassName)) { + clazz = byte.class; + } else if ("C".equals(binaryClassName)) { + clazz = char.class; + } else if ("D".equals(binaryClassName)) { + clazz = double.class; + } else if ("F".equals(binaryClassName)) { + clazz = float.class; + } else if ("I".equals(binaryClassName)) { + clazz = int.class; + } else if ("J".equals(binaryClassName)) { + clazz = long.class; + } else if ("S".equals(binaryClassName)) { + clazz = short.class; + } else if ("V".equals(binaryClassName)) { + clazz = void.class; + } else { + clazz = Class.forName(binaryClassName, false, + CompilingClassLoader.this); + } + + if (dims > 0) { + return Array.newInstance(clazz, new int[dims]).getClass(); + } else { + return clazz; + } } catch (ClassNotFoundException e) { return null; } @@ -597,8 +633,8 @@ * was previously cached and has not been garbage collected. * * @param javaObject the Object being wrapped - * @return the mapped wrapper, or <code>null</code> if the Java object - * mapped or if the wrapper has been garbage collected + * @return the mapped wrapper, or <code>null</code> if the Java object mapped + * or if the wrapper has been garbage collected */ public Object getWrapperForObject(Object javaObject) { return weakJavaWrapperCache.get(javaObject); Modified: changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/shell/DispatchClassInfo.java ============================================================================== --- changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/shell/DispatchClassInfo.java (original) +++ changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/shell/DispatchClassInfo.java Wed Feb 4 20:48:47 2009 @@ -177,7 +177,6 @@ * or * * x...@java.lang.object::equals(Ljava/lang/Object;)(y) - * */ // Get the methods on this class/interface. @@ -193,5 +192,8 @@ field.setAccessible(true); addMember(field, field.getName()); } + + // Add a magic field to access class literals from JSNI + addMember(new SyntheticClassMember(targetClass), "class"); } } Modified: changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/shell/JavaDispatchImpl.java ============================================================================== --- changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/shell/JavaDispatchImpl.java (original) +++ changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/shell/JavaDispatchImpl.java Wed Feb 4 20:48:47 2009 @@ -61,7 +61,19 @@ * @return the field */ public Field getField(int dispId) { - return (Field) getMember(dispId); + Member member = getMember(dispId); + + if (member instanceof SyntheticClassMember) { + try { + Field f = SyntheticClassMember.class.getDeclaredField("clazz"); + assert f != null; + return f; + } catch (SecurityException e) { + } catch (NoSuchFieldException e) { + } + assert false : "Should never get here"; + } + return (Field) member; } /** @@ -70,7 +82,13 @@ * @throws IllegalArgumentException */ public Object getFieldValue(int dispId) { - Field field = (Field) getMember(dispId); + Member member = getMember(dispId); + + if (member instanceof SyntheticClassMember) { + return member.getDeclaringClass(); + } + + Field field = (Field) member; try { return field.get(target); } catch (IllegalAccessException e) { @@ -108,7 +126,8 @@ return false; } - return getMember(dispId) instanceof Field; + Member member = getMember(dispId); + return member instanceof Field || member instanceof SyntheticClassMember; } /** Added: changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/shell/SyntheticClassMember.java ============================================================================== --- (empty file) +++ changes/bobv/elide_rpc_type_names_r4602/dev/core/src/com/google/gwt/dev/shell/SyntheticClassMember.java Wed Feb 4 20:48:47 2009 @@ -0,0 +1,46 @@ +/* + * Copyright 2009 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.shell; + +import java.lang.reflect.Member; + +/** + * This class is used to represent a synthetic field called "class" that allows + * JSNI references to class literals. + */ +class SyntheticClassMember implements Member { + private final Class<?> clazz; + + public SyntheticClassMember(Class<?> clazz) { + this.clazz = clazz; + } + + public Class getDeclaringClass() { + return clazz; + } + + public int getModifiers() { + return Member.PUBLIC; + } + + public String getName() { + return "class"; + } + + public boolean isSynthetic() { + return false; + } +} \ No newline at end of file Modified: changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/client/rpc/impl/ClientSerializationStreamWriter.java ============================================================================== --- changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/client/rpc/impl/ClientSerializationStreamWriter.java (original) +++ changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/client/rpc/impl/ClientSerializationStreamWriter.java Wed Feb 4 20:48:47 2009 @@ -201,18 +201,7 @@ clazz = e.getDeclaringClass(); } - String typeName = clazz.getName(); - - if (hasFlags(FLAG_ELIDE_TYPE_NAMES)) { - typeName = serializer.getSerializationSignature(typeName); - } else { - String serializationSignature = serializer.getSerializationSignature(typeName); - if (serializationSignature != null) { - typeName += "/" + serializationSignature; - } - } - - return typeName; + return serializer.getSerializationSignature(clazz); } @Override Modified: changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/client/rpc/impl/Serializer.java ============================================================================== --- changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/client/rpc/impl/Serializer.java (original) +++ changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/client/rpc/impl/Serializer.java Wed Feb 4 20:48:47 2009 @@ -32,9 +32,9 @@ String typeSignature) throws SerializationException; /** - * Return the serialization signature for the given type name. + * Return the serialization signature for the given type. */ - String getSerializationSignature(String typeName); + String getSerializationSignature(Class<?> clazz); /** * Instantiate an object of the given typeName from the serialized stream. Added: changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/client/rpc/impl/SerializerBase.java ============================================================================== --- (empty file) +++ changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/client/rpc/impl/SerializerBase.java Wed Feb 4 20:48:47 2009 @@ -0,0 +1,149 @@ +/* + * Copyright 2009 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.client.rpc.impl; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.JavaScriptObject; +import com.google.gwt.core.client.JsArray; +import com.google.gwt.core.client.JsArrayString; +import com.google.gwt.user.client.rpc.SerializationException; +import com.google.gwt.user.client.rpc.SerializationStreamReader; +import com.google.gwt.user.client.rpc.SerializationStreamWriter; + +import java.util.IdentityHashMap; +import java.util.Map; + +/** + * Maps class literals to type signatures and type signatures to serialization + * methods. Relies on monotonic behavior of hashcodes in web mode. In hosted + * mode, we map the underlying signature JsArray onto a proper IdentityHashMap. + */ +public abstract class SerializerBase implements Serializer { + + /** + * + */ + protected static final class MethodMap extends JavaScriptObject { + protected MethodMap() { + } + + native void deserialize(SerializationStreamReader stream, Object instance, + String signature) throws SerializationException /*-{this[signature][1](stream, instance);}-*/; + + native JsArray<JavaScriptObject> get(String signature) /*-{return this[signature];}-*/; + + native Object instantiate(SerializationStreamReader stream, String signature) + throws SerializationException /*-{return this[signature][0](stream);}-*/; + + native void put(String signature, JsArray<JavaScriptObject> methods) /*-{this[signature] = methods;}-*/; + + native void serialize(SerializationStreamWriter stream, Object instance, + String signature) throws SerializationException /*-{this[signature][2](stream, instance);}-*/; + } + + private static final Map<JsArrayString, Map<Class<?>, String>> hostedSignatureMaps; + + static { + if (GWT.isScript()) { + hostedSignatureMaps = null; + } else { + hostedSignatureMaps = new IdentityHashMap<JsArrayString, Map<Class<?>, String>>(); + } + } + + protected static final void registerMethods(MethodMap methodMap, + String signature, JsArray<JavaScriptObject> methods) { + assert signature != null : "signature"; + assert methodMap.get(signature) == null : "Duplicate signature " + + signature; + + methodMap.put(signature, methods); + } + + protected static final void registerSignature(JsArrayString signatureMap, + Class<?> clazz, String signature) { + assert clazz != null : "clazz"; + assert signature != null : "signature"; + + if (GWT.isScript()) { + assert signatureMap.get(clazz.hashCode()) == null : "Duplicate signature " + + signature; + signatureMap.set(clazz.hashCode(), signature); + + } else { + Map<Class<?>, String> subMap = getSubMap(signatureMap); + + assert !subMap.containsKey(clazz); + subMap.put(clazz, signature); + } + } + + private static Map<Class<?>, String> getSubMap(JsArrayString signatureMap) { + Map<Class<?>, String> subMap = hostedSignatureMaps.get(signatureMap); + if (subMap == null) { + subMap = new IdentityHashMap<Class<?>, String>(); + hostedSignatureMaps.put(signatureMap, subMap); + } + return subMap; + } + + public final void deserialize(SerializationStreamReader stream, + Object instance, String typeSignature) throws SerializationException { + check(typeSignature, 2); + + getMethodMap().deserialize(stream, instance, typeSignature); + } + + public final String getSerializationSignature(Class<?> clazz) { + if (GWT.isScript()) { + return getSignatureMap().get(clazz.hashCode()); + } else { + return getSubMap(getSignatureMap()).get(clazz); + } + } + + public final Object instantiate(SerializationStreamReader stream, + String typeSignature) throws SerializationException { + check(typeSignature, 1); + + return getMethodMap().instantiate(stream, typeSignature); + } + + public final void serialize(SerializationStreamWriter stream, + Object instance, String typeSignature) throws SerializationException { + check(typeSignature, 3); + + getMethodMap().serialize(stream, instance, typeSignature); + } + + protected abstract MethodMap getMethodMap(); + + protected abstract JsArrayString getSignatureMap(); + + private void check(String typeSignature, int length) + throws SerializationException { + /* + * Probably trying to serialize a type that isn't supposed to be + * serializable. + */ + if (getMethodMap().get(typeSignature) == null) { + throw new SerializationException(typeSignature); + } + + assert getMethodMap().get(typeSignature).length() >= length : "Not enough methods, expecting " + + length + " saw " + getMethodMap().get(typeSignature).length(); + } +} Modified: changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java ============================================================================== --- changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java (original) +++ changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java Wed Feb 4 20:48:47 2009 @@ -166,7 +166,7 @@ /** * The possibly obfuscated type signatures used to represent a type. */ - private Map<JType, String> typeSignatures; + private Map<JType, String> typeStrings; private JClassType serviceIntf; @@ -279,8 +279,8 @@ SerializationUtils.getTypeSerializerQualifiedName(serviceIntf)); tsc.realize(logger); - typeSignatures = new HashMap<JType, String>(tsc.getTypeSignatures()); - typeSignatures.put(serviceIntf, TypeNameObfuscator.SERVICE_INTERFACE_ID); + typeStrings = new HashMap<JType, String>(tsc.getTypeStrings()); + typeStrings.put(serviceIntf, TypeNameObfuscator.SERVICE_INTERFACE_ID); String serializationPolicyStrongName = writeSerializationPolicyFile(logger, context, typesSentFromBrowser, typesSentToBrowser); @@ -424,8 +424,8 @@ for (JParameter param : syncParams) { JType paramType = param.getType().getErasedType(); String typeName; - if (typeSignatures.containsKey(paramType)) { - typeName = typeSignatures.get(paramType); + if (typeStrings.containsKey(paramType)) { + typeName = typeStrings.get(paramType); } else { typeName = TypeOracleMediator.computeBinaryClassName(paramType); } @@ -630,7 +630,7 @@ pw.print(", " + Boolean.toString(serializationSto.isSerializable(type))); pw.print(", " + Boolean.toString(serializationSto.maybeInstantiated(type))); - pw.print(", " + typeSignatures.get(type)); + pw.print(", " + typeStrings.get(type)); /* * Include the serialization signature to bump the RPC file name if Modified: changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java ============================================================================== --- changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java (original) +++ changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java Wed Feb 4 20:48:47 2009 @@ -17,6 +17,7 @@ package com.google.gwt.user.rebind.rpc; import com.google.gwt.core.client.JavaScriptObject; +import com.google.gwt.core.client.JsArrayString; import com.google.gwt.core.ext.BadPropertyValueException; import com.google.gwt.core.ext.GeneratorContext; import com.google.gwt.core.ext.TreeLogger; @@ -31,6 +32,7 @@ import com.google.gwt.user.client.rpc.SerializationStreamReader; import com.google.gwt.user.client.rpc.SerializationStreamWriter; import com.google.gwt.user.client.rpc.impl.Serializer; +import com.google.gwt.user.client.rpc.impl.SerializerBase; import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; import com.google.gwt.user.rebind.SourceWriter; @@ -68,23 +70,11 @@ */ private static final String DEFAULT_CREATEMETHODMAP_SHARD_SIZE = "0"; - private static final String DESERIALIZE_METHOD_SIGNATURE = "public native void deserialize(" - + "SerializationStreamReader streamReader, Object instance, String typeSignature)" - + " throws SerializationException"; - /** * Java system property name to override the above. */ private static final String GWT_CREATEMETHODMAP_SHARD_SIZE = "gwt.typecreator.shard.size"; - private static final String INSTANTIATE_METHOD_SIGNATURE = "public native Object instantiate(" - + "SerializationStreamReader streamReader, String typeSignature)" - + " throws SerializationException"; - - private static final String SERIALIZE_METHOD_SIGNATURE = "public native void serialize(" - + "SerializationStreamWriter streamWriter, Object instance, String typeSignature)" - + " throws SerializationException"; - private static int shardSize = -1; private static void computeShardSize(TreeLogger logger) @@ -121,7 +111,7 @@ private final String typeSerializerClassName; - private final Map<JType, String> typeSignatures = new IdentityHashMap<JType, String>(); + private final Map<JType, String> typeStrings = new IdentityHashMap<JType, String>(); public TypeSerializerCreator(TreeLogger logger, SerializableTypeOracle serializationOracle, @@ -160,8 +150,8 @@ } } - public Map<JType, String> getTypeSignatures() { - return Collections.unmodifiableMap(typeSignatures); + public Map<JType, String> getTypeStrings() { + return Collections.unmodifiableMap(typeStrings); } public String realize(TreeLogger logger) throws UnableToCompleteException { @@ -177,22 +167,16 @@ writeStaticFields(); + writeStaticInitializer(); + writeCreateMethods(); - writeCreateSignatureMapMethod(); + writeRegisterSignatures(); - writeCreateMethodMapMethod(logger); + writeRegisterMethods(); writeRaiseSerializationException(); - writeDeserializeMethod(); - - writeGetSerializationSignatureMethod(); - - writeInstantiateMethod(); - - writeSerializeMethod(); - srcWriter.commit(logger); return typeSerializerName; @@ -282,12 +266,13 @@ packageName, className); composerFactory.addImport(JavaScriptObject.class.getName()); + composerFactory.addImport(JsArrayString.class.getName()); composerFactory.addImport(Serializer.class.getName()); composerFactory.addImport(SerializationException.class.getName()); composerFactory.addImport(SerializationStreamReader.class.getName()); composerFactory.addImport(SerializationStreamWriter.class.getName()); - composerFactory.addImplementedInterface("Serializer"); + composerFactory.setSuperclass(SerializerBase.class.getName()); return composerFactory.createSourceWriter(ctx, printWriter); } @@ -339,34 +324,6 @@ return true; } - /** - * Generate the createMethodMap function, possibly splitting it into smaller - * pieces if necessary to avoid an old Mozilla crash when dealing with - * excessively large JS functions. - * - * @param logger TreeLogger instance - * @throws UnableToCompleteException if an error is logged - */ - private void writeCreateMethodMapMethod(TreeLogger logger) - throws UnableToCompleteException { - List<JType> filteredTypes = new ArrayList<JType>(); - JType[] types = getSerializableTypes(); - int n = types.length; - for (int index = 0; index < n; ++index) { - JType type = types[index]; - if (serializationOracle.maybeInstantiated(type) - || deserializationOracle.maybeInstantiated(type)) { - filteredTypes.add(type); - } - } - if (shardSize > 0 && filteredTypes.size() > shardSize) { - writeShardedCreateMethodMapMethod(filteredTypes, shardSize); - } else { - writeSingleCreateMethodMapMethod(filteredTypes); - } - srcWriter.println(); - } - private void writeCreateMethods() { JType[] types = getSerializableTypes(); for (int typeIndex = 0; typeIndex < types.length; ++typeIndex) { @@ -396,202 +353,112 @@ } } - private void writeCreateSignatureMapMethod() { - srcWriter.println("private static native JavaScriptObject createSignatureMap() /*-" + '{'); - { - srcWriter.indent(); - srcWriter.println("return {"); - JType[] types = getSerializableTypes(); - boolean needComma = false; - for (int index = 0; index < types.length; ++index) { - JType type = types[index]; - - if (elideTypeNames) { - typeSignatures.put(type, Integer.toString(index, Character.MAX_RADIX)); - } else { - typeSignatures.put(type, getTypeString(type)); - } - - if (!serializationOracle.maybeInstantiated(type) - && !deserializationOracle.maybeInstantiated(type)) { - continue; - } - if (needComma) { - srcWriter.println(","); - } else { - needComma = true; - } - - /* - * TODO(bobv): Allow JSNI references to class literals to reduce the - * amount of string data. Perhaps - * m...@com.google.foo::class::@java.lang.Class::getName()()]='number' - * or some way of being able to compute the return value of getName(). - */ - srcWriter.print("\"" - + TypeOracleMediator.computeBinaryClassName(type) - + "\":\"" - + (elideTypeNames - ? Integer.toString(index, Character.MAX_RADIX) - : SerializationUtils.getSerializationSignature(typeOracle, type)) - + "\""); - } - srcWriter.println(); - srcWriter.println("};"); - srcWriter.outdent(); - } - srcWriter.println("}-*/;"); - srcWriter.println(); - } - - private void writeDeserializeMethod() { - srcWriter.print(DESERIALIZE_METHOD_SIGNATURE); - srcWriter.println(" /*-" + '{'); - { - String serializerTypeName = getTypeSerializerClassName(); - srcWriter.indent(); - srcWriter.println("var methodTable = @" + serializerTypeName - + "::methodMap[typeSignature];"); - srcWriter.println("if (!methodTable) {"); - srcWriter.indentln("@" + serializerTypeName - + "::raiseSerializationException(Ljava/lang/String;)(typeSignature);"); - srcWriter.println("}"); - srcWriter.println("methodTable[1](streamReader, instance);"); - srcWriter.outdent(); - } - srcWriter.println("}-*/;"); + private void writeRaiseSerializationException() { + srcWriter.println("private static void raiseSerializationException(String msg) throws SerializationException {"); + srcWriter.indentln("throw new SerializationException(msg);"); + srcWriter.println("}"); srcWriter.println(); } - private void writeGetSerializationSignatureMethod() { - String serializerTypeName = getTypeSerializerClassName(); - srcWriter.println("public native String getSerializationSignature(String typeName) /*-" + '{'); + private void writeRegisterMethods() { + srcWriter.println("private static native void registerMethods() /*-{"); srcWriter.indent(); - srcWriter.println("return @" + serializerTypeName - + "::signatureMap[typeName];"); - srcWriter.outdent(); - srcWriter.println("}-*/;"); - srcWriter.println(); - } - private void writeInstantiateMethod() { - srcWriter.print(INSTANTIATE_METHOD_SIGNATURE); - srcWriter.println(" /*-" + '{'); - { - String serializerTypeName = getTypeSerializerClassName(); - srcWriter.indent(); - srcWriter.println("var methodTable = @" + serializerTypeName - + "::methodMap[typeSignature];"); - srcWriter.println("if (!methodTable) {"); - srcWriter.indentln("@" + serializerTypeName - + "::raiseSerializationException(Ljava/lang/String;)(typeSignature);"); - srcWriter.println("}"); - srcWriter.println("return methodTable[0](streamReader);"); - srcWriter.outdent(); + List<JType> filteredTypes = new ArrayList<JType>(); + JType[] types = getSerializableTypes(); + int n = types.length; + for (int index = 0; index < n; ++index) { + JType type = types[index]; + if (serializationOracle.maybeInstantiated(type) + || deserializationOracle.maybeInstantiated(type)) { + filteredTypes.add(type); + } } - srcWriter.println("}-*/;"); - srcWriter.println(); - } - private void writeRaiseSerializationException() { - srcWriter.println("private static void raiseSerializationException(String msg) throws SerializationException {"); - srcWriter.indentln("throw new SerializationException(msg);"); - srcWriter.println("}"); - srcWriter.println(); - } + for (JType type : filteredTypes) { + + srcWriter.println("@com.google.gwt.user.client.rpc.impl.SerializerBase" + + "::registerMethods(" + + "Lcom/google/gwt/user/client/rpc/impl/SerializerBase$MethodMap;" + + "Ljava/lang/String;" + "Lcom/google/gwt/core/client/JsArray;)("); + + srcWriter.indentln("@" + typeSerializerClassName + "::methodMap,"); + + String typeString = typeStrings.get(type); + assert typeString != null : "Missing type signature for " + + type.getQualifiedSourceName(); + srcWriter.indentln("\"" + typeString + "\" , ["); - private void writeSerializeMethod() { - srcWriter.print(SERIALIZE_METHOD_SIGNATURE); - srcWriter.println(" /*-" + '{'); - { - String serializerTypeName = getTypeSerializerClassName(); srcWriter.indent(); - srcWriter.println("var methodTable = @" + serializerTypeName - + "::methodMap[typeSignature];"); - srcWriter.println("if (!methodTable) {"); - srcWriter.indentln("@" + serializerTypeName - + "::raiseSerializationException(Ljava/lang/String;)(typeSignature);"); - srcWriter.println("}"); - srcWriter.println("methodTable[2](streamWriter, instance);"); + writeTypeMethods(type); srcWriter.outdent(); + + srcWriter.indentln("]);"); + srcWriter.println(); } + + srcWriter.outdent(); srcWriter.println("}-*/;"); srcWriter.println(); } - /** - * Create a createMethodMap method which is sharded into smaller methods. This - * avoids a crash in old Mozilla dealing with very large JS functions being - * evaluated. - * - * @param types list of types to include - * @param shardSize batch size for sharding - */ - private void writeShardedCreateMethodMapMethod(List<JType> types, - int shardSize) { - srcWriter.println("private static JavaScriptObject createMethodMap() {"); - int n = types.size(); + private void writeRegisterSignatures() { + srcWriter.println("private static native void registerSignatures() /*-{"); srcWriter.indent(); - srcWriter.println("JavaScriptObject map = JavaScriptObject.createObject();"); - for (int i = 0; i < n; i += shardSize) { - srcWriter.println("createMethodMap_" + i + "(map);"); - } - srcWriter.println("return map;"); - srcWriter.outdent(); - srcWriter.println("}"); - srcWriter.println(); - for (int outerIndex = 0; outerIndex < n; outerIndex += shardSize) { - srcWriter.println("@SuppressWarnings(\"restriction\")"); - srcWriter.println("private static native void createMethodMap_" - + outerIndex + "(JavaScriptObject map) /*-" + '{'); - srcWriter.indent(); - int last = outerIndex + shardSize; - if (last > n) { - last = n; + + int index = 0; + + for (JType type : getSerializableTypes()) { + + String typeString; + if (elideTypeNames) { + typeString = Integer.toString(++index, Character.MAX_RADIX); + } else { + typeString = getTypeString(type); + } + typeStrings.put(type, typeString); + + if (!serializationOracle.maybeInstantiated(type) + && !deserializationOracle.maybeInstantiated(type)) { + continue; } - for (int i = outerIndex; i < last; ++i) { - JType type = types.get(i); - String typeString = typeSignatures.get(type); - assert typeString != null : "Missing typeSignatures entry for " - + type.getQualifiedSourceName(); - - srcWriter.print("map[\"" + typeString + "\"]=["); - writeTypeMethods(type); - srcWriter.println("];"); + + String jsniTypeRef; + jsniTypeRef = TypeOracleMediator.computeBinaryClassName(type.getLeafType()); + while (type.isArray() != null) { + jsniTypeRef += "[]"; + type = type.isArray().getComponentType(); } + srcWriter.println("@com.google.gwt.user.client.rpc.impl.SerializerBase" + + "::registerSignature(" + + "Lcom/google/gwt/core/client/JsArrayString;" + "Ljava/lang/Class;" + + "Ljava/lang/String;)("); + srcWriter.indent(); + srcWriter.println("@" + typeSerializerClassName + "::signatureMap,"); + srcWriter.println("@" + jsniTypeRef + "::class,"); + srcWriter.println("\"" + typeString + "\");"); srcWriter.outdent(); - srcWriter.println("}-*/;"); srcWriter.println(); } - } - private void writeSingleCreateMethodMapMethod(List<JType> types) { - srcWriter.println("@SuppressWarnings(\"restriction\")"); - srcWriter.println("private static native JavaScriptObject createMethodMap() /*-" + '{'); - srcWriter.indent(); - srcWriter.println("return {"); - int n = types.size(); - for (int i = 0; i < n; ++i) { - if (i > 0) { - srcWriter.println(","); - } - JType type = types.get(i); - String typeString = typeSignatures.get(type); - assert typeString != null : "Missing type signature for " - + type.getQualifiedSourceName(); - srcWriter.print("\"" + typeString + "\":["); - writeTypeMethods(type); - srcWriter.print("]"); - } - srcWriter.println("};"); srcWriter.outdent(); srcWriter.println("}-*/;"); + srcWriter.println(); } private void writeStaticFields() { - srcWriter.println("private static final JavaScriptObject methodMap = createMethodMap();"); - srcWriter.println("private static final JavaScriptObject signatureMap = createSignatureMap();"); + srcWriter.println("private static final MethodMap methodMap = JavaScriptObject.createObject().cast();"); + srcWriter.println("private static final JsArrayString signatureMap = JavaScriptObject.createArray().cast();"); + srcWriter.println("protected MethodMap getMethodMap() { return methodMap; }"); + srcWriter.println("protected JsArrayString getSignatureMap() { return signatureMap; }"); srcWriter.println(); + } + + private void writeStaticInitializer() { + srcWriter.println("static {"); + srcWriter.indentln("registerMethods();"); + srcWriter.indentln("registerSignatures();"); + srcWriter.println("}"); } /** Modified: changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/server/rpc/RPC.java ============================================================================== --- changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/server/rpc/RPC.java (original) +++ changes/bobv/elide_rpc_type_names_r4602/user/src/com/google/gwt/user/server/rpc/RPC.java Wed Feb 4 20:48:47 2009 @@ -821,6 +821,7 @@ private static String maybeDeobfuscate( ServerSerializationStreamReader streamReader, String name) throws SerializationException { + int index; if (streamReader.hasFlags(AbstractSerializationStream.FLAG_ELIDE_TYPE_NAMES)) { SerializationPolicy serializationPolicy = streamReader.getSerializationPolicy(); if (!(serializationPolicy instanceof TypeNameObfuscator)) { @@ -834,6 +835,8 @@ if (maybe != null) { return maybe; } + } else if ((index = name.indexOf('/')) != -1) { + return name.substring(0, index); } return name; } --~--~---------~--~----~------------~-------~--~----~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~----------~----~----~----~------~----~------~--~---