Revision: 10367
Author:   b...@google.com
Date:     Fri Jun 17 04:22:15 2011
Log:      Integrate r10344 into GWT 2.4 branch.

http://code.google.com/p/google-web-toolkit/source/detail?r=10367

Modified:
 /releases/2.4/user/src/com/google/gwt/core/client/impl/WeakMapping.java
/releases/2.4/user/src/com/google/web/bindery/autobean/shared/impl/AbstractAutoBean.java /releases/2.4/user/src/com/google/web/bindery/autobean/vm/impl/JsonSplittable.java /releases/2.4/user/src/com/google/web/bindery/autobean/vm/impl/ProxyAutoBean.java /releases/2.4/user/super/com/google/gwt/core/translatable/com/google/gwt/core/client/impl/WeakMapping.java

=======================================
--- /releases/2.4/user/src/com/google/gwt/core/client/impl/WeakMapping.java Thu Dec 16 11:33:51 2010 +++ /releases/2.4/user/src/com/google/gwt/core/client/impl/WeakMapping.java Fri Jun 17 04:22:15 2011
@@ -18,8 +18,10 @@
 import java.lang.ref.Reference;
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.WeakReference;
-import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;

 /**
  * A class associating a (String, Object) map with arbitrary source objects
@@ -87,13 +89,26 @@
       return hashCode;
     }
   }
+
+  private static class ManagedWeakReference<T> extends WeakReference<T> {
+    public ManagedWeakReference(T object) {
+      super(object);
+    }
+  }
+
+  /**
+ * Provides synchronization around {@link #queue} so at most one thread is
+   * cleaning at any given time.
+   */
+  private static final Lock cleanupLock = new ReentrantLock();

   /**
    * A Map from Objects to <String,Object> maps. Hashing is based on object
* identity. Weak references are used to allow otherwise unreferenced Objects
    * to be garbage collected.
    */
- private static Map<IdentityWeakReference, Map<String, Object>> map = new HashMap<IdentityWeakReference, Map<String, Object>>(); + private static final ConcurrentHashMap<IdentityWeakReference, Map<String, Object>> map =
+      new ConcurrentHashMap<IdentityWeakReference, Map<String, Object>>();

   /**
    * A ReferenceQueue used to clean up the map as its keys are
@@ -109,15 +124,18 @@
    * @param key a String key.
* @return an Object associated with that key on the given instance, or null.
    */
