Guard against invalid dispIds in JavaDispatchImpl

Also, rather than write an invalid dispId and wait for things to blow up, throw
a HostedModeException if we hit a JSNI ref that shouldn't be there

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

Review by: scottb@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9390 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/shell/JavaDispatchImpl.java b/dev/core/src/com/google/gwt/dev/shell/JavaDispatchImpl.java
index 2323597..9338a85 100644
--- a/dev/core/src/com/google/gwt/dev/shell/JavaDispatchImpl.java
+++ b/dev/core/src/com/google/gwt/dev/shell/JavaDispatchImpl.java
@@ -61,6 +61,9 @@
    * @return the field
    */
   public Field getField(int dispId) {
+    if (dispId < 0) {
+      throw new RuntimeException("Field does not exist.");
+    }
     Member member = getMember(dispId);
 
     if (member instanceof SyntheticClassMember) {
@@ -82,6 +85,10 @@
    * @throws IllegalArgumentException
    */
   public Object getFieldValue(int dispId) {
+    if (dispId < 0) {
+      throw new RuntimeException("Field does not exist.");
+    }
+    
     Member member = getMember(dispId);
 
     if (member instanceof SyntheticClassMember) {
@@ -103,6 +110,10 @@
    * @return the method
    */
   public MethodAdaptor getMethod(int dispId) {
+    if (dispId < 0) {
+      throw new RuntimeException("Method does not exist.");
+    }
+    
     Member m = getMember(dispId);
     if (m instanceof Method) {
       return new MethodAdaptor((Method) m);
diff --git a/dev/core/src/com/google/gwt/dev/shell/Jsni.java b/dev/core/src/com/google/gwt/dev/shell/Jsni.java
index 2533cd7..19bd33d 100644
--- a/dev/core/src/com/google/gwt/dev/shell/Jsni.java
+++ b/dev/core/src/com/google/gwt/dev/shell/Jsni.java
@@ -106,13 +106,18 @@
 
         Member member;
         if (dispId < 0) {
-          // We've already emitted a warning from getDispId; just fake the jsni
           member = null;
         } else {
           member = dispatchInfo.getClassInfoByDispId(dispId).getMember(dispId);
         }
+        
+        if (member == null) {
+          throw new HostedModeException(
+              "JSNI rewriter found reference to non-existent field in a field reference or java method tear-off: "
+                  + ident + " at " + x.getSourceInfo());
+        }
 
-        if (member == null || member instanceof Field
+        if (member instanceof Field
             || member instanceof SyntheticClassMember) {
           if (q != null) {
             accept(q);
@@ -176,18 +181,21 @@
             member = dispatchInfo.getClassInfoByDispId(dispId).getMember(dispId);
           }
 
+          if (member == null) {
+            throw new HostedModeException(
+                "JSNI rewriter found reference to non-existent field in a method invocation: "
+                    + ref.getIdent() + " at " + ref.getSourceInfo());
+          }
+          
           /*
            * Make sure the ident is a reference to a method or constructor and
            * not a reference to a field whose contents (e.g. a Function) we
            * intend to immediately invoke.
            * 
            * p.C::method()(); versus p.C::field();
-           * 
-           * Also, if the reference was to a non-existent field, we'll go ahead
-           * and rewrite the call site as though -1 is a valid dispid.
+           *
            */
-          if (member == null || member instanceof Method
-              || member instanceof Constructor<?>) {
+          if (member instanceof Method || member instanceof Constructor<?>) {
 
             // Use a clone instead of modifying the original JSNI
             // __gwt_makeJavaInvoke(paramCount)(obj, dispId, args)
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 a3336ef..121ab51 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
@@ -60,16 +60,12 @@
       Object[] array;
       if (GWT.isScript()) {
         // Violator pattern.
-        array = getArray0(instance);
+        array = ArraysViolator.getArray0(instance);
       } else {
         // Clone the underlying array.
         array = instance.toArray();
       }
       streamWriter.writeObject(array);
     }
-
-    private static native Object[] getArray0(List<?> instance) /*-{
-      return instance.@java.util.Arrays$ArrayList::array;
-    }-*/;
   }
 }
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/util/ArraysViolator.java b/user/src/com/google/gwt/user/client/rpc/core/java/util/ArraysViolator.java
new file mode 100644
index 0000000..350bd57
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/rpc/core/java/util/ArraysViolator.java
@@ -0,0 +1,28 @@
+/*
+ * 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.core.java.util;
+
+import java.util.List;
+
+/**
+ * Used to delay referencing methods only present in the emulated JRE until they
+ * are actually used.
+ */
+public class ArraysViolator {
+  public static native Object[] getArray0(List<?> instance) /*-{
+    return instance.@java.util.Arrays$ArrayList::array;
+  }-*/;
+}
diff --git a/user/super/com/google/gwt/emul/java/util/Random.java b/user/super/com/google/gwt/emul/java/util/Random.java
index 0ded4c2..3605535 100644
--- a/user/super/com/google/gwt/emul/java/util/Random.java
+++ b/user/super/com/google/gwt/emul/java/util/Random.java
@@ -34,14 +34,14 @@
  */
 package java.util;
 
-import java.io.Serializable;
-
 /**
  * This class provides methods that generates pseudo-random numbers of different
  * types, such as {@code int}, {@code long}, {@code double}, and {@code float}.
  * It follows the algorithms specified in the JRE javadoc.
+ * 
+ * This emulated version of Random is not serializable.
  */
-public class Random implements Serializable {
+public class Random {
 
   private static final double multiplierHi = 0x5de;
   private static final double multiplierLo = 0xece66d;
@@ -90,29 +90,21 @@
 
   /**
    * The boolean value indicating if the second Gaussian number is available.
-   * 
-   * @serial
    */
   private boolean haveNextNextGaussian = false;
 
   /**
    * The second Gaussian generated number.
-   * 
-   * @serial
    */
   private double nextNextGaussian;
   
   /**
    * The high 24 bits of the 48=bit seed value.
-   * 
-   * @serial It is associated with the internal state of this generator.
    */
   private double seedhi;
 
   /**
    * The low 24 bits of the 48=bit seed value.
-   * 
-   * @serial It is associated with the internal state of this generator.
    */
   private double seedlo;
   
diff --git a/user/test/com/google/gwt/emultest/java/math/BigIntegerConstructorsTest.java b/user/test/com/google/gwt/emultest/java/math/BigIntegerConstructorsTest.java
index 6909741..a3f77aa 100644
--- a/user/test/com/google/gwt/emultest/java/math/BigIntegerConstructorsTest.java
+++ b/user/test/com/google/gwt/emultest/java/math/BigIntegerConstructorsTest.java
@@ -786,29 +786,25 @@
       // JRE implementation doesn't have the method tested here
       return;
     }
-    BigInteger val = fromDouble(1.0);
+    BigInteger val = BigIntegerViolator.fromDouble(1.0);
     assertEquals("1", val.toString());
-    val = fromDouble(100.0);
+    val = BigIntegerViolator.fromDouble(100.0);
     assertEquals("100", val.toString());
-    val = fromDouble(2147483647.0);
+    val = BigIntegerViolator.fromDouble(2147483647.0);
     assertEquals("2147483647", val.toString());
-    val = fromDouble(-2147483647.0);
+    val = BigIntegerViolator.fromDouble(-2147483647.0);
     assertEquals("-2147483647", val.toString());
-    val = fromDouble(2147483648.0);
+    val = BigIntegerViolator.fromDouble(2147483648.0);
     assertEquals("2147483648", val.toString());
-    val = fromDouble(-2147483648.0);
+    val = BigIntegerViolator.fromDouble(-2147483648.0);
     assertEquals("-2147483648", val.toString());
-    val = fromDouble(4294967295.0);
+    val = BigIntegerViolator.fromDouble(4294967295.0);
     assertEquals("4294967295", val.toString());
-    val = fromDouble(-4294967295.0);
+    val = BigIntegerViolator.fromDouble(-4294967295.0);
     assertEquals("-4294967295", val.toString());
-    val = fromDouble(4294967296.0);
+    val = BigIntegerViolator.fromDouble(4294967296.0);
     assertEquals("4294967296", val.toString());
-    val = fromDouble(-4294967296.0);
+    val = BigIntegerViolator.fromDouble(-4294967296.0);
     assertEquals("-4294967296", val.toString());
   }
-
-  private native BigInteger fromDouble(double v) /*-{
-    return @java.math.BigInteger::valueOf(D)(v);
-  }-*/;
 }
diff --git a/user/test/com/google/gwt/emultest/java/math/BigIntegerViolator.java b/user/test/com/google/gwt/emultest/java/math/BigIntegerViolator.java
new file mode 100644
index 0000000..81edf89
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigIntegerViolator.java
@@ -0,0 +1,29 @@
+/*
+ * 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.emultest.java.math;
+
+import java.math.BigInteger;
+
+/**
+ * Used to delay referencing methods only present in the emulated JRE until they
+ * are actually used.
+ */
+public class BigIntegerViolator {
+  
+  public static native BigInteger fromDouble(double v) /*-{
+    return @java.math.BigInteger::valueOf(D)(v);
+  }-*/;
+}
\ No newline at end of file
diff --git a/user/test/com/google/gwt/emultest/java/util/TreeMapTest.java b/user/test/com/google/gwt/emultest/java/util/TreeMapTest.java
index 07251c9..37cd46d 100644
--- a/user/test/com/google/gwt/emultest/java/util/TreeMapTest.java
+++ b/user/test/com/google/gwt/emultest/java/util/TreeMapTest.java
@@ -136,12 +136,6 @@
     assertEquals(expected.values().toArray(), actual.values().toArray());
   }
 
-  // Use JSNI to call a special method on our implementation of TreeMap.
-  @SuppressWarnings("unchecked") // raw Map
-  private static native void callAssertCorrectness(Map map) /*-{
-    map.@java.util.TreeMap::assertCorrectness()();
-  }-*/;
-
   /**
    * Create the expected return of toString for a Map containing only the passed
    * key and value.
@@ -1868,7 +1862,7 @@
   protected void verifyMap() {
     if (GWT.isScript()) {
       // Verify red-black correctness in our implementation
-      callAssertCorrectness(map);
+      TreeMapViolator.callAssertCorrectness(map);
     }
     super.verifyMap();
   }
diff --git a/user/test/com/google/gwt/emultest/java/util/TreeMapViolator.java b/user/test/com/google/gwt/emultest/java/util/TreeMapViolator.java
new file mode 100644
index 0000000..d2de931
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/util/TreeMapViolator.java
@@ -0,0 +1,30 @@
+/*
+ * 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.emultest.java.util;
+
+import java.util.Map;
+
+/**
+ * Used to delay referencing methods only present in the emulated JRE until they
+ * are actually used.
+ */
+public class TreeMapViolator {
+  // Use JSNI to call a special method on our implementation of TreeMap.
+  @SuppressWarnings("unchecked") // raw Map
+  public static native void callAssertCorrectness(Map map) /*-{
+    map.@java.util.TreeMap::assertCorrectness()();
+  }-*/;
+}