Fix AutoBean VM memory leak due to circular references between the
ProxyAutoBean, ShimHandler, and WeakReference.
Issue 6193.
http://gwt-code-reviews.appspot.com/1448803
Patch by: bobv
Review by: tbroyer, rjrjr


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10201 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/web/bindery/autobean/vm/impl/ProxyAutoBean.java b/user/src/com/google/web/bindery/autobean/vm/impl/ProxyAutoBean.java
index cdf61dc..d52579d 100644
--- a/user/src/com/google/web/bindery/autobean/vm/impl/ProxyAutoBean.java
+++ b/user/src/com/google/web/bindery/autobean/vm/impl/ProxyAutoBean.java
@@ -15,14 +15,15 @@
  */
 package com.google.web.bindery.autobean.vm.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;
 import com.google.web.bindery.autobean.shared.AutoBeanVisitor;
 import com.google.web.bindery.autobean.shared.impl.AbstractAutoBean;
 import com.google.web.bindery.autobean.vm.Configuration;
-import com.google.gwt.core.client.impl.WeakMapping;
 
+import java.lang.ref.WeakReference;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -66,7 +67,7 @@
       Class<?>... extraInterfaces) {
     Class<?>[] intfs;
     if (extraInterfaces == null) {
-      intfs = new Class<?>[]{intf};
+      intfs = new Class<?>[] {intf};
     } else {
       intfs = new Class<?>[extraInterfaces.length + 1];
       intfs[0] = intf;
@@ -116,7 +117,25 @@
   private final Class<T> beanType;
   private final Configuration configuration;
   private final Data data;
-  private final T shim;
+  /**
+   * Because the shim and the ProxyAutoBean are related through WeakMapping, we
+   * need to ensure that the ProxyAutoBean doesn't artificially extend the
+   * lifetime of the shim. If there are no external references to the shim, it's
+   * ok if it's deallocated, since it has no interesting state.
+   * 
+   * <pre>
+   * 
+   * -----------------        --------------
+   * | ProxyAutoBean |        |    Shim    |
+   * |               | <------+-bean       |
+   * |          shim-+---X--->|____________|
+   * |_______________|              ^
+   *         ^                      |
+   *         |                      X
+   *         |______ WeakMapping ___|
+   * </pre>
+   */
+  private WeakReference<T> shim;
 
   // These constructors mirror the generated constructors.
   @SuppressWarnings("unchecked")
@@ -125,7 +144,6 @@
     this.beanType = (Class<T>) beanType;
     this.configuration = configuration;
     this.data = calculateData(beanType);
-    this.shim = createShim();
   }
 
   @SuppressWarnings("unchecked")
@@ -135,12 +153,16 @@
     this.beanType = (Class<T>) beanType;
     this.configuration = configuration;
     this.data = calculateData(beanType);
-    this.shim = createShim();
   }
 
   @Override
   public T as() {
-    return shim;
+    T toReturn = shim == null ? null : shim.get();
+    if (toReturn == null) {
+      toReturn = createShim();
+      shim = new WeakReference<T>(toReturn);
+    }
+    return toReturn;
   }
 
   public Configuration getConfiguration() {
@@ -241,7 +263,7 @@
       Object value;
       try {
         getter.setAccessible(true);
-        value = getter.invoke(shim);
+        value = getter.invoke(as());
       } catch (IllegalArgumentException e) {
         throw new RuntimeException(e);
       } catch (IllegalAccessException e) {