Reduces class and JSNI loading for RPC in devmode.

- Makes GwtScriptOnly work with JSNI methods.
- Modifies the RPC generator to tag native methods with GwtScriptOnly.
- Modifies the RPC generator to defer class loads of FieldSerializers until needed.

Review at http://gwt-code-reviews.appspot.com/1215801


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9424 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java b/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java
index fc333f6..9572448 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java
@@ -15,10 +15,12 @@
  */
 package com.google.gwt.dev.javac;
 
+import com.google.gwt.core.client.GwtScriptOnly;
 import com.google.gwt.core.ext.TreeLogger.HelpInfo;
 import com.google.gwt.dev.jjs.InternalCompilerException;
 import com.google.gwt.dev.jjs.SourceInfo;
 import com.google.gwt.dev.jjs.SourceOrigin;
+import com.google.gwt.dev.jjs.ast.JAnnotation;
 import com.google.gwt.dev.js.JsParser;
 import com.google.gwt.dev.js.JsParserException;
 import com.google.gwt.dev.js.JsParserException.SourceDetail;
@@ -30,12 +32,15 @@
 import com.google.gwt.dev.util.collect.IdentityHashMap;
 import com.google.gwt.dev.util.collect.IdentityMaps;
 
+import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.CompilationResult;
 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Annotation;
 import org.eclipse.jdt.internal.compiler.ast.Argument;
 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
 import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
 import org.eclipse.jdt.internal.compiler.util.Util;
 
@@ -66,10 +71,12 @@
   private static final class JsniMethodImpl extends JsniMethod {
     private final JsFunction func;
     private final String name;
+    private boolean isScriptOnly;
 
-    public JsniMethodImpl(String name, JsFunction func) {
+    public JsniMethodImpl(String name, JsFunction func, boolean isScriptOnly) {
       this.name = name;
       this.func = func;
+      this.isScriptOnly = isScriptOnly;
     }
 
     @Override
@@ -78,6 +85,11 @@
     }
 
     @Override
+    public boolean isScriptOnly() {
+      return isScriptOnly;
+    }
+
+    @Override
     public int line() {
       return func.getSourceInfo().getStartLine();
     }
@@ -114,6 +126,20 @@
   }
 
   private static class Visitor extends MethodVisitor {
+    private static boolean isScriptOnly(AbstractMethodDeclaration method) {
+      if (method.annotations == null) {
+        return false;
+      }
+      for (Annotation a : method.annotations) {
+        JAnnotation annotation;
+        ReferenceBinding binding = (ReferenceBinding) a.resolvedType;
+        String name = CharOperation.toString(binding.compoundName);
+        if (name.equals(GwtScriptOnly.class.getName())) {
+          return true;
+        }
+      }
+      return false;
+    }
 
     private final Map<AbstractMethodDeclaration, JsniMethod> jsniMethods;
     private final JsProgram jsProgram;
@@ -140,7 +166,7 @@
       if (jsFunction != null) {
         String jsniSignature = getJsniSignature(enclosingType, method);
         jsniMethods.put(method, new JsniMethodImpl(jsniSignature,
-            jsFunction));
+            jsFunction, isScriptOnly(method)));
       }
     }
   }
diff --git a/dev/core/src/com/google/gwt/dev/javac/JsniMethod.java b/dev/core/src/com/google/gwt/dev/javac/JsniMethod.java
index e00d001..fd0c87b 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JsniMethod.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JsniMethod.java
@@ -29,6 +29,12 @@
   public abstract JsFunction function();
 
   /**
+   * Returns true if this JSNI function should only be used from script.
+   * See {@link com.google.gwt.core.client.GwtScriptOnly GwtScriptOnly}.
+   */
+  public abstract boolean isScriptOnly();
+  
+  /**
    * Starting line number of the method.
    */
   public abstract int line();
@@ -49,7 +55,7 @@
   public abstract String[] paramNames();
 
   /**
-   * Gets the JsProgram in which {@link #function(TreeLogger)} is located.
+   * Gets the JsProgram in which this method is located.
    */
   public abstract JsProgram program();
 }
diff --git a/dev/core/src/com/google/gwt/dev/javac/StandardGeneratorContext.java b/dev/core/src/com/google/gwt/dev/javac/StandardGeneratorContext.java
index 8acc0f9..d46c927 100644
--- a/dev/core/src/com/google/gwt/dev/javac/StandardGeneratorContext.java
+++ b/dev/core/src/com/google/gwt/dev/javac/StandardGeneratorContext.java
@@ -226,6 +226,33 @@
 
   private static DiskCache diskCache = new DiskCache();
 