-  public static synchronized Object get(Object instance, String key) {
+  public static Object get(Object instance, String key) {
     cleanup();
-
     Object ref = new IdentityWeakReference(instance, queue);
     Map<String, Object> m = map.get(ref);
     if (m == null) {
       return null;
     }
-    return m.get(key);
+    Object toReturn = m.get(key);
+    if (toReturn instanceof ManagedWeakReference) {
+      toReturn = ((ManagedWeakReference<?>) toReturn).get();
+    }
+    return toReturn;
   }

   /**
@@ -128,16 +146,15 @@
    * <p>
* Due to restrictions of the Production Mode implementation, the instance
    * argument must not be a String.
-   *
+   *
    * @param instance the source Object, which must not be a String.
    * @param key a String key.
    * @param value the Object to associate with the key on the given source
    *          Object.
    * @throws IllegalArgumentException if instance is a String.
    */
- public static synchronized void set(Object instance, String key, Object value) {
+  public static void set(Object instance, String key, Object value) {
     cleanup();
-
     if (instance instanceof String) {
throw new IllegalArgumentException("Cannot use Strings with WeakMapping");
     }
@@ -145,10 +162,23 @@
     IdentityWeakReference ref = new IdentityWeakReference(instance, queue);
     Map<String, Object> m = map.get(ref);
     if (m == null) {
-      m = new HashMap<String, Object>();
-      map.put(ref, m);
-    }
-    m.put(key, value);
+      m = new ConcurrentHashMap<String, Object>();
+      map.putIfAbsent(ref, m);
+      m = map.get(ref);
+    }
+    if (value == null) {
+      m.remove(key);
+    } else {
+      m.put(key, value);
+    }
+  }
+
+  /**
+   * Like {@link #set(Object, String, Object)}, but doesn't guarantee that
+   * {@code value} can be retrieved.
+   */
+  public static void setWeak(Object instance, String key, Object value) {
+    set(instance, key, new ManagedWeakReference<Object>(value));
   }

   /**
@@ -157,13 +187,16 @@
    * will be eligible for future garbage collection.
    */
   private static void cleanup() {
-    Reference<? extends Object> ref;
-    while ((ref = queue.poll()) != null) {
-      /**
- * Note that we can still remove ref from the map even though its referent
-       * has been nulled out since we only need == equality to do so.
-       */
-      map.remove(ref);
+    if (cleanupLock.tryLock()) {
+      Reference<? extends Object> ref;
+      while ((ref = queue.poll()) != null) {
+        /**
+         * Note that we can still remove ref from the map even though its
+ * referent has been nulled out since we only need == equality to do so.
+         */
+        map.remove(ref);
+      }
+      cleanupLock.unlock();
     }
   }
 }
=======================================
--- /releases/2.4/user/src/com/google/web/bindery/autobean/shared/impl/AbstractAutoBean.java Mon Apr 18 02:42:06 2011 +++ /releases/2.4/user/src/com/google/web/bindery/autobean/shared/impl/AbstractAutoBean.java Fri Jun 17 04:22:15 2011
@@ -15,6 +15,7 @@
  */
 package com.google.web.bindery.autobean.shared.impl;

+import com.google.gwt.core.client.impl.WeakMapping;
 import com.google.web.bindery.autobean.shared.AutoBean;
 import com.google.web.bindery.autobean.shared.AutoBeanFactory;
 import com.google.web.bindery.autobean.shared.AutoBeanUtils;
@@ -23,7 +24,6 @@
 import com.google.web.bindery.autobean.shared.Splittable;
 import com.google.web.bindery.autobean.shared.impl.AutoBeanCodexImpl.Coder;
import com.google.web.bindery.autobean.shared.impl.AutoBeanCodexImpl.EncodeState;
-import com.google.gwt.core.client.impl.WeakMapping;

 import java.util.HashMap;
 import java.util.HashSet;
@@ -94,7 +94,7 @@
     this.wrapped = wrapped;

     // Used by AutoBeanUtils
-    WeakMapping.set(wrapped, AutoBean.class.getName(), this);
+    WeakMapping.setWeak(wrapped, AutoBean.class.getName(), this);
   }

   public void accept(AutoBeanVisitor visitor) {
=======================================
--- /releases/2.4/user/src/com/google/web/bindery/autobean/vm/impl/JsonSplittable.java Wed Jun 1 06:50:18 2011 +++ /releases/2.4/user/src/com/google/web/bindery/autobean/vm/impl/JsonSplittable.java Fri Jun 17 04:22:15 2011
@@ -306,10 +306,10 @@
     if (seen == null) {
       if (object instanceof JSONObject) {
         seen = new JsonSplittable((JSONObject) object);
-        WeakMapping.set(object, JsonSplittable.class.getName(), seen);
+        WeakMapping.setWeak(object, JsonSplittable.class.getName(), seen);
       } else if (object instanceof JSONArray) {
         seen = new JsonSplittable((JSONArray) object);
-        WeakMapping.set(object, JsonSplittable.class.getName(), seen);
+        WeakMapping.setWeak(object, JsonSplittable.class.getName(), seen);
       } else if (object instanceof String) {
         seen = new JsonSplittable(object.toString());
       } else if (object instanceof Number) {
=======================================
--- /releases/2.4/user/src/com/google/web/bindery/autobean/vm/impl/ProxyAutoBean.java Fri May 20 08:39:14 2011 +++ /releases/2.4/user/src/com/google/web/bindery/autobean/vm/impl/ProxyAutoBean.java Fri Jun 17 04:22:15 2011
@@ -124,16 +124,23 @@
    * ok if it's deallocated, since it has no interesting state.
    *
    * <pre>
-   *
-   * -----------------        --------------
-   * | ProxyAutoBean |        |    Shim    |
-   * |               | <------+-bean       |
-   * |          shim-+---X--->|____________|
-   * |_______________|              ^
-   *         ^                      |
-   *         |                      X
-   *         |______ WeakMapping ___|
+   * _________________            ______________
+   * | ProxyAutoBean |            |    Shim    |
+   * |               | <----------+-bean       |
+   * |          shim-+---X------> |            |
+   * |_______________|            |____________|
+   *         ^                           ^  ^
+   *         X                           X  |
+   *         |__value__WeakMapping__key__|  |
+   *                      ^                 |
+   *                      |                 |
+   *                   GC Roots -> Owner____|
    * </pre>
+   * <p>
+   * In the case of a wrapped object (for example, an ArrayList), the weak
+ * reference from WeakMapping to the ProxyAutoBean may cause the AutoBean to + * be prematurely collected if neither the bean nor the shim are referenced
+   * elsewhere. The alternative is a massive memory leak.
    */
   private WeakReference<T> shim;

@@ -332,7 +339,7 @@

   private T createShim() {
T toReturn = ProxyAutoBean.makeProxy(beanType, new ShimHandler<T>(this, getWrapped()));
-    WeakMapping.set(toReturn, AutoBean.class.getName(), this);
+    WeakMapping.setWeak(toReturn, AutoBean.class.getName(), this);
     return toReturn;
   }
 }
=======================================
--- /releases/2.4/user/super/com/google/gwt/core/translatable/com/google/gwt/core/client/impl/WeakMapping.java Wed Oct 28 09:10:53 2009 +++ /releases/2.4/user/super/com/google/gwt/core/translatable/com/google/gwt/core/client/impl/WeakMapping.java Fri Jun 17 04:22:15 2011
@@ -58,6 +58,10 @@
assert !(instance instanceof String) : "Cannot use Strings with WeakMapping";
     setNative(instance, key, value);
   }
+
+  public static void setWeak(Object instance, String key, Object value) {
+    set(instance, key, value);
+  }

private static native void setNative(Object instance, String key, Object value) /*-{
     if (!instan...@java.lang.Object::expando) {

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to