In JsValueMoz, Conditionalizes debug code on a private static final flag, to eliminate run-time overhead.  Also includes a refactoring to move all debug-related code into a private inner class.

Patch by: jat (+me)
Review by: me


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@886 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/linux/src/com/google/gwt/dev/shell/moz/JsValueMoz.java b/dev/linux/src/com/google/gwt/dev/shell/moz/JsValueMoz.java
index d8456f0..81e9735 100644
--- a/dev/linux/src/com/google/gwt/dev/shell/moz/JsValueMoz.java
+++ b/dev/linux/src/com/google/gwt/dev/shell/moz/JsValueMoz.java
@@ -32,6 +32,95 @@
  * sizeof(void*)=4
  */
 public class JsValueMoz extends JsValue {
+
+  /**
+   * Records debug information, only used when {@link JsValueMoz#debugFlag} is
+   * <code>true</code>.
+   */
+  private static class DebugLogging {
+    private Map alreadyCleanedJsRootedValues = Collections.synchronizedMap(new HashMap());
+    private int maxActive = 0;
+    private int numActive = 0;
+    private Map seenJsRootedValues = Collections.synchronizedMap(new HashMap());
+    private int totAlloc = 0;
+
+    /**
+     * Count a JsValueMoz instance being created.
+     * 
+     * Verify that the underlying JsRootedValue is not currently active, and
+     * mark that it is active.
+     * 
+     * This is debug code that is only executed if debugFlag is true. Since this
+     * is a private static final field, the compiler should optimize out all
+     * this code. It is useful to have for tracking down problems, so it is
+     * being left in but disabled.
+     */
+    public void createInstance(int jsRootedValue) {
+      Integer jsrv = new Integer(jsRootedValue);
+      if (seenJsRootedValues.containsKey(jsrv)) {
+        Throwable t = (Throwable) seenJsRootedValues.get(jsrv);
+        String msg = hexString(jsRootedValue);
+        System.err.println(msg + ", original caller stacktrace:");
+        t.printStackTrace();
+        throw new RuntimeException(msg);
+      }
+      Throwable t = new Throwable();
+      seenJsRootedValues.put(jsrv, t);
+      if (alreadyCleanedJsRootedValues.containsKey(jsrv)) {
+        alreadyCleanedJsRootedValues.remove(jsrv);
+      }
+      if (++numActive > maxActive) {
+        maxActive = numActive;
+      }
+      ++totAlloc;
+    }
+
+    /**
+     * Count a JsValueMoz instance being destroyed.
+     * 
+     * Verify that this instance hasn't already been destroyed, that it has
+     * previously been created, and that the underlying JsRootedValue is only
+     * being cleaned once.
+     * 
+     * This is debug code that is only executed if debugFlag is true. Since this
+     * is a private static final field, the compiler should optimize out all
+     * this code. It is useful to have for tracking down problems, so it is
+     * being left in but disabled.
+     */
+    public void destroyInstance(int jsRootedValue) {
+      if (jsRootedValue == 0) {
+        throw new RuntimeException("Cleaning already-cleaned JsValueMoz");
+      }
+      Integer jsrv = new Integer(jsRootedValue);
+      if (!seenJsRootedValues.containsKey(jsrv)) {
+        throw new RuntimeException("cleaning up 0x" + hexString(jsRootedValue)
+            + ", not active");
+      }
+      if (alreadyCleanedJsRootedValues.containsKey(jsrv)) {
+        Throwable t = (Throwable) seenJsRootedValues.get(jsrv);
+        String msg = "Already cleaned 0x" + hexString(jsRootedValue);
+        System.err.println(msg + ", original allocator stacktrace:");
+        t.printStackTrace();
+        throw new RuntimeException(msg);
+      }
+      Throwable t = new Throwable();
+      alreadyCleanedJsRootedValues.put(jsrv, t);
+      seenJsRootedValues.remove(jsrv);
+      --numActive;
+    }
+
+    /**
+     * Print collected statistics on JsValueMoz usage.
+     */
+    public void dumpStatistics() {
+      System.gc();
+      System.out.println("JsValueMoz usage:");
+      System.out.println(" " + totAlloc + " total instances created");
+      System.out.println(" " + maxActive + " at any one time");
+      System.out.println(" " + seenJsRootedValues.size() + " uncleaned entries");
+    }
+  }
+
   private static class JsCleanupMoz implements JsCleanup {
     private final int jsRootedValue;
 
@@ -45,19 +134,20 @@
   }
 
   /**
-   * This must match the value from jsapi.h
+   * Flag to enable debug checks on underlying JsRootedValues.
+   */
+  private static final boolean debugFlag = false;
+
+  /**
+   * Flag to enable debug checks on underlying JsRootedValues.
+   */
+  private static final DebugLogging debugInfo = debugFlag ? new DebugLogging() : null;
+
+  /**
+   * This must match the value from jsapi.h.
    */
   private static final int JSVAL_VOID = 0x80000001;
 
-  // TODO(jat): remove debugging code before 1.4 final
-  private static Map alreadyCleanedJsRootedValues
-      = Collections.synchronizedMap(new HashMap());
-  private static int maxActive = 0;
-  private static int numActive = 0;
-  private static Map seenJsRootedValues 
-      = Collections.synchronizedMap(new HashMap());
-  private static int totAlloc = 0;
-
   /**
    * Create a new undefined JavaScript value.
    * 
@@ -68,17 +158,6 @@
     return new JsValueMoz(scriptObject, JSVAL_VOID);
   }
 
-  /**
-   * Print collected statistics on JsValueMoz usage.
-   */
-  public static void dumpStatistics() {
-    System.gc();
-    System.out.println("JsValueMoz usage:");
-    System.out.println(" " + totAlloc + " total instances created");
-    System.out.println(" " + maxActive + " at any one time");
-    System.out.println(" " + seenJsRootedValues.size() + " uncleaned entries");
-  }
-
   // CHECKSTYLE_NAMING_OFF -- native methods start with '_'
   protected static native boolean _getBoolean(int jsRootedValue);
 
@@ -160,6 +239,18 @@
     _destroyJsRootedValue(jsRootedValue);
   }
 