+  private static final Map<String,CompilerEventType> eventsByGeneratorType = new HashMap<String,CompilerEventType>();
+  static {
+    eventsByGeneratorType.put(
+        "com.google.gwt.resources.rebind.context.InlineClientBundleGenerator",
+        CompilerEventType.GENERATOR_CLIENT_BUNDLE);
+    eventsByGeneratorType.put("com.google.gwt.i18n.rebind.LocalizableGenerator",
+        CompilerEventType.GENERATOR_I18N);
+    eventsByGeneratorType.put("com.google.gwt.i18n.rebind.LocaleInfoGenerator",
+        CompilerEventType.GENERATOR_I18N);
+    eventsByGeneratorType.put(
+        "com.google.gwt.i18n.rebind.CurrencyListGenerator",
+        CompilerEventType.GENERATOR_I18N);
+    eventsByGeneratorType.put(
+        "com.google.gwt.i18n.rebind.CustomDateTimeFormatGenerator",
+        CompilerEventType.GENERATOR_I18N);
+    eventsByGeneratorType.put(
+        "com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator",
+        CompilerEventType.GENERATOR_RPC);
+    eventsByGeneratorType.put("com.google.gwt.rpc.rebind.RpcServiceGenerator",
+        CompilerEventType.GENERATOR_RPC); // deRPC
+    eventsByGeneratorType.put(
+        "com.google.gwt.uibinder.rebind.UiBinderGenerator",
+        CompilerEventType.GENERATOR_UIBINDER);
+    eventsByGeneratorType.put("com.google.gwt.inject.rebind.GinjectorGenerator",
+        CompilerEventType.GENERATOR_GIN);
+  }
+
   private final ArtifactSet allGeneratedArtifacts;
 
   private final Set<GeneratedUnit> committedGeneratedCups = new HashSet<GeneratedUnit>();
@@ -421,8 +448,16 @@
     setCurrentGenerator(generatorClass);
 
     long before = System.currentTimeMillis();
