Linux hosted mode now keeps a map of DispatchObjects to the underlying
jsval's. Entries are removed when the jsval is garbage collected. This
change supports stable identity of Java objects in JavaScript.
Patch by: scottb, jat (pair prog)
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2277 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 36f0798..e9d7cb3 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
@@ -154,9 +154,9 @@
protected static native int _getInt(int jsRootedValue);
- protected static native double _getNumber(int jsRootedValue);
+ protected static native int _getJsval(int jsRootedValue);
- protected static native int _getObjectPointer(int jsRootedValue);
+ protected static native double _getNumber(int jsRootedValue);
protected static native String _getString(int jsRootedValue);
@@ -191,6 +191,8 @@
protected static native void _setJsRootedValue(int jsRootedValue,
int jsOtherRootedValue);
+ protected static native void _setJsval(int jsRootedValue, int jsval);
+
protected static native void _setNull(int jsRootedValue);
protected static native void _setString(int jsRootedValue, String val);
@@ -294,7 +296,8 @@
@Override
public int getJavaScriptObjectPointer() {
- return _getObjectPointer(jsRootedValue);
+ assert isJavaScriptObject();
+ return _getJsval(jsRootedValue);
}
/**
@@ -555,7 +558,13 @@
} else {
dispObj = new GeckoDispatchAdapter(cl, val);
}
- _setWrappedJavaObject(jsRootedValue, dispObj);
+ Integer jsval = LowLevelMoz.sObjectToJsval.get(dispObj);
+ if (jsval != null) {
+ _setJsval(jsRootedValue, jsval);
+ } else {
+ _setWrappedJavaObject(jsRootedValue, dispObj);
+ LowLevelMoz.sObjectToJsval.put(dispObj, _getJsval(jsRootedValue));
+ }
}
/**
diff --git a/dev/linux/src/com/google/gwt/dev/shell/moz/LowLevelMoz.java b/dev/linux/src/com/google/gwt/dev/shell/moz/LowLevelMoz.java
index 716a39f..c06b166 100644
--- a/dev/linux/src/com/google/gwt/dev/shell/moz/LowLevelMoz.java
+++ b/dev/linux/src/com/google/gwt/dev/shell/moz/LowLevelMoz.java
@@ -17,6 +17,9 @@
import com.google.gwt.dev.shell.LowLevel;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.Map;
import java.util.Vector;
/**
@@ -76,6 +79,12 @@
boolean gwtOnLoad(int scriptGlobalObject, String moduleName);
}
+ /**
+ * Stores a map from DispatchObject/DispatchMethod to the live underlying jsval. This is used to
+ * both preserve identity for the same Java Object and also prevent GC.
+ */
+ static Map<Object, Integer> sObjectToJsval = Collections.synchronizedMap(new IdentityHashMap<Object, Integer>());
+
private static Vector<ExternalFactory> sExternalFactories = new Vector<ExternalFactory>();
private static boolean sInitialized = false;
@@ -186,6 +195,13 @@
System.out.flush();
}
+ /**
+ * Native code accessor to remove the mapping upon GC.
+ */
+ static void removeJsvalForObject(Object o) {
+ sObjectToJsval.remove(o);
+ }
+
// CHECKSTYLE_NAMING_OFF: Non JSNI native code may have leading '_'s.
private static native boolean _executeScriptWithInfo(int scriptObject,
@@ -220,7 +236,8 @@
* @param jsthis the JS object with the named method
* @param jsargs an array of arguments to the method
*/
- @SuppressWarnings("unused") // kept for future debugging purposes
+ @SuppressWarnings("unused")
+ // kept for future debugging purposes
private static void printInvocationParams(String methodName,
JsValueMoz jsthis, JsValueMoz[] jsargs) {
System.out.println("LowLevelMoz.invoke:");
diff --git a/jni/linux/JsValueMoz.cpp b/jni/linux/JsValueMoz.cpp
index 1faa49f..195306c 100644
--- a/jni/linux/JsValueMoz.cpp
+++ b/jni/linux/JsValueMoz.cpp
@@ -382,18 +382,17 @@
/**
* Class: com_google_gwt_dev_shell_moz_JsValueMoz
- * Method: _getObjectPointer()
+ * Method: _getJsval()
* Signature: (I)I
*/
extern "C" JNIEXPORT jint JNICALL
-Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getObjectPointer
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getJsval
(JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
{
JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
(jsRootedValueInt);
Tracer tracer("JsValueMoz._getObjectPointer", jsRootedValue);
- JSObject* ptr = jsRootedValue->getObject();
- int val = reinterpret_cast<int>(ptr);
+ int val = jsRootedValue->getValue();
tracer.log("value=%d", val);
return val;
}
@@ -733,6 +732,23 @@
}
/*
+ * Set the Javascript value to a specific jsval.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setJsval()
+ * Signature: (II)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setJsval
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jint jsval)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._setJsval", jsRootedValue);
+ jsRootedValue->setValue(jsval);
+}
+
+/*
* Set the JavaScript value to be null.
*
* Class: com_google_gwt_dev_shell_moz_JsValueMoz
@@ -821,7 +837,7 @@
jsRootedValue->setObject(newObj);
tracer.log("jsobject=%08x", unsigned(newObj));
- // TODO(jat): how does this globalref get freed?
+ // This is collected when the gwt_nativewrapper_class destructor runs.
jobject dispObjRef = jniEnv->NewGlobalRef(obj);
if (!dispObjRef || jniEnv->ExceptionCheck()) {
tracer.throwHostedModeException(jniEnv,
diff --git a/jni/linux/NativeWrapper.cpp b/jni/linux/NativeWrapper.cpp
index be3963e..c017fd7 100644
--- a/jni/linux/NativeWrapper.cpp
+++ b/jni/linux/NativeWrapper.cpp
@@ -158,9 +158,23 @@
static void JS_DLL_CALLBACK gwt_nativewrapper_finalize(JSContext *cx,
JSObject *obj)
{
+ Tracer tracer("gwt_nativewrapper_finalize");
jobject dispObj = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
- if (dispObj)
+ if (dispObj) {
+ // Remove this pairing from the global map.
+ jmethodID removeMethod = savedJNIEnv->GetStaticMethodID(lowLevelMozClass, "removeJsvalForObject",
+ "(Ljava/lang/Object;)V");
+ if (!removeMethod || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("Cannot GetMethodID for removeJsvalForObject");
+ return;
+ }
+ savedJNIEnv->CallStaticVoidMethod(lowLevelMozClass, removeMethod, dispObj);
+ if (savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("Exception calling removeJsvalForObject");
+ return;
+ }
savedJNIEnv->DeleteGlobalRef(dispObj);
+ }
}
static JSBool JS_DLL_CALLBACK gwt_nativewrapper_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
diff --git a/jni/linux/prebuilt/libgwt-ll.so b/jni/linux/prebuilt/libgwt-ll.so
index e941084..33af9c7 100755
--- a/jni/linux/prebuilt/libgwt-ll.so
+++ b/jni/linux/prebuilt/libgwt-ll.so
Binary files differ