+  /**
+   * Convert an address to a hex string.
+   * 
+   * @param jsRootedValue underlying JavaScript value as an opaque integer
+   * @return a string with the JavaScript value represented as hex
+   */
+  private static String hexString(int jsRootedValue) {
+    long l = jsRootedValue;
+    l = l & 0xffffffffL;
+    return Long.toHexString(l);
+  }
+
   // pointer to underlying JsRootedValue object as an integer
   private int jsRootedValue;
 
@@ -171,7 +262,9 @@
    */
   public JsValueMoz(int jsRootedValue) {
     this.jsRootedValue = jsRootedValue;
-    createInstance();
+    if (debugFlag) {
+      debugInfo.createInstance(jsRootedValue);
+    }
   }
 
   /**
@@ -181,11 +274,14 @@
    */
   public JsValueMoz(JsValueMoz other) {
     jsRootedValue = _copyJsRootedValue(other.jsRootedValue);
-    createInstance();
+    if (debugFlag) {
+      debugInfo.createInstance(jsRootedValue);
+    }
   }
-  
+
   /**
    * Create a JsValue object with the JavaScript value jsval.
+   * 
    * Only used internally.
    * 
    * @param scriptObject reference to containing window object in JavaScript
@@ -193,7 +289,9 @@
    */
   protected JsValueMoz(int scriptObject, int jsval) {
     jsRootedValue = _createJsRootedValue(scriptObject, jsval);
-    createInstance();
+    if (debugFlag) {
+      debugInfo.createInstance(jsRootedValue);
+    }
   }
 
   /*
@@ -459,78 +557,15 @@
   }
 
   /**
-   * create a cleanup object that will free the underlying JsRootedValue object.
+   * Create a cleanup object that will free the underlying JsRootedValue object.
    */
   protected JsCleanup createCleanupObject() {
     JsCleanup cleanup = new JsCleanupMoz(jsRootedValue);
-    destroyInstance();
+    if (debugFlag) {
+      debugInfo.destroyInstance(jsRootedValue);
+      jsRootedValue = 0;
+    }
     return cleanup;
   }
 
-  /**
-   * Count a JsValueMoz instance being created.
-   */
-  protected void createInstance() {
-    // TODO(jat): remove this debug code before 1.4 final
-    Integer jsrv = new Integer(jsRootedValue);
-    if (seenJsRootedValues.containsKey(jsrv)) {
-      Throwable t = (Throwable) seenJsRootedValues.get(jsrv);
-      String msg = hexString(jsRootedValue);
-      System.err.println(msg + ", original caller stacktrace:");
-      t.printStackTrace();
-      throw new RuntimeException(msg);
-    }
-    Throwable t = new Throwable();
-    t.fillInStackTrace();
-    seenJsRootedValues.put(jsrv, t);
-    if (alreadyCleanedJsRootedValues.containsKey(jsrv)) {
-      alreadyCleanedJsRootedValues.remove(jsrv);
-    }
-    if (++numActive > maxActive) {
-      maxActive = numActive;
-    }
-    ++totAlloc;
-  }
-
-  /**
-   * Count a JsValueMoz instance being destroyed.
-   */
-  protected void destroyInstance() {
-    // TODO(jat): remove this debug code before 1.4 final
-    if (jsRootedValue == 0) {
-      throw new RuntimeException("Cleaning already-cleaned JsValueMoz");
-    }
-    Integer jsrv = new Integer(jsRootedValue);
-    if (!seenJsRootedValues.containsKey(jsrv)) {
-      throw new RuntimeException("cleaning up 0x" + hexString(jsRootedValue)
-          + ", not active");
-    }
-    if (alreadyCleanedJsRootedValues.containsKey(jsrv)) {
-      Throwable t = (Throwable) seenJsRootedValues.get(jsrv);
-      String msg = "Already cleaned 0x" + hexString(jsRootedValue);
-      System.err.println(msg + ", original allocator stacktrace:");
-      t.printStackTrace();
-      throw new RuntimeException(msg);
-    }
-    Throwable t = new Throwable();
-    t.fillInStackTrace();
-    alreadyCleanedJsRootedValues.put(jsrv, t);
-    seenJsRootedValues.remove(jsrv);
-    jsRootedValue = 0;
-    --numActive;
-  }
-
-  /**
-   * Convert an address to a hex string.
-   * TODO(jat): remove this method
-   * 
-   * @param jsRootedValue underlying JavaScript value as an opaque integer
-   * @return a string with the JavaScript value represented as hex
-   */
-  private String hexString(int jsRootedValue) {
-    long l = jsRootedValue;
-    l = l & 0xffffffffL;
-    return Long.toHexString(l);
-  }
-
 }