-    Event generatorEvent = SpeedTracerLogger.start(CompilerEventType.GENERATOR, "class",
-        generator.getClass().getName(), "type", typeName);
+    String generatorClassName = generator.getClass().getName();
+    CompilerEventType type = eventsByGeneratorType.get(generatorClassName);
+    
+    if (type == null) {
+      type = CompilerEventType.GENERATOR_OTHER;
+    }
+
+    Event generatorEvent = SpeedTracerLogger.start(type, "class",
+        generatorClassName, "type", typeName);
+    
     try {
       String className = generator.generate(logger, this, typeName);
       long after = System.currentTimeMillis();
diff --git a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
index 06a83fd..bfd2454 100644
--- a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
+++ b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
@@ -42,6 +42,9 @@
 import com.google.gwt.dev.util.Name.SourceOrBinaryName;
 import com.google.gwt.dev.util.Util;
 import com.google.gwt.dev.util.collect.Lists;
+import com.google.gwt.dev.util.log.speedtracer.DevModeEventType;
+import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger;
+import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event;
 import com.google.gwt.util.tools.Utility;
 
 import org.apache.commons.collections.map.AbstractReferenceMap;
@@ -1247,7 +1250,14 @@
     if (unit == null || unit.getJsniMethods() == null) {
       return;
     }
-    shellJavaScriptHost.createNativeMethods(logger, unit.getJsniMethods(), this);
+    Event event = SpeedTracerLogger.start(DevModeEventType.LOAD_JSNI, "unit",
+        unit.getTypeName());
+    try {
+      shellJavaScriptHost.createNativeMethods(logger, unit.getJsniMethods(),
+          this);
+    } finally {
+      event.end();
+    }
   }
 
   private void maybeInitializeScriptOnlyClassLoader() {
diff --git a/dev/core/src/com/google/gwt/dev/shell/ModuleSpaceOOPHM.java b/dev/core/src/com/google/gwt/dev/shell/ModuleSpaceOOPHM.java
index 7d4f75a..97b2f05 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ModuleSpaceOOPHM.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ModuleSpaceOOPHM.java
@@ -46,6 +46,9 @@
     }
     StringBuilder jsni = new StringBuilder();
     for (JsniMethod jsniMethod : jsniMethods) {
+      if (jsniMethod.isScriptOnly()) {
+        continue;
+      }
       String body = Jsni.getJavaScriptForHostedMode(logger, dispatchIdOracle,
           jsniMethod);
       if (body == null) {
diff --git a/dev/core/src/com/google/gwt/dev/util/log/speedtracer/CompilerEventType.java b/dev/core/src/com/google/gwt/dev/util/log/speedtracer/CompilerEventType.java
index e5950a7..9d3d4a3 100644
--- a/dev/core/src/com/google/gwt/dev/util/log/speedtracer/CompilerEventType.java
+++ b/dev/core/src/com/google/gwt/dev/util/log/speedtracer/CompilerEventType.java
@@ -27,7 +27,15 @@
   COMPILE_PERMUTATIONS("CompilePermutations", "BurlyWood"), //
   JJS_COMPILE_PERMUTATION("JjsCompilePermutation", "Moccasin"), //
   DRAFT_OPTIMIZE("DraftOptimizer", "Blue"), //
-  GENERATOR("Generator", "Red"), //
+  GENERATOR_CLIENT_BUNDLE("Generator ClientBundle", "#CCCC33"), //
+  GENERATOR_I18N("Generator I18N", "#FF00CC"), //
+  GENERATOR_RPC("Generator RPC", "#3300CC"), //
+  GENERATOR_RPC_STOB("Generator RPC STOB", "#3300CC"), //
+  GENERATOR_RPC_TYPE_SERIALIZER("Generator RPC Type Serializer", "#3300CC"), //
+  GENERATOR_RPC_FIELD_SERIALIZER("Generator RPC Field Serializer", "#3300CC"), //
+  GENERATOR_UIBINDER("Generator UiBinder", "#FFFF00"), //
+  GENERATOR_GIN("Generator GIN", "#009900"), //
+  GENERATOR_OTHER("Generator (Other)", "Red"), //
   JDT_COMPILER("JdtCompiler1", "#6c6"), //
   JDT_COMPILER2("JdtCompiler2", "#0c0"), //
   JDT_COMPILER3("JdtCompiler3", "#494"), //
diff --git a/dev/core/src/com/google/gwt/dev/util/log/speedtracer/DevModeEventType.java b/dev/core/src/com/google/gwt/dev/util/log/speedtracer/DevModeEventType.java
index cb4b380..c011fe9 100644
--- a/dev/core/src/com/google/gwt/dev/util/log/speedtracer/DevModeEventType.java
+++ b/dev/core/src/com/google/gwt/dev/util/log/speedtracer/DevModeEventType.java
@@ -30,6 +30,7 @@
   JAVA_TO_JS_CALL("Java to JS call", "LightSkyBlue"), //
   JETTY_STARTUP("Jetty startup", "Orchid"), //
   JS_TO_JAVA_CALL("JS to Java call", "Orange"), //
+  LOAD_JSNI("Parse and Load JSNI", "LightCoral"), //
   MODULE_INIT("Module init", "Khaki"), //
   MODULE_SPACE_CLASS_LOAD("ModuleSpace class load", "MintCream"), //
   MODULE_SPACE_HOST_CREATE("ModuleSpaceHost create", "Peachpuff"), //
diff --git a/dev/core/super/com/google/gwt/core/client/GwtScriptOnly.java b/dev/core/super/com/google/gwt/core/client/GwtScriptOnly.java
index 9161f97..811baed 100644
--- a/dev/core/super/com/google/gwt/core/client/GwtScriptOnly.java
+++ b/dev/core/super/com/google/gwt/core/client/GwtScriptOnly.java
@@ -29,8 +29,13 @@
  * to provide web-mode implementations of (binary-only) types that the developer
  * wishes to use in hosted mode. This can be used, for instance, to provide a
  * reference implementation to develop unit tests.
+ * <p>
+ * This annotation may also be applied to jsni methods to prevent them from
+ * being parsed and loaded for devmode. This is done under certain 
+ * circumstances as an optimization to avoid loading very large jsni methods
+ * which are only executed in webmode.   
  */
 @Documented
-@Target(ElementType.TYPE)
+@Target({ElementType.TYPE, ElementType.METHOD})
 public @interface GwtScriptOnly {
 }
diff --git a/tools/api-checker/config/gwt21_22userApi.conf b/tools/api-checker/config/gwt21_22userApi.conf
index 37f4e11..63bdabe 100644
--- a/tools/api-checker/config/gwt21_22userApi.conf
+++ b/tools/api-checker/config/gwt21_22userApi.conf
@@ -48,7 +48,8 @@
 :com/google/gwt/rpc/client/impl/EscapeUtil.java\
 :com/google/gwt/soyc/**\
 :com/google/gwt/safehtml/shared/SafeHtmlHostedModeUtils.java\
-:com/google/gwt/user/client/rpc/core/java/util/LinkedHashMap_CustomFieldSerializer.java\
+:com/google/gwt/user/client/rpc/core/**\
+:com/google/gwt/user/client/rpc/impl/**\
 :com/google/gwt/uibinder/attributeparsers/**\
 :com/google/gwt/uibinder/elementparsers/**\
 :com/google/gwt/uibinder/testing/**\
@@ -90,7 +91,8 @@
 :user/src/com/google/gwt/rpc/client/impl/ClientWriterFactory.java\
 :user/src/com/google/gwt/rpc/client/impl/EscapeUtil.java\
 :user/src/com/google/gwt/safehtml/shared/SafeHtmlHostedModeUtils.java\
-:user/src/com/google/gwt/user/client/rpc/core/java/util/LinkedHashMap_CustomFieldSerializer.java\
+:user/src/com/google/gwt/user/client/rpc/core/**\
+:user/src/com/google/gwt/user/client/rpc/impl/**\
 :user/src/com/google/gwt/uibinder/attributeparsers/**\
 :user/src/com/google/gwt/uibinder/elementparsers/**\
 :user/src/com/google/gwt/uibinder/testing/**\
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/util/Arrays.java b/user/src/com/google/gwt/user/client/rpc/core/java/util/Arrays.java
index 121ab51..b27afae 100644
--- a/user/src/com/google/gwt/user/client/rpc/core/java/util/Arrays.java
+++ b/user/src/com/google/gwt/user/client/rpc/core/java/util/Arrays.java
@@ -32,8 +32,8 @@
    */
   public static final class ArrayList_CustomFieldSerializer {
 
-    public static Class<?> concreteType() {
-      return java.util.Arrays.asList().getClass();
+    public static String concreteType() {
+      return java.util.Arrays.asList().getClass().getName();
     }
 
     /*
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/util/Collections.java b/user/src/com/google/gwt/user/client/rpc/core/java/util/Collections.java
index 225bf3b..6b54997 100644
--- a/user/src/com/google/gwt/user/client/rpc/core/java/util/Collections.java
+++ b/user/src/com/google/gwt/user/client/rpc/core/java/util/Collections.java
@@ -33,8 +33,8 @@
    */
   public static final class EmptyList_CustomFieldSerializer {
 
-    public static Class<?> concreteType() {
-      return java.util.Collections.emptyList().getClass();
+    public static String concreteType() {
+      return java.util.Collections.emptyList().getClass().getName();
     }
 
     @SuppressWarnings({"unused", "unchecked"})
@@ -61,8 +61,8 @@
    */
   public static final class EmptyMap_CustomFieldSerializer {
 
-    public static Class<?> concreteType() {
-      return java.util.Collections.emptyMap().getClass();
+    public static String concreteType() {
+      return java.util.Collections.emptyMap().getClass().getName();
     }
 
     @SuppressWarnings({"unused", "unchecked"})
@@ -89,8 +89,8 @@
    */
   public static final class EmptySet_CustomFieldSerializer {
 
-    public static Class<?> concreteType() {
-      return java.util.Collections.emptySet().getClass();
+    public static String concreteType() {
+      return java.util.Collections.emptySet().getClass().getName();
     }
 
     @SuppressWarnings({"unused", "unchecked"})
@@ -117,8 +117,8 @@
    */
   public static final class SingletonList_CustomFieldSerializer {
 
-    public static Class<?> concreteType() {
-      return java.util.Collections.singletonList(null).getClass();
+    public static String concreteType() {
+      return java.util.Collections.singletonList(null).getClass().getName();
     }
 
     @SuppressWarnings({"unused", "unchecked"})
diff --git a/user/src/com/google/gwt/user/client/rpc/impl/ReflectionHelper.java b/user/src/com/google/gwt/user/client/rpc/impl/ReflectionHelper.java
new file mode 100644
index 0000000..924abf6
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/rpc/impl/ReflectionHelper.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+package com.google.gwt.user.client.rpc.impl;
+
+import java.lang.reflect.Constructor;
+
+/**
+ * Provides access to reflection capability, but only when running from 
+ * bytecode.
+ */
+public class ReflectionHelper {
+
+  /**
+   * Loads {@code klass} using Class.forName.
+   */
+  public static Class<?> loadClass(String klass) throws Exception {
+    return Class.forName(klass);
+  }
+
+  /**
+   * Creates a new instance of {@code klass}. The class must have a no-arg
+   * constructor. The constructor may have any access modifier (for example,
+   * private).
+   */
+  public static <T> T newInstance(Class<T> klass)
+      throws Exception {
+    Constructor<T> c = klass.getDeclaredConstructor();
+    c.setAccessible(true);
+    return c.newInstance();
+  }  
+}
diff --git a/user/src/com/google/gwt/user/client/rpc/impl/SerializerBase.java b/user/src/com/google/gwt/user/client/rpc/impl/SerializerBase.java
index 79132e5..652e399 100644
--- a/user/src/com/google/gwt/user/client/rpc/impl/SerializerBase.java
+++ b/user/src/com/google/gwt/user/client/rpc/impl/SerializerBase.java
@@ -23,6 +23,7 @@
 import com.google.gwt.user.client.rpc.SerializationStreamReader;
 import com.google.gwt.user.client.rpc.SerializationStreamWriter;
 
+import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -64,17 +65,20 @@
     }-*/;
   }
 
-  private final Map<String, TypeHandler> methodMapJava;
-
+  private final Map<String, TypeHandler> handlerCache;
+  
+  private final Map<String, String> methodMapJava;
+  
   private final MethodMap methodMapNative;
 
-  private final Map<Class<?>, String> signatureMapJava;
+  private final Map<String, String> signatureMapJava;
 
   private final JsArrayString signatureMapNative;
 
-  public SerializerBase(Map<String, TypeHandler> methodMapJava,
-      MethodMap methodMapNative, Map<Class<?>, String> signatureMapJava,
+  public SerializerBase(Map<String, String> methodMapJava,
+      MethodMap methodMapNative, Map<String, String> signatureMapJava,
       JsArrayString signatureMapNative) {
+    this.handlerCache = new HashMap<String, TypeHandler>();
     this.methodMapJava = methodMapJava;
     this.methodMapNative = methodMapNative;
     this.signatureMapJava = signatureMapJava;
@@ -97,7 +101,7 @@
     if (GWT.isScript()) {
       return signatureMapNative.get(clazz.hashCode());
     } else {
-      return signatureMapJava.get(clazz);
+      return signatureMapJava.get(clazz.getName());
     }
   }
 
@@ -139,14 +143,27 @@
 
   private TypeHandler getTypeHandler(String typeSignature)
       throws SerializationException {
-    TypeHandler typeHandler = methodMapJava.get(typeSignature);
-    if (typeHandler == null) {
-      /*
-       * Probably trying to serialize a type that isn't supposed to be
-       * serializable.
-       */
+    String typeHandlerClass = methodMapJava.get(typeSignature);
+
+    if (typeHandlerClass == null) {
+     /*
+      * Probably trying to serialize a type that isn't supposed to be
+      * serializable.
+      */
       throw new SerializationException(typeSignature);
     }
+
+    TypeHandler typeHandler = handlerCache.get(typeHandlerClass);
+    
+    if (typeHandler == null) {
+      try {
+        Class<?> klass = ReflectionHelper.loadClass(typeHandlerClass);
+        typeHandler = (TypeHandler) ReflectionHelper.newInstance(klass);
+        handlerCache.put(typeHandlerClass, typeHandler);
+      } catch (Exception e) {
+        throw new SerializationException(e);
+      }
+    }
     return typeHandler;
   }
 }
diff --git a/user/src/com/google/gwt/user/rebind/rpc/CustomFieldSerializerValidator.java b/user/src/com/google/gwt/user/rebind/rpc/CustomFieldSerializerValidator.java
index f4c81df..b22d071 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/CustomFieldSerializerValidator.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/CustomFieldSerializerValidator.java
@@ -35,7 +35,7 @@
   private static final String NO_INSTANTIATE_METHOD = "Custom Field Serializer ''{0}'' does not define an instantiate method: ''public static {1} instantiate({2} reader)''; but ''{1}'' is not default instantiable";
   private static final String NO_SERIALIZE_METHOD = "Custom Field Serializer ''{0}'' does not define a serialize method: ''public static void serialize({1} writer,{2} instance)''";
   private static final String TOO_MANY_METHODS = "Custom Field Serializer ''{0}'' defines too many methods named ''{1}''; please define only one method with that name";
-  private static final String WRONG_CONCRETE_TYPE_RETURN = "Custom Field Serializer ''{0}'' returns the wrong type from ''concreteType''; return type must be ''java.lang.Class''";
+  private static final String WRONG_CONCRETE_TYPE_RETURN = "Custom Field Serializer ''{0}'' returns the wrong type from ''concreteType''; return type must be ''java.lang.String''";
 
   public static JMethod getConcreteTypeMethod(JClassType serializer) {
     return serializer.findMethod("concreteType", new JType[0]);
@@ -163,7 +163,7 @@
 
     JMethod concreteTypeMethod = getConcreteTypeMethod(serializer);
     if (concreteTypeMethod != null) {
-      if (!"java.lang.Class".equals(concreteTypeMethod.getReturnType().getQualifiedSourceName())) {
+      if (!"java.lang.String".equals(concreteTypeMethod.getReturnType().getQualifiedSourceName())) {
         // Wrong return type.
         reasons.add(MessageFormat.format(WRONG_CONCRETE_TYPE_RETURN,
             serializer.getQualifiedSourceName()));
diff --git a/user/src/com/google/gwt/user/rebind/rpc/FieldSerializerCreator.java b/user/src/com/google/gwt/user/rebind/rpc/FieldSerializerCreator.java
index dab6529..a8102ba 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/FieldSerializerCreator.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/FieldSerializerCreator.java
@@ -112,8 +112,6 @@
 
     writeFieldAccessors();
 
-    writeConcreteTypeMethod();
-
     writeDeserializeMethod();
 
     maybeWriteInstatiateMethod();
@@ -579,37 +577,6 @@
     }
   }
 
-  /**
-   * Writes the concreteType method, for loading a Java Class -> TypeHandler
-   * map.
-   * 
-   * <pre>
-   * public static Class&lt;?&gt; concreteType() {
-   *   return com.google.gwt.sample.client.Student.class;
-   * }
-   * </pre>
-   */
-  private void writeConcreteTypeMethod() {
-    if (customFieldSerializer != null
-        && CustomFieldSerializerValidator.getConcreteTypeMethod(customFieldSerializer) != null) {
-      return;
-    }
-
-    if (classIsAccessible()) {
-      sourceWriter.println("public static Class<?> concreteType() {");
-      sourceWriter.indentln("return "
-          + serializableClass.getQualifiedSourceName() + ".class;");
-      sourceWriter.println("}");
-      sourceWriter.println();
-    } else {
-      String jsniTypeRef = SerializationUtils.getRpcTypeName(serializableClass);
-      sourceWriter.println("public static native Class<?> concreteType() /*-{");
-      sourceWriter.indentln("return @" + jsniTypeRef + "::class;");
-      sourceWriter.println("}-*/;");
-      sourceWriter.println();
-    }
-  }
-
   private void writeDeserializeMethod() {
     if (customFieldSerializer != null) {
       return;
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 e554f1d..4921dd4 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,9 @@
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
 import com.google.gwt.dev.generator.NameFactory;
 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;
+import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event;
 import com.google.gwt.http.client.Request;
 import com.google.gwt.http.client.RequestBuilder;
 import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
@@ -280,6 +283,8 @@
         propertyOracle);
 
     // Determine the set of serializable types
+    Event event = SpeedTracerLogger.start(CompilerEventType.GENERATOR_RPC_STOB);
+    
     SerializableTypeOracleBuilder typesSentFromBrowserBuilder = new SerializableTypeOracleBuilder(
         logger, propertyOracle, typeOracle);
     typesSentFromBrowserBuilder.setTypeFilter(blacklistTypeFilter);
@@ -328,7 +333,8 @@
       writer.close();
       rpcLog = stringWriter.toString();
     }
-
+    event.end();
+    
     generateTypeHandlers(logger, context, typesSentFromBrowser,
         typesSentToBrowser);
 
@@ -687,11 +693,13 @@
       GeneratorContext context, SerializableTypeOracle typesSentFromBrowser,
       SerializableTypeOracle typesSentToBrowser)
       throws UnableToCompleteException {
+    Event event = SpeedTracerLogger.start(CompilerEventType.GENERATOR_RPC_TYPE_SERIALIZER);
     TypeSerializerCreator tsc = new TypeSerializerCreator(logger,
         typesSentFromBrowser, typesSentToBrowser, context,
         SerializationUtils.getTypeSerializerQualifiedName(serviceIntf),
         SerializationUtils.getTypeSerializerSimpleName(serviceIntf));
     tsc.realize(logger);
+    event.end();
 
     typeStrings = new HashMap<JType, String>(tsc.getTypeStrings());
     typeStrings.put(serviceIntf, TypeNameObfuscator.SERVICE_INTERFACE_ID);
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 f391d2c..9c0101a 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
@@ -17,6 +17,7 @@
 package com.google.gwt.user.rebind.rpc;
 
 import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.GwtScriptOnly;
 import com.google.gwt.core.client.JsArrayString;
 import com.google.gwt.core.ext.BadPropertyValueException;
 import com.google.gwt.core.ext.ConfigurationProperty;
@@ -28,6 +29,9 @@
 import com.google.gwt.core.ext.typeinfo.JParameterizedType;
 import com.google.gwt.core.ext.typeinfo.JType;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
+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 com.google.gwt.user.client.rpc.SerializationStreamReader;
 import com.google.gwt.user.client.rpc.SerializationStreamWriter;
 import com.google.gwt.user.client.rpc.impl.SerializerBase;
@@ -205,6 +209,7 @@
    */
   private void createFieldSerializer(TreeLogger logger, GeneratorContext ctx,
       JType type) {
+    Event event = SpeedTracerLogger.start(CompilerEventType.GENERATOR_RPC_FIELD_SERIALIZER);
     assert (type != null);
     assert (serializationOracle.isSerializable(type) || deserializationOracle.isSerializable(type));
 
@@ -228,6 +233,7 @@
         serializationOracle, deserializationOracle, (JClassType) type,
         customFieldSerializer);
     creator.realize(logger, ctx);
+    event.end();
   }
 
   /*
@@ -276,6 +282,7 @@
     composerFactory.addImport(TypeHandler.class.getName());
     composerFactory.addImport(HashMap.class.getName());
     composerFactory.addImport(Map.class.getName());
+    composerFactory.addImport(GwtScriptOnly.class.getName());
 
     composerFactory.setSuperclass(SerializerBase.class.getName());
     return composerFactory.createSourceWriter(ctx, printWriter);
@@ -317,15 +324,15 @@
   }
 
   /**
-   * Writes a method to produce a map of type string -> {@link TypeHandler}
-   * for Java.
+   * Writes a method to produce a map of type string -> class name of 
+   * {@link TypeHandler} for Java.
    * 
    * <pre>
-   * private static Map&lt;String, TypeHandler&gt; loadMethodsJava() {
-   *   Map&lt;String, TypeHandler&gt; result = new HashMap&lt;String, TypeHandler&gt;();
+   * private static Map&lt;String, String&gt; loadMethodsJava() {
+   *   Map&lt;String, String&gt; result = new HashMap&lt;String, String&gt;();
    *   result.put(
    *       &quot;java.lang.String/2004016611&quot;,
-   *       new com.google.gwt.user.client.rpc.core.java.lang.String_FieldSerializer.Handler());
+   *       &quot;com.google.gwt.user.client.rpc.core.java.lang.String_FieldSerializer&quot;
    *   ...
    *   return result;
    * }
@@ -333,9 +340,9 @@
    */
   private void writeLoadMethodsJava() {
     srcWriter.println("@SuppressWarnings(\"deprecation\")");
-    srcWriter.println("private static Map<String, TypeHandler> loadMethodsJava() {");
+    srcWriter.println("private static Map<String, String> loadMethodsJava() {");
     srcWriter.indent();
-    srcWriter.println("Map<String, TypeHandler> result = new HashMap<String, TypeHandler>();");
+    srcWriter.println("Map<String, String> result = new HashMap<String, String>();");
 
     List<JType> filteredTypes = new ArrayList<JType>();
     JType[] types = getSerializableTypes();
@@ -352,9 +359,9 @@
       String typeString = typeStrings.get(type);
       assert typeString != null : "Missing type signature for "
           + type.getQualifiedSourceName();
-      srcWriter.println("result.put(\"" + typeString + "\", new "
+      srcWriter.println("result.put(\"" + typeString + "\", \""
           + SerializationUtils.getStandardSerializerName((JClassType) type)
-          + "());");
+          + "\");");
     }
 
     srcWriter.println("return result;");
@@ -381,6 +388,7 @@
    */
   private void writeLoadMethodsNative() {
     srcWriter.println("@SuppressWarnings(\"deprecation\")");
+    srcWriter.println("@GwtScriptOnly");
     srcWriter.println("private static native MethodMap loadMethodsNative() /*-{");
     srcWriter.indent();
     srcWriter.println("var result = {};");
@@ -433,11 +441,11 @@
   }
 
   /**
-   * Writes a method to produce a map of class to type string for Java.
+   * Writes a method to produce a map of class name to type string for Java.
    * 
    * <pre>
-   * private static Map&lt;Class&lt;?&gt;, String&gt; loadSignaturesJava() {
-   *   Map&lt;Class&lt;?&gt;, String&gt; result = new HashMap&lt;Class&lt;?&gt;, String&gt;();
+   * private static Map&lt;String&lt;?&gt;, String&gt; loadSignaturesJava() {
+   *   Map&lt;String&lt;?&gt;, String&gt; result = new HashMap&lt;String&lt;?&gt;, String&gt;();
    *   result.put(
    *       com.google.gwt.user.client.rpc.core.java.lang.String_FieldSerializer.concreteType(),
    *       &quot;java.lang.String/2004016611&quot;);
@@ -448,9 +456,9 @@
    */
   private void writeLoadSignaturesJava() {
     srcWriter.println("@SuppressWarnings(\"deprecation\")");
-    srcWriter.println("private static Map<Class<?>, String> loadSignaturesJava() {");
+    srcWriter.println("private static Map<String, String> loadSignaturesJava() {");
     srcWriter.indent();
-    srcWriter.println("Map<Class<?>, String> result = new HashMap<Class<?>, String>();");
+    srcWriter.println("Map<String, String> result = new HashMap<String, String>();");
 
     for (JType type : getSerializableTypes()) {
       String typeString = typeStrings.get(type);
@@ -466,16 +474,8 @@
       if (customSerializer != null
           && CustomFieldSerializerValidator.getConcreteTypeMethod(customSerializer) != null) {
         typeRef = customSerializer.getQualifiedSourceName() + ".concreteType()";
-      } else if (type instanceof JClassType) {
-        typeRef = SerializationUtils.getStandardSerializerName((JClassType) type)
-            + ".concreteType()";
       } else {
-        typeRef = type.getLeafType().getQualifiedSourceName();
-        while (type.isArray() != null) {
-          typeRef += "[]";
-          type = type.isArray().getComponentType();
-        }
-        typeRef += ".class";
+        typeRef = '"' + SerializationUtils.getRpcTypeName(type) + '"';
       }
 
       srcWriter.println("result.put(" + typeRef + ", \"" + typeString + "\");");
@@ -501,6 +501,7 @@
    */
   private void writeLoadSignaturesNative() {
     srcWriter.println("@SuppressWarnings(\"deprecation\")");
+    srcWriter.println("@GwtScriptOnly");  
     srcWriter.println("private static native JsArrayString loadSignaturesNative() /*-{");
     srcWriter.indent();
     srcWriter.println("var result = [];");
@@ -550,16 +551,16 @@
    * Writes the class's static fields.
    * 
    * <pre>
-   * private static final Map&lt;String, TypeHandler&gt; methodMapJava;
+   * private static final Map&lt;String, String&gt; methodMapJava;
    * private static final MethodMap methodMapNative;
-   * private static final Map&lt;Class&lt;?&gt;, String&gt; signatureMapJava;
+   * private static final Map&lt;String&lt;?&gt;, String&gt; signatureMapJava;
    * private static final JsArrayString signatureMapNative;
    * </pre>
    */
   private void writeStaticFields() {
-    srcWriter.println("private static final Map<String, TypeHandler> methodMapJava;");
+    srcWriter.println("private static final Map<String, String> methodMapJava;");
     srcWriter.println("private static final MethodMap methodMapNative;");
-    srcWriter.println("private static final Map<Class<?>, String> signatureMapJava;");
+    srcWriter.println("private static final Map<String, String> signatureMapJava;");
     srcWriter.println("private static final JsArrayString signatureMapNative;");
     srcWriter.println();
   }
diff --git a/user/super/com/google/gwt/user/translatable/com/google/gwt/user/client/rpc/impl/ReflectionHelper.java b/user/super/com/google/gwt/user/translatable/com/google/gwt/user/client/rpc/impl/ReflectionHelper.java
new file mode 100644
index 0000000..e77b80c
--- /dev/null
+++ b/user/super/com/google/gwt/user/translatable/com/google/gwt/user/client/rpc/impl/ReflectionHelper.java
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+package com.google.gwt.user.client.rpc.impl;
+
+import com.google.gwt.core.client.GwtScriptOnly;
+
+/**
+ * The script-mode equivalent for ReflectionHelper. This version throws
+ * exceptions if used, because ReflectionHelper can only be used from bytecode.
+ */
+@GwtScriptOnly
+public class ReflectionHelper {
+  public static Class<?> loadClass(String name) throws Exception {
+    throw new RuntimeException("ReflectionHelper can't be used from web mode.");
+  }
+
+  public static <T> T newInstance(Class<T> klass)
+      throws Exception {
+    throw new RuntimeException("ReflectionHelper can't be used from web mode.");
+  }
+}