Add back IE proxy handling for CheckForUpdates.
Also remove branch-info.txt inadvertently committed to trunk.

Patch by: scottb
Review by: jat


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6390 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/jni/linux/JsValueMoz.cpp b/jni/linux/JsValueMoz.cpp
new file mode 100644
index 0000000..195306c
--- /dev/null
+++ b/jni/linux/JsValueMoz.cpp
@@ -0,0 +1,993 @@
+/*
+ * Copyright 2007 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.
+ */
+
+#include <jni.h>
+#include "JsRootedValue.h"
+#include "gwt-jni.h"
+#include "ExternalWrapper.h"
+#include "Tracer.h"
+
+// include javah-generated header to make sure things match
+#include "JsValueMoz.h"
+
+/*
+ * Returns the value of a field on a Java object.
+ * 
+ * context - JavaScript context
+ * clazz - class of obj
+ * obj - Java object to retreive field from
+ * fieldName - name of field on Java object to retrieve
+ * 
+ * Returns null on failure.  Caller is responsible for deleting
+ * returned JsRootedValue when done with it.
+ */
+static JsRootedValue* GetFieldAsRootedValue(JSContext* cx, jclass clazz,
+    jobject obj, jstring fieldName)
+{
+  Tracer tracer("GetFieldAsRootedValue");
+  JsRootedValue::ContextManager context(cx);
+  jmethodID getFieldMeth = savedJNIEnv->GetMethodID(clazz, "getField",
+      "(Ljava/lang/String;I)V");
+  if (!getFieldMeth || savedJNIEnv->ExceptionCheck()) {
+    return 0;
+  }
+
+  JsRootedValue* jsRootedValue = new JsRootedValue();
+  savedJNIEnv->CallVoidMethod(obj, getFieldMeth, fieldName,
+  	 reinterpret_cast<jint>(jsRootedValue));
+  if (savedJNIEnv->ExceptionCheck()) {
+  	 delete jsRootedValue;
+    return 0;
+  }
+  return jsRootedValue;
+}
+  
+/*
+ * Sets the value of a field on a Java object.
+ * 
+ * context - JavaScript context
+ * clazz - class of obj
+ * obj - Java object to store into field
+ * fieldName - name of field on Java object to store into
+ * jsRootedValue - the value to store in the field
+ * 
+ * returns true on success, false on failure
+ */
+static bool SetFieldFromRootedValue(JSContext* cx, jclass clazz,
+    jobject obj, jstring fieldName, JsRootedValue* jsRootedValue)
+{
+  Tracer tracer("SetFieldAsRootedValue");
+  JsRootedValue::ContextManager context(cx);
+  jmethodID getFieldMeth = savedJNIEnv->GetMethodID(clazz, "setField",
+      "(Ljava/lang/String;I)V");
+  if (!getFieldMeth || savedJNIEnv->ExceptionCheck()) {
+    return false;
+  }
+
+  savedJNIEnv->CallVoidMethod(obj, getFieldMeth, fieldName,
+  	 reinterpret_cast<jint>(jsRootedValue));
+  if (savedJNIEnv->ExceptionCheck()) {
+    return false;
+  }
+
+  return true;
+}
+
+/*
+ * Throws a HostedModeException with the specified message.
+ */
+static void ThrowHostedModeException(JNIEnv* jniEnv, const char* msg) {
+  jclass exceptionClass
+      = jniEnv->FindClass("com/google/gwt/dev/shell/HostedModeException");
+  jniEnv->ThrowNew(exceptionClass, msg);
+}
+
+/*
+ * Types of jsvals.
+ */
+enum JsValueType {
+  JSVAL_TYPE_VOID=0,
+  JSVAL_TYPE_NULL,
+  JSVAL_TYPE_BOOLEAN,
+  JSVAL_TYPE_NUMBER,
+  JSVAL_TYPE_STRING,
+  JSVAL_TYPE_OBJECT,
+  JSVAL_TYPE_UNKNOWN,
+};
+
+/*
+ * Names of jsval types -- must match the order of the enum above.
+ */
+static const char* JsValueTypeStrings[]={
+  "undefined",
+  "null",
+  "boolean",
+  "number",
+  "string",
+  "object",
+  "unknown",
+};
+
+/*
+ * Return the type of a jsval.
+ */
+static JsValueType GetValueType(jsval val) {
+  if(JSVAL_IS_VOID(val)) {
+    return JSVAL_TYPE_VOID;
+  } else if(JSVAL_IS_NULL(val)) {
+    return JSVAL_TYPE_NULL;
+  } else if(JSVAL_IS_BOOLEAN(val)) {
+    return JSVAL_TYPE_BOOLEAN;
+  } else if(JSVAL_IS_NUMBER(val)) {
+    return JSVAL_TYPE_NUMBER;
+  } else if(JSVAL_IS_STRING(val)) {
+    return JSVAL_TYPE_STRING;
+  } else if(JSVAL_IS_OBJECT(val)) {
+    return JSVAL_TYPE_OBJECT;
+  } else {
+    return JSVAL_TYPE_UNKNOWN;
+  } 
+}
+
+/*
+ * Called from JavaScript to call a Java method that has previously been
+ * wrapped.  See _setWrappedFunction for use.
+ */ 
+static JSBool invokeJavaMethod(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+  Tracer tracer("invokeJavaMethod");
+  JsRootedValue::ContextManager context(cx);
+
+  // I kid you not; this is how XPConnect gets their function object so they can
+  // multiplex dispatch the call from a common site.  See XPCDispObject.cpp(466)
+  //
+  // I now have a secondary confirmation that this trick is legit.
+  // brandon@mozilla.org writes:
+  //
+  // argv[-2] is part of the JS API, unabstracted.  Just as argv[0] is the
+  // first argument (if argc != 0), argv[-1] is the |this| parameter (equal
+  // to OBJECT_TO_JSVAL(obj) in a native method with the standard |obj|
+  // second formal parameter name), and argv[-2] is the callee object, tagged
+  // as a jsval.
+  if (JS_TypeOfValue(cx, argv[-2]) != JSTYPE_FUNCTION) {
+    tracer.setFail("not a function type");
+    return JS_FALSE;
+  }
+  JSObject* funObj = JSVAL_TO_OBJECT(argv[-2]);
+
+  // Pull the wrapper object out of the funObj's reserved slot
+  jsval jsCleanupObj;
+  if (!JS_GetReservedSlot(cx, funObj, 0, &jsCleanupObj)) {
+    tracer.setFail("JS_GetReservedSlot failed");
+    return JS_FALSE;
+  }
+  JSObject* cleanupObj = JSVAL_TO_OBJECT(jsCleanupObj);
+  if (!cleanupObj) {
+    tracer.setFail("cleanupObj is null");
+    return JS_FALSE;
+  }
+
+  // Get DispatchMethod instance out of the wrapper object
+  jobject dispMeth =
+      NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, cleanupObj));
+  if (!dispMeth) {
+    tracer.setFail("dispMeth is null");
+    return JS_FALSE;
+  }
+  jclass dispClass = savedJNIEnv->GetObjectClass(dispMeth);
+  if (!dispClass || savedJNIEnv->ExceptionCheck()) {
+    tracer.setFail("GetObjectClass returns null");
+    return JS_FALSE;
+  }
+
+  // lookup the invoke method on the dispatch object
+  jmethodID invokeID =
+      savedJNIEnv->GetMethodID(dispClass, "invoke", "(I[II)V");
+  if (!invokeID || savedJNIEnv->ExceptionCheck()) {
+    tracer.setFail("GetMethodID failed");
+    return JS_FALSE;
+  }
+
+  // create an array of integers to hold the JsRootedValue pointers passed
+  // to the invoke method
+  jintArray args = savedJNIEnv->NewIntArray(argc);
+  if (!args || savedJNIEnv->ExceptionCheck()) {
+    tracer.setFail("NewIntArray failed");
+    return JS_FALSE;
+  }
+
+  // these arguments are already rooted by the JS interpreter, but we
+  // can't easily take advantage of that without complicating the JsRootedValue
+  // interface.
+  
+  // argv[-1] is OBJECT_TO_JSVAL(this)
+  JsRootedValue* jsThis = new JsRootedValue(argv[-1]);
+  tracer.log("jsthis=%08x, RV=%08x", unsigned(argv[-1]), unsigned(jsThis));
+
+  // create JsRootedValues for arguments  
+  JsRootedValue *jsArgs[argc]; 
+  for (uintN i = 0; i < argc; ++i) {
+    jsArgs[i] = new JsRootedValue(argv[i]);
+  }
+  savedJNIEnv->SetIntArrayRegion(args, 0, argc,
+      reinterpret_cast<jint*>(jsArgs));
+  if (savedJNIEnv->ExceptionCheck()) {
+    tracer.setFail("SetIntArrayRegion failed");
+    return JS_FALSE;
+  }
+  
+  // slot for return value
+  JsRootedValue* jsReturnVal = new JsRootedValue();
+
+  // TODO(jat): small window here where invocation may fail before Java
+  // takes ownership of the JsRootedValue objects.  One solution would be
+  // to reference-count them between Java and C++ (so the reference count
+  // would always be 0, 1, or 2).  Also setField has a similar problem.
+  // I plan to fix this when switching away from Java holding pointers to
+  // C++ objects as part of the fix for 64-bit support (which we could
+  // accomplish inefficiently by changing int to long everywhere, but there
+  // are other 64-bit issues to resolve and we need to reduce the number of
+  // roots the JS interpreter has to search.
+  
+  // call Java method
+  savedJNIEnv->CallVoidMethod(dispMeth, invokeID, reinterpret_cast<int>(jsThis),
+      args, reinterpret_cast<int>(jsReturnVal));
+  
+  JSBool returnValue = JS_TRUE;
+  
+  if (savedJNIEnv->ExceptionCheck()) {
+    tracer.log("dispMeth=%08x", unsigned(dispMeth));
+    tracer.setFail("java exception is active:");
+    jobject exception = savedJNIEnv->ExceptionOccurred();
+    if (exception) {
+      fprintf(stderr, "Exception occurred in MethodDispatch.invoke:\n");
+      savedJNIEnv->ExceptionDescribe();
+      savedJNIEnv->DeleteLocalRef(exception);
+    }
+    returnValue = JS_FALSE;
+  } else if (JS_IsExceptionPending(cx)) {
+    tracer.setFail("js exception is active");
+    returnValue = JS_FALSE;
+  }
+
+  // extract return value
+  *rval = jsReturnVal->getValue();
+
+#if 0
+  // NOTE: C++ objects are not cleaned up here because Java now owns them.
+  // TODO(jat): if reference-counted, they *do* need to be Released here.
+  
+  // free JsRootedValues
+  for (uintN i = 0; i < argc; ++i) {
+    delete jsArgs[i];
+  }
+  delete jsThis;
+  delete jsReturnVal;
+#endif
+
+  return returnValue;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _createJsRootedValue()
+ * Signature: (I)I
+ */
+extern "C" JNIEXPORT jint JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1createJsRootedValue
+  (JNIEnv* jniEnv, jclass, jint jsval)
+{
+  Tracer tracer("JsValueMoz._createJsRootedValue");
+  JsRootedValue* jsRootedValue = new JsRootedValue(jsval);
+  return NS_REINTERPRET_CAST(jint, jsRootedValue);
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _copyJsRootedValue()
+ * Signature: (I)I
+ */
+extern "C" JNIEXPORT jint JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1copyJsRootedValue
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+  const JsRootedValue* jsRootedValue = reinterpret_cast<const JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._copyJsRootedValue", jsRootedValue);
+  JsRootedValue* newRootedValue = new JsRootedValue(*jsRootedValue);
+  return NS_REINTERPRET_CAST(jint, newRootedValue);
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _destroyJsRootedValue()
+ * Signature: (I)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1destroyJsRootedValue
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._destroyJsRootedValue", jsRootedValue);
+  delete jsRootedValue;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _getBoolean()
+ * Signature: (I)Z
+ * 
+ * TODO(jat): unboxing Javascript Boolean type?
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getBoolean
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._getBoolean", jsRootedValue);
+  return jsRootedValue->getBoolean();
+}
+
+/**
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _getInt()
+ * Signature: (I)I
+ * 
+ * @see com.google.gwt.dev.shell.moz.JsValueMoz#getInt()
+ */
+extern "C" JNIEXPORT jint JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getInt
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._getInt", jsRootedValue);
+  int val = jsRootedValue->getInt();
+  tracer.log("value=%d", val);
+  return val;
+}
+
+/**
+ * Return a Javascript number as a Java double.
+ * 
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _getNumber()
+ * Signature: (I)D
+ */
+extern "C" JNIEXPORT jdouble JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getNumber
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._getNumber", jsRootedValue);
+  return jsRootedValue->getDouble();
+}
+
+/**
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _getJsval()
+ * Signature: (I)I
+ */
+extern "C" JNIEXPORT jint JNICALL
+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);
+  int val = jsRootedValue->getValue();
+  tracer.log("value=%d", val);
+  return val;
+}
+
+/**
+ * Return a Javascript string as a Java string.
+ * 
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _getString()
+ * Signature: (I)Ljava/lang/String;
+ * 
+ * Note that this relies on jschar being assignment compatible with jchar
+ */
+extern "C" JNIEXPORT jstring JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getString
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._getString", jsRootedValue);
+  const JSString* str = jsRootedValue->getString();
+  int len = JS_GetStringLength(const_cast<JSString*>(str));
+  jstring javaStr =jniEnv->NewString(reinterpret_cast<const jchar*>(
+      JS_GetStringChars(const_cast<JSString*>(str))), len);
+  return javaStr;
+}
+
+/*
+ * Returns a human-readable Java string describing the type of a
+ * JavaScript object.
+ * 
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _getTypeString
+ * Signature: (I)Ljava/lang/String;
+ */
+extern "C" JNIEXPORT jstring JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getTypeString
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._getTypeString", jsRootedValue);
+  jsval val = jsRootedValue->getValue();
+  JSContext* cx = JsRootedValue::currentContext();
+  JsValueType valueType = GetValueType(val);
+  const char* typeString = 0;
+  char buf[256];
+  if(valueType == JSVAL_TYPE_OBJECT) {
+    JSObject* jsObject = JSVAL_TO_OBJECT(val);
+    JSClass* objClass = JS_GET_CLASS(cx, jsObject);
+    if (JS_InstanceOf(cx, jsObject,
+        &gwt_nativewrapper_class, 0)) {
+      typeString = "Java object";
+    } else {
+      snprintf(buf, sizeof(buf), "class %s", objClass->name);
+      typeString = buf;
+    }
+  } else {
+    typeString = JsValueTypeStrings[valueType];
+  }
+  jstring returnValue = jniEnv->NewStringUTF(typeString);
+  return returnValue;
+}
+
+/*
+ * Unwraps a wrapped Java object from a JS object.
+ * 
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _getWrappedJavaObject
+ * Signature: (I)Ljava/lang/Object;
+ */
+extern "C" JNIEXPORT jobject JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getWrappedJavaObject
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._getWrappedJavaObject", jsRootedValue);
+  JSObject* jsObject = jsRootedValue->getObject();
+  if(!jsObject) {
+    tracer.throwHostedModeException(jniEnv, "Javascript value not an object");
+    return 0;
+  }
+  JSContext* cx = JsRootedValue::currentContext();
+  if(!JS_InstanceOf(cx, jsObject, &gwt_nativewrapper_class, 0)) {
+    tracer.throwHostedModeException(jniEnv,
+      "Javascript object not a Java object");
+    return 0;
+  } 
+  jobject javaObject
+      = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, jsObject));
+  return javaObject;
+} 
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _isBoolean()
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isBoolean
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._isBoolean", jsRootedValue);
+  return jsRootedValue->isBoolean();
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _isInt()
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isInt
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._isBoolean", jsRootedValue);
+  return jsRootedValue->isInt();
+}
+
+/*
+ * Checks if a JS object is a JavaScript object.
+ * 
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _isJavaScriptObject
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isJavaScriptObject
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._isJavaScriptObject", jsRootedValue);
+  jsval val = jsRootedValue->getValue();
+  bool returnValue = false;
+  if(JSVAL_IS_OBJECT(val)) {
+    JSObject* jsObject = JSVAL_TO_OBJECT(val);
+    returnValue = !JS_InstanceOf(JsRootedValue::currentContext(), jsObject,
+        &gwt_nativewrapper_class, 0);
+    tracer.log("jsobject=%08x, isJSObject=%s", unsigned(jsObject),
+        returnValue ? "true" : "false");
+  } else {
+    tracer.log("not an object");
+  }
+  return returnValue;
+} 
+
+/*
+ * Checks if a JS object is a JavaScript String object.
+ * 
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _isJavaScriptString
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isJavaScriptString
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._isJavaScriptString", jsRootedValue);
+  bool returnValue = jsRootedValue->isJavaScriptStringObject();
+  tracer.log("value=%s", returnValue ? "true" : "false");
+  return returnValue;
+} 
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _isNull()
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isNull
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._isNull", jsRootedValue);
+  return jsRootedValue->isNull();
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _isNumber()
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isNumber
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._isNumber", jsRootedValue);
+  return jsRootedValue->isNumber();
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _isString()
+ * Signature: (I)Z
+ * 
+ * Handles the case of JavaScript String objects as well
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isString
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._isString", jsRootedValue);
+  return jsRootedValue->isString();
+}
+
+/*
+ * Checks if a JS object is undefined (void)
+ * 
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _isUndefined
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isUndefined
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._isUndefined", jsRootedValue);
+  return jsRootedValue->isUndefined();
+} 
+
+/*
+ * Checks if a JS object is a wrapped Java object.
+ * 
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _isWrappedJavaObject
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isWrappedJavaObject
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._isWrappedJavaObject", jsRootedValue);
+  jsval val = jsRootedValue->getValue();
+  bool returnValue = false;
+  if(JSVAL_IS_OBJECT(val)) {
+    JSObject* jsObject = JSVAL_TO_OBJECT(val);
+    returnValue = JS_InstanceOf(JsRootedValue::currentContext(), jsObject,
+        &gwt_nativewrapper_class, 0);
+    tracer.log("jsobject=%08x, wrappedJava=%s", unsigned(jsObject),
+        returnValue ? "true" : "false");
+  } else {
+    tracer.log("not an object");
+  }
+  return returnValue;
+} 
+
+/*
+ * Set the JavaScript value to be a boolean of the supplied value.
+ * 
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _setBoolean()
+ * Signature: (IZ)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setBoolean
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jboolean val)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._setBoolean", jsRootedValue);
+  jsRootedValue->setBoolean(val == JNI_TRUE);
+  return;
+}
+
+/*
+ * Set the JavaScript value to be a double of the supplied value.
+ * 
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _setDouble()
+ * Signature: (ID)V
+ */
+extern "C" JNIEXPORT void
+JNICALL Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setDouble
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jdouble val)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._setDouble", jsRootedValue);
+  if(!jsRootedValue->setDouble(val)) {
+    tracer.throwHostedModeException(jniEnv, "Unable to allocate JS double");
+    return;
+  }
+}
+
+/*
+ * Set the Javascript value to be an integer.
+ * 
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _setInt()
+ * Signature: (II)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setInt
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jint val)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._setInt", jsRootedValue);
+  tracer.log("val=%d", val);
+  jsRootedValue->setInt(val);
+}
+
+/*
+ * Set the Javascript value to be another JsRootedValue's value.
+ * 
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _setJsRootedValue()
+ * Signature: (II)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setJsRootedValue
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jint jsOtherRootedValueInt)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  JsRootedValue* jsOtherRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsOtherRootedValueInt);
+  Tracer tracer("JsValueMoz._setJsRootedValue", jsRootedValue);
+  jsRootedValue->setValue(jsOtherRootedValue->getValue());
+}
+
+/*
+ * 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
+ * Method:    _setNull()
+ * Signature: (I)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setNull
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._setNull", jsRootedValue);
+  jsRootedValue->setNull();
+}
+
+/*
+ * Set the JavaScript value to be a string of the supplied value.
+ * 
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _setString()
+ * Signature: (ILjava/lang/String;)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setString
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jstring val)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._setString", jsRootedValue);
+  JStringWrap strVal(jniEnv, val);
+  const jchar* stringUTF16 = strVal.jstr();
+  if(!stringUTF16) {
+    tracer.throwHostedModeException(jniEnv, "Unable to retrieve Java string");
+    return;
+  }
+  tracer.log("string=%s", strVal.str());
+  if(!jsRootedValue->setString(reinterpret_cast<const wchar_t*>(stringUTF16),
+      strVal.length())) {
+    tracer.throwHostedModeException(jniEnv, "Unable to allocate JS string");
+    return;
+  }
+}
+
+/*
+ * Set the JavaScript value to be undefined (void).
+ * 
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _setUndefined()
+ * Signature: (I)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setUndefined
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._setUndefined", jsRootedValue);
+  jsRootedValue->setUndefined();
+}
+
+/*
+ * Wraps a Java object in a JS object.
+ * 
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _setWrappedJavaObject
+ * Signature: (ILjava/lang/Object)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setWrappedJavaObject
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jobject obj)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._setWrappedJavaObject", jsRootedValue);
+  JSContext* cx = JsRootedValue::currentContext();
+  JSObject* scriptWindow = JS_GetGlobalObject(cx);
+  JSObject* newObj = JS_NewObject(cx, &gwt_nativewrapper_class, 0,
+      scriptWindow);
+  if (!newObj) {
+    tracer.throwHostedModeException(jniEnv,
+        "Unable to allocate JS object to wrap Java object");
+    return;
+  }
+  // Save in output value so it won't get GCed.
+  jsRootedValue->setObject(newObj); 
+  tracer.log("jsobject=%08x", unsigned(newObj));
+  
+  // This is collected when the gwt_nativewrapper_class destructor runs.
+  jobject dispObjRef = jniEnv->NewGlobalRef(obj);
+  if (!dispObjRef || jniEnv->ExceptionCheck()) {
+    tracer.throwHostedModeException(jniEnv,
+        "Unable to allocate global reference for JS wrapper");
+    return;
+  } 
+  if (!JS_SetPrivate(cx, newObj, dispObjRef)) {
+    jniEnv->DeleteGlobalRef(dispObjRef);
+    tracer.throwHostedModeException(jniEnv,
+        "Unable to allocate global reference for JS wrapper");
+    return;
+  } 
+  // forcibly setup a "toString" method to override the default
+  jclass dispClass = jniEnv->GetObjectClass(obj);
+  if (jniEnv->ExceptionCheck()) {
+    tracer.throwHostedModeException(jniEnv, "Can't get object class");
+    return;
+  } 
+  jmethodID getFieldMeth = jniEnv->GetMethodID(dispClass, "getField",
+      "(Ljava/lang/String;I)V");
+  if (!getFieldMeth || jniEnv->ExceptionCheck()) {
+    tracer.throwHostedModeException(jniEnv, "Can't get getField method");
+    return;
+  } 
+  jstring ident = jniEnv->NewStringUTF("@java.lang.Object::toString()");
+  if (!ident || jniEnv->ExceptionCheck()) {
+    tracer.throwHostedModeException(jniEnv,
+        "Can't create Java string for toString method name");
+    return;
+  }
+  // allocate a new root to hold the result of the getField call
+  JsRootedValue* toStringFunc = new JsRootedValue(); 
+  jniEnv->CallVoidMethod(obj, getFieldMeth, ident,
+      NS_REINTERPRET_CAST(jint, toStringFunc));
+  if (toStringFunc->isUndefined() || jniEnv->ExceptionCheck()) {
+    tracer.throwHostedModeException(jniEnv, "getField(toString) failed");
+    return;
+  } 
+  if (!JS_DefineProperty(cx, newObj, "toString", toStringFunc->getValue(),
+      JS_PropertyStub, JS_PropertyStub, JSPROP_READONLY | JSPROP_PERMANENT)) {
+    tracer.throwHostedModeException(jniEnv, "Can't define JS toString method");
+    return;
+  }
+} 
+
+/*
+ * Wraps a Java function in a JS object.
+ * 
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _setWrappedFunction
+ * Signature: (ILjava/lang/String;Lcom/google/gwt/dev/shell/moz/DispatchMethod;)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setWrappedFunction
+    (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jstring methodName,
+     jobject dispatchMethod)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._setWrappedFunction", jsRootedValue);
+  JSContext* cx = JsRootedValue::currentContext();
+  JSObject* scriptWindow = JS_GetGlobalObject(cx);
+  JStringWrap nameStr(jniEnv, methodName);
+  if (!nameStr.str()) {
+    tracer.throwHostedModeException(jniEnv,
+       "null method name passed to setWrappedFunction");
+    return;
+  }
+  tracer.log("JsRootedValue=%08x, method=%s, obj=%08x", jsRootedValueInt,
+      nameStr.str(), unsigned(dispatchMethod));
+  JSFunction* function = JS_NewFunction(cx, invokeJavaMethod, 0,
+      JSFUN_LAMBDA, 0, nameStr.str());
+  if (!function) {
+    tracer.throwHostedModeException(jniEnv, "JS_NewFunction failed");
+    return;
+  }
+  JSObject* funObj = JS_GetFunctionObject(function);
+  if (!funObj) {
+    tracer.throwHostedModeException(jniEnv, "JS_GetFunctionObject failed");
+    return;
+  }
+  // Save in output value so it won't get GCed.
+  jsRootedValue->setObject(funObj); 
+
+  // Create a cleanup object to hold and clean up dispMeth
+  JSObject* cleanupObj = JS_NewObject(cx, &gwt_functionwrapper_class, 0,
+      scriptWindow);
+  if (!cleanupObj) {
+    tracer.throwHostedModeException(jniEnv, "JS_NewObject failed");
+    return;
+  }
+  tracer.log("funObj=%08x, cleanupObj=%08x", unsigned(funObj),
+      unsigned(cleanupObj));
+  // Store the cleanup object in funObj's reserved slot; now GC protected.
+  if(!JS_SetReservedSlot(cx, funObj, 0, OBJECT_TO_JSVAL(cleanupObj))) {
+    tracer.throwHostedModeException(jniEnv, "JS_SetReservedSlot failed");
+    return;
+  }
+  jobject dispMethRef = jniEnv->NewGlobalRef(dispatchMethod);
+  if (!dispMethRef || jniEnv->ExceptionCheck()) {
+    tracer.throwHostedModeException(jniEnv,
+        "NewGlobalRef(dispatchMethod) failed");
+    return;
+  }
+  // Store our global ref in the wrapper object
+  if (!JS_SetPrivate(cx, cleanupObj, dispMethRef)) {
+    jniEnv->DeleteGlobalRef(dispMethRef);
+    tracer.throwHostedModeException(jniEnv, "JS_SetPrivate(cleanupObj) failed");
+    return;
+  }
+}      
+
+/*
+ * Returns a JavaScript value as a string.
+ * 
+ * Class:     com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method:    _toString
+ * Signature: (I)Ljava/lang/String;
+ */
+extern "C" JNIEXPORT jstring JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1toString
+  (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+  JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+      (jsRootedValueInt);
+  Tracer tracer("JsValueMoz._toString", jsRootedValue);
+  jsval val = jsRootedValue->getValue();
+  JSContext* cx = JsRootedValue::currentContext();
+
+  // if it is a JavaScript object that has a toString member function
+  // call that, otherwise call JS_ValueToString
+  if(JSVAL_IS_OBJECT(val)) {
+    JSObject* jsObject = JSVAL_TO_OBJECT(val);
+    jsval fval;
+    jsval rval;
+    if (!JS_InstanceOf(cx, jsObject, &gwt_nativewrapper_class, 0)
+        && JS_GetProperty(cx, jsObject, "toString", &fval)
+        && JS_ValueToFunction(cx, fval)
+        && JS_CallFunctionValue(cx, jsObject, fval, 0, 0, &rval)) {
+      // all the steps succeeded, so use the result of toString() instead
+      // of the value for JS_ValueToString below
+      val = rval;
+    }
+  }
+  JSString* str = JS_ValueToString(cx, val);
+  if (!str) {
+    return 0;
+  }
+  int len = JS_GetStringLength(str);
+  jstring javaStr =jniEnv->NewString(reinterpret_cast<const jchar*>(
+      JS_GetStringChars(str)), len);
+  return javaStr;
+}