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/build.xml b/jni/build.xml
new file mode 100755
index 0000000..fc25ce0
--- /dev/null
+++ b/jni/build.xml
@@ -0,0 +1,9 @@
+<project name="jni" default="build" basedir=".">
+  <property name="gwt.root" location=".." />
+  <property name="project.tail" value="jni" />
+  <import file="${gwt.root}/common.ant.xml" />
+
+  <target name="build" description="Build each platforms">
+    <gwt.ant dir="windows" target="build"/>
+  </target>
+</project>
diff --git a/jni/core/gwt-ll.cpp b/jni/core/gwt-ll.cpp
new file mode 100644
index 0000000..4076aea
--- /dev/null
+++ b/jni/core/gwt-ll.cpp
@@ -0,0 +1,66 @@
+// Copyright 2005-2006 Google Inc.
+// All Rights Reserved.
+
+// A slim and portable set of JNI methods for GWT hosted mode
+
+#include <jni.h>
+#include <stdlib.h>
+
+extern "C" {
+
+/*
+ * Class:     com_google_gwt_dev_shell_LowLevel
+ * Method:    newGlobalRefInt
+ * Signature: (Ljava/lang/Object;)I
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_LowLevel__1newGlobalRefInt(JNIEnv* env, jclass, jobject o) {
+	return reinterpret_cast<int>(env->NewGlobalRef(o));
+}
+/*
+ * Class:     com_google_gwt_dev_shell_LowLevel
+ * Method:    objFromGlobalRefInt
+ * Signature: (I)Ljava/lang/Object;
+ */
+JNIEXPORT jobject JNICALL Java_com_google_gwt_dev_shell_LowLevel__1objFromGlobalRefInt(JNIEnv* env, jclass, jint globalRef) {
+	return reinterpret_cast<jobject>(globalRef);
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_LowLevel
+ * Method:    deleteGlobalRefInt
+ * Signature: (I)I
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_LowLevel__1deleteGlobalRefInt(JNIEnv* env, jclass, jint globalRef) {
+	env->DeleteGlobalRef(reinterpret_cast<jobject>(globalRef));
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_LowLevel
+ * Method:    getEnv
+ * Signature: (Ljava/lang/String;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_google_gwt_dev_shell_LowLevel__1getEnv(JNIEnv* env, jclass, jstring key) {
+    if (!key) {
+        // null -> null
+        return 0;
+    }
+
+	const char* keyPtr = env->GetStringUTFChars(key, 0);
+	if (!keyPtr) {
+		// There will be a pending OutOfMemoryException on this thread, so leave immediately and let it be thrown.
+		return 0;
+	}
+
+    const char* valuePtr = getenv(keyPtr);
+  	env->ReleaseStringUTFChars(key, keyPtr);
+
+    if (!valuePtr) {
+        // no match found
+        return 0;
+    }
+
+    // return the result
+	return env->NewStringUTF(valuePtr);
+}
+
+} // extern "C"
diff --git a/jni/linux/ExternalWrapper.cpp b/jni/linux/ExternalWrapper.cpp
new file mode 100644
index 0000000..3b2854e
--- /dev/null
+++ b/jni/linux/ExternalWrapper.cpp
@@ -0,0 +1,412 @@
+/*
+ * 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.
+ */
+
+/*
+ * Defines the JavaScript class gwt_external_class, which interface via JNI
+ * to Java objects.
+ */
+
+#include <jni.h>
+#include "JsRootedValue.h"
+#include "gwt-jni.h"
+#include "ExternalWrapper.h"
+#include "Tracer.h"
+#include "JsStringWrap.h"
+
+#ifdef ENABLE_TRACING
+extern void PrintJSValue(JSContext* cx, jsval val, char* prefix="");
+#else
+// Include a null version just to keep from cluttering up call sites.
+static inline void PrintJSValue(JSContext* cx, jsval val, char* prefix="") { }
+#endif
+
+// note that this does not use the NS_DEFINE_CID macro because it defines
+// the variable as const, which by default has internal linkage.  I could
+// work around it by putting extern in front of the macro, but that seems
+// fragile if the macro changes.
+nsCID kGwtExternalCID = GWT_EXTERNAL_FACTORY_CID;
+
+/*
+ * definition of JavaScript gwtOnLoad method which maps to the Java
+ * gwtOnLoad method.
+ */
+static JSBool gwtOnLoad(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+  Tracer tracer("gwtOnLoad");
+  tracer.log("context=%08x", unsigned(cx));
+  JsRootedValue::ContextManager context(cx);
+  JsRootedValue::ensureRuntime(cx);
+  if (argc < 3) {
+    tracer.setFail("less than 3 args");
+    return JS_FALSE;
+  }
+
+  JSObject* scriptWindow = 0;
+  if (argv[0] != JSVAL_NULL && argv[0] != JSVAL_VOID) {
+    if (!JS_ValueToObject(cx, argv[0], &scriptWindow)) {
+      tracer.setFail("can't get script window object");
+      return JS_FALSE;
+    }
+  }
+
+  JSString* moduleName = 0;
+  if (argv[1] != JSVAL_NULL && argv[1] != JSVAL_VOID) {
+    moduleName = JS_ValueToString(cx, argv[1]);
+  }
+
+  JSString* version = 0;
+  if (argv[2] != JSVAL_NULL && argv[2] != JSVAL_VOID) {
+    version = JS_ValueToString(cx, argv[2]);
+  }
+
+  nsCOMPtr<nsIScriptGlobalObject> scriptGlobal(0);
+  if (scriptWindow) {
+    nsCOMPtr<nsIXPConnect> xpConnect = do_GetService(nsIXPConnect::GetCID());
+    nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
+    xpConnect->GetWrappedNativeOfJSObject(cx, scriptWindow,
+        getter_AddRefs(wrappedNative));
+    if (wrappedNative) {
+        nsCOMPtr<nsISupports> native;
+        wrappedNative->GetNative(getter_AddRefs(native));
+        scriptGlobal = do_QueryInterface(native);
+    }
+  }
+  jstring jModuleName(0);
+  if (moduleName) {
+    jModuleName = savedJNIEnv->NewString(JS_GetStringChars(moduleName),
+        JS_GetStringLength(moduleName));
+    if (!jModuleName || savedJNIEnv->ExceptionCheck()) {
+      tracer.setFail("can't get module name in Java string");
+      return JS_FALSE;
+    }
+    tracer.log("module name=%s", JS_GetStringBytes(moduleName));
+  } else {
+    tracer.log("null module name");
+  }
+
+  jstring jVersion(0);
+  if (version) {
+    jVersion = savedJNIEnv->NewString(JS_GetStringChars(version),
+        JS_GetStringLength(version));
+    if (!jVersion || savedJNIEnv->ExceptionCheck()) {
+      tracer.setFail("can't get module name in Java string");
+      return JS_FALSE;
+    }
+    tracer.log("version=%s", JS_GetStringBytes(version));
+  } else {
+    tracer.log("null version");
+  }
+
+  jobject externalObject = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+  jclass objClass = savedJNIEnv->GetObjectClass(externalObject);
+  if (!objClass || savedJNIEnv->ExceptionCheck()) {
+    tracer.setFail("can't get LowLevelMoz.ExternalObject class");
+    return JS_FALSE;
+  }
+
+  jmethodID methodID = savedJNIEnv->GetMethodID(objClass, "gwtOnLoad",
+      "(ILjava/lang/String;Ljava/lang/String;)Z");
+  if (!methodID || savedJNIEnv->ExceptionCheck()) {
+    tracer.setFail("can't get gwtOnLoad method");
+    return JS_FALSE;
+  }
+
+  tracer.log("scriptGlobal=%08x", unsigned(scriptGlobal.get()));
+
+  jboolean result = savedJNIEnv->CallBooleanMethod(externalObject, methodID,
+      NS_REINTERPRET_CAST(jint, scriptGlobal.get()), jModuleName, jVersion);
+  if (savedJNIEnv->ExceptionCheck()) {
+    tracer.setFail("LowLevelMoz.ExternalObject.gwtOnLoad() threw an exception");
+    return JS_FALSE;
+  }
+  *rval = BOOLEAN_TO_JSVAL((result == JNI_FALSE) ? JS_FALSE : JS_TRUE);
+  return JS_TRUE;
+}
+
+/*
+ * definition of JavaScript initModule method which maps to the Java
+ * initModule method.
+ */
+static JSBool initModule(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+  Tracer tracer("initModule");
+  tracer.log("context=%08x", unsigned(cx));
+  JsRootedValue::ContextManager context(cx);
+  JsRootedValue::ensureRuntime(cx);
+  if (argc < 1) {
+    tracer.setFail("less than 1 args");
+    return JS_FALSE;
+  }
+
+  JSString* moduleName = 0;
+  if (argv[0] != JSVAL_NULL && argv[0] != JSVAL_VOID) {
+    moduleName = JS_ValueToString(cx, argv[0]);
+  }
+
+  jstring jModuleName(0);
+  if (moduleName) {
+    jModuleName = savedJNIEnv->NewString(JS_GetStringChars(moduleName),
+        JS_GetStringLength(moduleName));
+    if (!jModuleName || savedJNIEnv->ExceptionCheck()) {
+      tracer.setFail("can't get module name in Java string");
+      return JS_FALSE;
+    }
+    tracer.log("module name=%s", JS_GetStringBytes(moduleName));
+  } else {
+    tracer.log("null module name");
+  }
+
+  jobject externalObject = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+  jclass objClass = savedJNIEnv->GetObjectClass(externalObject);
+  if (!objClass || savedJNIEnv->ExceptionCheck()) {
+    tracer.setFail("can't get LowLevelMoz.ExternalObject class");
+    return JS_FALSE;
+  }
+
+  jmethodID methodID = savedJNIEnv->GetMethodID(objClass, "initModule",
+      "(Ljava/lang/String;)Z");
+  if (!methodID || savedJNIEnv->ExceptionCheck()) {
+    tracer.setFail("can't get initModule method");
+    return JS_FALSE;
+  }
+
+  jboolean result = savedJNIEnv->CallBooleanMethod(externalObject, methodID,
+      jModuleName);
+  if (savedJNIEnv->ExceptionCheck()) {
+    tracer.setFail("LowLevelMoz.ExternalObject.initModule() threw an exception");
+    return JS_FALSE;
+  }
+  *rval = BOOLEAN_TO_JSVAL((result == JNI_FALSE) ? JS_FALSE : JS_TRUE);
+  return JS_TRUE;
+}
+
+/*=======================================================================*/
+/* Implementation of the getProperty, setProperty, and finalize methods  */
+/* for the JavaScript class gwt_external_class.                          */
+/*=======================================================================*/
+
+static JSBool JS_DLL_CALLBACK gwt_external_getProperty(JSContext *cx,
+    JSObject *obj, jsval id, jsval *vp)
+{
+  Tracer tracer("gwt_external_getProperty");
+  JsRootedValue::ContextManager context(cx);
+  if (*vp != JSVAL_VOID) {
+    // we setup the gwtOnLoad function as a property in GetScriptObject and
+    // do not maintain a copy of it anywhere.  So, if there is a cached
+    // value for a property we must return it.  As we never redefine any
+    // property values, this is safe.  If we were going to keep this code
+    // around and add Toby's profiling code we would need to revisit this.
+    return JS_TRUE;
+  }
+
+  if (!JSVAL_IS_STRING(id)) {
+    tracer.setFail("not a string");
+    return JS_FALSE;
+  }
+  JsStringWrap jsStr(cx, id);
+  tracer.log("obj=%08x, property=%.*s", obj, jsStr.length(), jsStr.bytes());
+
+// All this is for calling resolveReference which only returns void.  So,
+// just replace this code to return void for now.  TODO(jat): revisit when
+// merging in Toby's code.
+#if 0
+  jstring jident = savedJNIEnv->NewString(jsStr.chars(), jsStr.length());
+  if (!jident || savedJNIEnv->ExceptionCheck()) {
+    tracer.setFail("can't create Java string ");
+    return JS_FALSE;
+  }
+  jobject externalObject = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+  jclass objClass = savedJNIEnv->GetObjectClass(externalObject);
+  if (!objClass || savedJNIEnv->ExceptionCheck()) {
+    tracer.setFail("can't find Java class for JS object");
+    return JS_FALSE;
+  }
+
+  jmethodID methodID = savedJNIEnv->GetMethodID(objClass, "resolveReference",
+      "(Ljava/lang/String;)I");
+  if (!methodID || savedJNIEnv->ExceptionCheck()) {
+    tracer.setFail("exception getting method for int resolveReference(String)");
+    return JS_FALSE;
+  }
+  int retval = savedJNIEnv->CallIntMethod(externalObject, methodID, jident);
+  if (savedJNIEnv->ExceptionCheck()) {
+    tracer.setFail("exception calling int resolveReference(String)");
+    return JS_FALSE;
+  }
+  *vp = retval;
+#else
+  *vp = JSVAL_VOID;
+#endif
+  return JS_TRUE;
+}
+
+static void JS_DLL_CALLBACK gwt_external_finalize(JSContext *cx, JSObject *obj)
+{
+  // We don't need to push a context if all we do is DeleteGlobalRef
+  Tracer tracer("gwt_external_finalize", obj);
+  jobject externalObject = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+  if (externalObject) {
+    savedJNIEnv->DeleteGlobalRef(externalObject);
+  }
+  JS_FinalizeStub(cx, obj);
+}
+
+static JSBool JS_DLL_CALLBACK gwt_external_setProperty(JSContext *cx,
+    JSObject *obj, jsval id, jsval *vp)
+{
+  return JS_FALSE;
+}
+ 
+static JSClass gwt_external_class = {
+    "gwt_external_class", JSCLASS_HAS_PRIVATE,
+    JS_PropertyStub, JS_PropertyStub, gwt_external_getProperty,
+    gwt_external_setProperty, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
+    gwt_external_finalize,
+    JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+NS_IMPL_ISUPPORTS1(ExternalWrapper, nsIScriptObjectOwner)
+
+/*
+ * Create a new LowLevelMoz.ExternalObject instance and a JavaScript object
+ * that refers to it, mapping the gwtOnLoad member function mapping to
+ * a Javascript method.
+ */
+NS_IMETHODIMP ExternalWrapper::GetScriptObject(nsIScriptContext *aContext,
+    void** aScriptObject)
+{
+  Tracer tracer("ExternalWrapper::GetScriptObject"); 
+  if (!aScriptObject) {
+    tracer.setFail("null script object pointer");
+    return NS_ERROR_INVALID_POINTER;
+  }
+  if (!jsWindowExternalObject) {
+    JSContext* cx = NS_REINTERPRET_CAST(JSContext*,
+        aContext->GetNativeContext());
+    if (!cx) {
+      tracer.setFail("can't get JSContext");
+      return NS_ERROR_UNEXPECTED;
+    }
+    JsRootedValue::ContextManager context(cx);
+    *aScriptObject = 0;
+
+    nsIScriptGlobalObject* globalObject = aContext->GetGlobalObject();
+    nsCOMPtr<nsIDOMWindow> domWindow(do_QueryInterface(globalObject));
+    if (!domWindow) {
+      tracer.setFail("can't get DOM window");
+      return NS_ERROR_UNEXPECTED;
+    }
+    nsCOMPtr<nsIDOMWindow> topWindow;
+    domWindow->GetTop(getter_AddRefs(topWindow));
+    if (!topWindow) {
+      tracer.setFail("Can't get top window");
+      return NS_ERROR_UNEXPECTED;
+    }
+
+    tracer.log("savedJNIEnv=%08x, llClass=%08x", unsigned(savedJNIEnv),
+        lowLevelMozClass);
+    
+    jmethodID methodID = savedJNIEnv->GetStaticMethodID(lowLevelMozClass,
+        "createExternalObjectForDOMWindow",
+        "(I)Lcom/google/gwt/dev/shell/moz/LowLevelMoz$ExternalObject;");
+    if (!methodID || savedJNIEnv->ExceptionCheck()) {
+      tracer.setFail("Can't get createExternalObjectForDOMWindow method");
+      return NS_ERROR_UNEXPECTED;
+    }
+
+    jobject externalObject = savedJNIEnv->CallStaticObjectMethod(
+        lowLevelMozClass, methodID, NS_REINTERPRET_CAST(jint, topWindow.get()));
+    if (!externalObject || savedJNIEnv->ExceptionCheck()) {
+      tracer.setFail("createExternalObjectForDOMWindow failed");
+      return NS_ERROR_UNEXPECTED;
+    }
+    externalObject = savedJNIEnv->NewGlobalRef(externalObject);
+    if (!externalObject || savedJNIEnv->ExceptionCheck()) {
+      tracer.setFail("can't get GlobalRef for external object");
+      return NS_ERROR_UNEXPECTED;
+    }
+    JSObject* newObj = JS_NewObject(cx, &gwt_external_class, 0,
+        globalObject->GetGlobalJSObject());
+    if (!newObj) {
+      tracer.setFail("can't create new gwt_external_class object");
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+    if (!JS_SetPrivate(cx, newObj, externalObject)) {
+      savedJNIEnv->DeleteGlobalRef(externalObject);
+      tracer.setFail("can't store external object private reference");
+      return NS_ERROR_UNEXPECTED;
+    }
+  
+    if (!JS_DefineFunction(cx, newObj, "gwtOnLoad", gwtOnLoad, 3,
+        JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
+      tracer.setFail("can't define gwtOnLoad function on JavaScript object");
+      return NS_ERROR_UNEXPECTED;
+    }
+    if (!JS_DefineFunction(cx, newObj, "initModule", initModule, 1,
+        JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
+      tracer.setFail("can't define initModule function on JavaScript object");
+      return NS_ERROR_UNEXPECTED;
+    }
+    jsWindowExternalObject = newObj;
+  }
+
+  *aScriptObject = jsWindowExternalObject;
+  return NS_OK;
+}
+
+NS_IMETHODIMP ExternalWrapper::SetScriptObject(void* aScriptObject)
+{
+    jsWindowExternalObject = aScriptObject;
+    return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS1(nsRpExternalFactory, nsIFactory)
+
+NS_IMETHODIMP nsRpExternalFactory::CreateInstance(nsISupports *aOuter,
+    const nsIID& aIID, void** aResult)
+{
+  Tracer tracer("nsRpExternalFactory::CreateInstance");
+  if (!aResult) {
+    tracer.setFail("null pointer for return value");
+    return NS_ERROR_INVALID_POINTER;
+  }
+  *aResult  = NULL;
+
+  if (aOuter) {
+    tracer.setFail("aOuter is not null");
+    return NS_ERROR_NO_AGGREGATION;
+  }
+
+  nsISupports* object = new ExternalWrapper();
+  if (!object) {
+    tracer.setFail("can't create a new ExternalWrapper");
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  nsresult result = object->QueryInterface(aIID, aResult);
+  if (!*aResult || NS_FAILED(result)) {
+    tracer.setFail("ExternalWrapper::QueryInterface failed");
+    delete object;
+  }
+  return result;
+}
+
+NS_IMETHODIMP nsRpExternalFactory::LockFactory(PRBool lock)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
diff --git a/jni/linux/ExternalWrapper.h b/jni/linux/ExternalWrapper.h
new file mode 100644
index 0000000..0168083
--- /dev/null
+++ b/jni/linux/ExternalWrapper.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2006 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.
+ */
+
+#ifndef EXTERNALWRAPPER_H_
+#define EXTERNALWRAPPER_H_
+
+class ExternalWrapper : public nsIScriptObjectOwner {
+public:
+  NS_DECL_ISUPPORTS
+  NS_IMETHOD GetScriptObject(nsIScriptContext *aContext, void** aScriptObject);
+  NS_IMETHOD SetScriptObject(void* aScriptObject);
+  ExternalWrapper(): jsWindowExternalObject(0) { }
+private:
+  ~ExternalWrapper() { }
+  void *jsWindowExternalObject;
+};
+
+class nsRpExternalFactory : public nsIFactory {
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIFACTORY
+  nsRpExternalFactory() { }
+private:
+  ~nsRpExternalFactory() { }
+};
+
+#define GWT_EXTERNAL_FACTORY_CID \
+{ 0xF56E23F8, 0x5D06, 0x47F9, \
+{ 0x88, 0x5A, 0xD9, 0xCA, 0xC3, 0x38, 0x41, 0x7F } }
+#define GWT_EXTERNAL_CONTRACTID "@com.google/GWT/external;1"
+
+#endif /*EXTERNALWRAPPER_H_*/
diff --git a/jni/linux/JStringWrap.h b/jni/linux/JStringWrap.h
new file mode 100644
index 0000000..9d2ebcc
--- /dev/null
+++ b/jni/linux/JStringWrap.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#ifndef JNI_LINUX_JSTRINGWRAP_H_
+#define JNI_LINUX_JSTRINGWRAP_H_
+
+/*
+ * Wrapper arouond Java Strings, keeps pointers to unpacked strings
+ * and makes sure they are cleaned up. 
+ */
+class JStringWrap {
+  public:
+    JStringWrap(JNIEnv* env, jstring str): env(env), s(str), p(0), jp(0) { }
+    ~JStringWrap() {
+      if (p) env->ReleaseStringUTFChars(s, p);
+      if (jp) env->ReleaseStringChars(s, jp);
+    }
+    const char* str() {
+      if (!p) p = env->GetStringUTFChars(s, 0);
+      return p;
+    }
+    const jchar* jstr() {
+      if (!jp) jp = env->GetStringChars(s, 0);
+      return jp;
+    }
+    int length() {
+      return env->GetStringLength(s);
+    }
+  private:
+    JNIEnv* env;
+    jstring s;
+    const char* p;
+    const jchar* jp;
+};
+
+
+#endif // JNI_LINUX_JSTRINGWRAP_H_
diff --git a/jni/linux/JsRootedValue.cpp b/jni/linux/JsRootedValue.cpp
new file mode 100644
index 0000000..29b95ca
--- /dev/null
+++ b/jni/linux/JsRootedValue.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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 "JsRootedValue.h"
+
+// Initialize static value used to hold the JavaScript String class.
+JSClass* JsRootedValue::stringClass = 0;
+
+// Initialize static reference to the sole JSRuntime value in Gecko.
+JSRuntime* JsRootedValue::runtime = 0;
+
+// Static stack of JavaScript execution contexts.
+std::stack<JSContext*> JsRootedValue::contextStack;
+
+/*
+ * Actually get the stringClass pointer from JavaScript.
+ */
+void JsRootedValue::fetchStringClass() const {
+  Tracer tracer("JsRootedValue::fetchStringClass");
+  JSContext* cx = currentContext();
+  jsval val = JS_GetEmptyStringValue(cx);
+  JSObject* obj;
+  // on error, leave stringClass null
+  if (!JS_ValueToObject(cx, val, &obj)) return;
+  if (!obj) {
+    tracer.log("ensureStringClass: null object");
+    return;
+  }
+  stringClass = JS_GET_CLASS(cx, obj);
+  tracer.log("stringClass=%08x", unsigned(stringClass));
+}
diff --git a/jni/linux/JsRootedValue.h b/jni/linux/JsRootedValue.h
new file mode 100644
index 0000000..65c25af
--- /dev/null
+++ b/jni/linux/JsRootedValue.h
@@ -0,0 +1,428 @@
+/*
+ * 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.
+ */
+#ifndef JNI_LINUX_JSROOTEDVALUE_H_
+#define JNI_LINUX_JSROOTEDVALUE_H_
+
+// Mozilla header files
+#include "mozilla-headers.h"
+
+#include "Tracer.h"
+#include <stack>
+
+extern "C" JSClass gwt_nativewrapper_class;
+
+/*
+ * Holds a root for Javascript objects, so the JS interpreter knows not to
+ * garbage-collect the underlying object as long as this object exists.
+ * Java code will pass a pointer to this object around (as an int/long) for
+ * referring to the underlying Javascript object.
+ *
+ * There are also convenience routines for manipulating the underlying value.
+ * Note that all get* methods assume the type is correct, so the corresponding
+ * is* method should be called first if you aren't sure of the type.
+ *
+ * See http://developer.mozilla.org/en/docs/JS_AddRoot for details.
+ *
+ * TODO(jat): rewrite this to minimize the number of roots held and to
+ *    improve 64-bit compatibility.
+ */
+class JsRootedValue
+{
+private:
+  // the JavaScript String class
+  static JSClass* stringClass;
+  
+  // Javascript runtime
+  static JSRuntime* runtime;
+
+  // stack of Javascript contexts
+  static std::stack<JSContext*> contextStack;
+
+  // underlying Javascript value
+  jsval         value_;
+
+protected:
+  /*
+   * Fetch the JavaScript String class.
+   * Not inlined to minimize code bloat since it should only be called once.
+   */
+  void fetchStringClass() const;
+  
+  /*
+   * Make sure we have the JS code to identify String objects installed.
+   */
+  void ensureStringClass() const {
+    if(stringClass) return;
+    fetchStringClass();
+  }
+  
+  /*
+   * Helper for the various constructors
+   */
+  void constructorHelper(const char* ctorDesc) {
+    Tracer tracer(ctorDesc, this);
+    if (!JS_AddNamedRootRT(runtime, &value_, ctorDesc)) {
+      tracer.log("JS_AddNamedRootRT failed");
+      // TODO(jat): handle errors
+    }
+  }
+
+  /*
+   * Push a new JavaScript execution context.
+   */
+  static void pushContext(JSContext* context) {
+    Tracer tracer("JsRootedValue::pushContext");
+    tracer.log("pushed context=%08x", unsigned(context));
+    contextStack.push(context);
+  }
+  
+  /*
+   * Pop a JavaScript execution context from the context stack.
+   */
+  static void popContext() {
+    Tracer tracer("JsRootedValue::popContext");
+    JSContext* context = currentContext();
+    contextStack.pop();
+    tracer.log("popped context=%08x", unsigned(context));
+  }
+
+public:
+  /*
+   * This is a helper class used to push/pop JSContext values automatically,
+   * using RAII.  Simply create a ContextManager object on the stack and it
+   * will push the context at creation time and pop it at destruction time,
+   * so you don't have to worry about covering all the exit paths from a
+   * function.
+   */
+  class ContextManager {
+  public:
+    explicit ContextManager(JSContext* context) {
+      JsRootedValue::pushContext(context);
+    }
+    ~ContextManager() {
+      JsRootedValue::popContext();
+    }
+  };
+
+  /*
+   * This is a helper class to manage short-lived roots on the stack, using
+   * RAII to free the roots when no longer needed.
+   */
+  class Temp {
+  private:
+    void* ptr_;
+  public:
+    explicit Temp(void* ptr) : ptr_(ptr) {
+      JS_AddNamedRootRT(runtime, ptr_, "temporary root");
+    }
+    ~Temp() {
+      JS_RemoveRootRT(runtime, ptr_);
+    }
+  };
+  
+  /*
+   * Copy constructor - make another rooted value that refers to the same
+   * JavaScript object (or has the same value if a primitive)
+   */
+  JsRootedValue(const JsRootedValue& rooted_value) : value_(rooted_value.value_)
+  {
+    constructorHelper("JsRootedValue copy ctor");
+  }
+  
+  /*
+   * Create a value with a given jsval value
+   */
+  JsRootedValue(jsval value) : value_(value)
+  {
+    constructorHelper("JsRootedValue jsval ctor");
+  }
+  
+  /*
+   * Create a void value
+   */
+  JsRootedValue() : value_(JSVAL_VOID) {
+    constructorHelper("JsRootedValue void ctor");
+  }
+  
+  /*
+   * Destroy this object.
+   */
+  ~JsRootedValue() {
+    Tracer tracer("~JsRootedValue", this);
+    // ignore error since currently it is not possible to fail
+    JS_RemoveRootRT(runtime, &value_);
+  }
+  
+  /*
+   * Save a pointer to the JSRuntime if we don't have it yet
+   */
+  static void ensureRuntime(JSContext* context) {
+    if(!runtime) runtime = JS_GetRuntime(context);
+  }
+  
+  /*
+   * Return the current JavaScript execution context.
+   */
+  static JSContext* currentContext() {
+    Tracer tracer("JsRootedValue::currentContext");
+    if (contextStack.empty()) {
+      // TODO(jat): better error handling?
+      fprintf(stderr, "JsRootedValue::currentContext - context stack empty\n");
+      ::abort();
+    }
+    JSContext* context = contextStack.top();
+    tracer.log("context=%08x", unsigned(context));
+    return context;
+  }
+
+  /* 
+   * Return the underlying JS object
+   */
+  jsval getValue() const { return value_; }
+  
+  /*
+   * Sets the value of the underlying JS object.
+   * 
+   * Returns false if an error occurred.
+   */
+  bool setValue(jsval new_value) {
+    value_ = new_value;
+    return true;
+  }
+  
+   /*
+   * Returns true if the underlying value is of some number type.
+   */
+  bool isNumber() const {
+    return JSVAL_IS_NUMBER(value_);
+  }
+  /*
+   * Returns the underlying value as a double.
+   * Result is 0.0 if the underlying value is not a number
+   * type.
+   */
+  double getDouble() const {
+    jsdouble return_value=0.0;
+    // ignore return value -- if it fails, value will remain 0.0
+    JS_ValueToNumber(currentContext(), value_, &return_value); 
+    return double(return_value);
+  }
+  /*
+   * Set the underlying value to a double value.
+   * 
+   * Returns false on failure.
+   */
+  bool setDouble(double val) {
+    jsval js_double;
+    if(!JS_NewDoubleValue(currentContext(), jsdouble(val), &js_double)) {
+      return false;
+    }
+    return setValue(js_double);
+  }
+
+  /*
+   * Returns the underlying value as an integer value.  Note that the result
+   * is undefined if isInt() does not return true.
+   */
+  int getInt() {
+    return JSVAL_TO_INT(value_);
+  }
+  
+  /*
+   * Set the underlying value to an integer value.
+   * 
+   * Returns false on failure.
+   */
+  bool setInt(int val) {
+    // check if it fits in 31 bits (ie, top two bits are equal).
+    // if not, store it as a double
+    if ((val & 0x80000000) != ((val << 1) & 0x80000000)) {
+      return setDouble(val);
+    } else {
+      return setValue(INT_TO_JSVAL(val));
+    }
+  }
+  
+  /*
+   * Returns true if the underlying value is a boolean.
+   */
+  bool isBoolean() const {
+    return JSVAL_IS_BOOLEAN(value_);
+  }
+  /*
+   * Returns the underlying value as a boolean.
+   * Result is undefined if the value is not actually
+   * a boolean.
+   */
+  bool getBoolean() const {
+    return value_ != JSVAL_FALSE;
+  }
+  /*
+   * Set the underlying value to a boolean value.
+   * 
+   * Returns false on failure (impossible?).
+   */
+  bool setBoolean(bool val) {
+    return setValue(val ? JSVAL_TRUE : JSVAL_FALSE);
+  }
+
+  /*
+   * Returns true if the underlying value is a string.
+   */
+  bool isInt() const {
+    return JSVAL_IS_INT(value_);
+  }
+  
+  /*
+   * Returns true if the underlying value is a string.
+   */
+  bool isString() const {
+    return JSVAL_IS_STRING(value_);
+  }
+
+  /*
+   * Check if the value is a JavaScript String object.
+   */
+  bool isJavaScriptStringObject() const {
+    if (!isObject()) return false;
+    ensureStringClass();
+    return getObjectClass() == stringClass;
+  }
+  
+  /*
+   * Return this value as a string, converting as necessary.
+   */
+  JSString* asString() const {
+    return JS_ValueToString(currentContext(), value_);
+  }
+  
+  /* Returns the string as a JSString pointer.
+   * Result is undefined if the value is not actually a string or String object.
+   */
+  const JSString* getString() const {
+    if (JSVAL_IS_STRING(value_)) {
+      return JSVAL_TO_STRING(value_);
+    }
+    return asString();
+  }
+  /*
+   * Returns the string as a zero-terminated array of UTF16 characters.
+   * Note that this pointer may become invalid when JS performs GC, so it
+   * may only be used without calling other JS functions.  Result is
+   * undefined if the value is not actually a string.
+   */
+  const wchar_t* getStringChars() const {
+    return reinterpret_cast<const wchar_t*>(JS_GetStringChars(
+        const_cast<JSString*>(getString())));
+  }
+  
+  /*
+   * Returns the length of the underlying string.  Result is undefined
+   * if the value is not actually a string.
+   */
+  int getStringLength() const {
+    return JS_GetStringLength(const_cast<JSString*>(getString()));
+  } 
+  
+  /*
+   * Sets the underlying value, defined by a null-terminated array of UTF16
+   * chars.
+   * 
+   * Returns false on failure.
+   */
+  bool setString(const wchar_t* utf16) {
+    JSString* str = JS_NewUCStringCopyZ(currentContext(),
+        reinterpret_cast<const jschar*>(utf16));
+    return setValue(STRING_TO_JSVAL(str));
+  }
+  
+  /*
+   * Sets the underlying value, defined by a counted array of UTF16 chars.
+   * 
+   * Returns false on failure.
+   */
+  bool setString(const wchar_t* utf16, size_t len) {
+    JSString* str = JS_NewUCStringCopyN(currentContext(),
+        reinterpret_cast<const jschar*>(utf16), len);
+    return setValue(STRING_TO_JSVAL(str));
+  }
+  
+  /*
+   * Returns true if the underlying value is an object.
+   */
+  bool isObject() const {
+    return JSVAL_IS_OBJECT(value_);
+  }
+  
+  /*
+   * Returns the underlying value as an object.
+   * Result is undefined if it is not actually an object.
+   */
+  JSObject* getObject() const {
+    return isObject() ? JSVAL_TO_OBJECT(value_) : 0;
+  }
+  
+  /*
+   * Returns the class name of the underlying value.
+   *
+   * Result is undefined if it is not actually an object.
+   */
+  const JSClass* getObjectClass() const {
+    return isObject() ? JS_GET_CLASS(currentContext(), getObject()) : 0;
+  }
+  
+  /*
+   * Sets the underlying value to be an object.
+   *
+   * Returns false on failure.
+   */
+  bool setObject(JSObject* obj) {
+    return setValue(OBJECT_TO_JSVAL(obj));
+  }
+
+  /*
+   * Returns true if the underlying value is undefined (void).
+   */
+  bool isUndefined() const {
+    return JSVAL_IS_VOID(value_);
+  }
+  
+  /*
+   * Sets the underlying value to be undefined (void).
+   * 
+   * Returns false on failure (impossible?)
+   */
+  bool setUndefined() {
+    return setValue(JSVAL_VOID);
+  }
+  
+  /*
+   * Returns true if the underlying value is null.
+   */
+  bool isNull() const {
+    return JSVAL_IS_NULL(value_);
+  }
+  /*
+   * Sets the underlying value to be null.
+   * 
+   * Returns false on failure (impossible?)
+   */
+  bool setNull() {
+    return setValue(JSVAL_NULL);
+  }
+};
+
+#endif /*JNI_LINUX_JSROOTEDVALUE_H_*/
diff --git a/jni/linux/JsStringWrap.h b/jni/linux/JsStringWrap.h
new file mode 100644
index 0000000..7ab0ce6
--- /dev/null
+++ b/jni/linux/JsStringWrap.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#ifndef JNI_LINUX_JSSTRINGWRAP_H_
+#define JNI_LINUX_JSSTRINGWRAP_H_
+
+/*
+ * Wrapper arouond JavaScript Strings, keeps pointers to unpacked strings
+ * and makes sure they are not cleaned up early. 
+ */
+class JsStringWrap {
+  private:
+    JSContext* context_;
+    JSString* string_;
+    const char* bytes_;
+    const wchar_t* chars_;
+
+  public:
+    JsStringWrap(JSContext* context, JSString* str)
+        : context_(context), string_(str), bytes_(0), chars_(0) {
+      JS_AddRoot(context_, &string_);
+      JS_AddRoot(context_, &bytes_);
+      JS_AddRoot(context_, &chars_);
+    }
+    JsStringWrap(JSContext* context, jsval str)
+        : context_(context), string_(JSVAL_TO_STRING(str)), bytes_(0), chars_(0) {
+      JS_AddRoot(context_, &string_);
+      JS_AddRoot(context_, &bytes_);
+      JS_AddRoot(context_, &chars_);
+    }
+    ~JsStringWrap() {
+      JS_RemoveRoot(context_, &string_);
+      JS_RemoveRoot(context_, &bytes_);
+      JS_RemoveRoot(context_, &chars_);
+    }
+    const char* bytes() {
+      if (!bytes_) bytes_ = JS_GetStringBytes(string_);
+      return bytes_;
+    }
+    const wchar_t* chars() {
+      if (!chars_) {
+        chars_ = reinterpret_cast<wchar_t*>(JS_GetStringChars(string_));
+      }
+      return chars_;
+    }
+    int length() {
+      return JS_GetStringLength(string_);
+    }
+};
+
+#endif // JNI_LINUX_JSSTRINGWRAP_H_
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;
+} 
diff --git a/jni/linux/LowLevelMoz.cpp b/jni/linux/LowLevelMoz.cpp
new file mode 100644
index 0000000..9c3aba2
--- /dev/null
+++ b/jni/linux/LowLevelMoz.cpp
@@ -0,0 +1,380 @@
+/*
+ * 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.
+ */
+
+// Mozilla-specific hosted-mode methods
+
+// Define to log debug-level output rather than just warnings.
+#define DEBUG
+
+#include <cstdio>
+#include <cstdarg>
+#include <cwchar>
+
+// Mozilla header files
+#include "mozilla-headers.h"
+
+#include <jni.h>
+#include "gwt-jni.h"
+#include "JsRootedValue.h"
+#include "ExternalWrapper.h"
+#include "Tracer.h"
+#include "JsStringWrap.h"
+
+/*
+ * Debug definitions -- define FILETRACE to have debug output written to
+ * a file named gwt-ll.log, or JAVATRACE to have debug output passed to the
+ * Java LowLevelMoz.trace method.
+ */
+#ifdef ENABLE_TRACING
+#define FILETRACE
+//#define JAVATRACE
+#endif
+
+// include javah-generated header to make sure we match
+#include "LowLevelMoz.h"
+
+JNIEnv* savedJNIEnv = 0;
+jclass lowLevelMozClass;
+
+// Only include debugging code if we are tracing somewhere.
+#ifdef ENABLE_TRACING
+
+/*
+ * Template so vsnprintf/vswprintf can be used interchangeably in the
+ * append_sprintf template below.
+ *   buf - pointer to the start of the output buffer
+ *   len - maximum number of characters to write into the buffer
+ *         (including the null terminator)
+ *   fmt - printf-style format string
+ *   args - stdarg-style variable arguments list
+ *  Returns the number of characters written (excluding the null terminator)
+ *   or -1 if an error occurred.
+ * 
+ * Note that %lc and %ls are only legal in the wchar_t implementation.
+ */
+template<class charT>
+int safe_vsprintf(charT* buf, size_t len, const charT* fmt, va_list args); 
+
+// specialization for char that maps to vsnprintf
+template<>
+inline int safe_vsprintf<char>(char* buf, size_t len, const char* fmt,
+    va_list args) {
+  return ::vsnprintf(buf, len, fmt, args);
+}
+
+// specialization for wchar_t that maps to vswprintf
+template<>
+inline int safe_vsprintf<wchar_t>(wchar_t* buf, size_t len, const wchar_t* fmt,
+    va_list args) {
+  return ::vswprintf(buf, len, fmt, args);
+}
+
+/*
+ * Safely append to a string buffer, updating the output pointer and always
+ * reserving the last character of the buffer for a null terminator.
+ *   bufStart - pointer to the start of the output buffer
+ *   bufEnd - pointer just past the end of the output buffer
+ *   fmt - format string
+ *   additional arguments as passed to *printf
+ * Returns the number of characters actually written, not including the null
+ * terminator.  Nothing is written, including the null terminator, if the
+ * buffer start points beyond the output buffer.
+ *
+ * Templated to work with any character type that has a safe_vsprintf
+ * implementation.
+ */
+template<class charT>
+static int append_sprintf(charT* bufStart, const charT* bufEnd,
+    const charT* fmt, ...) {
+  va_list args;
+  va_start(args, fmt); // initialize variable arguments list
+  // compute space left in buffer: -1 for null terminator
+  int maxlen = bufEnd - bufStart - 1;
+  if (maxlen <= 0) return 0;
+  int n = safe_vsprintf(bufStart, maxlen, fmt, args);
+  va_end(args);
+  if (n > maxlen) {
+    n = maxlen;
+  }
+  bufStart[n] = 0;
+  return n;
+}
+
+/*
+ * Log a given jsval with a prefix.
+ *  cx - JSContext for the JS execution context to use
+ *  val - jsval to print
+ *  prefix - string to print before the value, defaults to empty string
+ *
+ * TODO(jat): this whole printf-style logging needs to be replaced, but we
+ * run into library version issues if we use C++ iostreams so we would need
+ * to implement our own equivalent.  Given that this code is all likely to
+ * be rewritten for out-of-process hosted mode, it seems unlikely to be worth
+ * the effort until that is completed.
+ */
+void PrintJSValue(JSContext* cx, jsval val, char* prefix="") {
+  JSType type = JS_TypeOfValue(cx, val);
+  const char* typeString=JS_GetTypeName(cx, type);
+  static const int BUF_SIZE = 256;
+  char buf[BUF_SIZE];
+  const char *bufEnd = buf + BUF_SIZE;
+  char* p = buf;
+  p += append_sprintf(p, bufEnd, "%s%s", prefix, typeString);
+  switch(type) {
+    case JSTYPE_VOID:
+      break;
+    case JSTYPE_BOOLEAN:
+      p += append_sprintf(p, bufEnd, ": %s",
+          JSVAL_TO_BOOLEAN(val) ? "true" : "false");
+      break;
+    case JSTYPE_NUMBER:
+      if (JSVAL_IS_INT(val)) {
+        p += append_sprintf(p, bufEnd, ": %d", JSVAL_TO_INT(val));
+      } else {
+        p += append_sprintf(p, bufEnd, ": %lf", (double)*JSVAL_TO_DOUBLE(val));
+      }
+      break;
+    case JSTYPE_OBJECT: {
+      JSObject* obj = JSVAL_TO_OBJECT(val);
+      if (!JSVAL_IS_OBJECT(val)) break;
+      JSClass* clazz = obj ? JS_GET_CLASS(cx, obj) : 0;
+      p += append_sprintf(p, bufEnd, " @ %08x, class %s",
+          (unsigned)obj, clazz ? clazz->name : "<null>");
+      break;
+    }
+    case JSTYPE_FUNCTION:
+    case JSTYPE_LIMIT:
+      break;
+    case JSTYPE_STRING: {
+      /*
+       * TODO(jat): support JS strings with international characters
+       */
+      JsStringWrap str(cx, JSVAL_TO_STRING(val));
+      p += append_sprintf(p, bufEnd, ": %.*s", str.length(), str.bytes());
+      break;
+    }
+  }
+  Tracer::log("%s", buf);
+}
+#else
+// Include a null version just to keep from cluttering up call sites.
+static inline void PrintJSValue(JSContext* cx, jsval val, char* prefix="") { }
+#endif
+
+
+static bool InitGlobals(JNIEnv* env, jclass llClass) {
+  if (savedJNIEnv)
+    return false;
+
+#ifdef FILETRACE
+  Tracer::setFile("gwt-ll.log");
+#endif // FILETRACE
+
+#ifdef JAVATRACE
+  Tracer::setJava(env, llClass);
+#endif // JAVATRACE
+
+#ifdef DEBUG
+  Tracer::setLevel(Tracer::LEVEL_DEBUG);
+#endif
+
+  savedJNIEnv = env;
+  lowLevelMozClass = static_cast<jclass>(env->NewGlobalRef(llClass));
+  return true;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _executeScriptWithInfo
+ * Signature: (ILjava/lang/String;Ljava/lang/String;I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1executeScriptWithInfo
+    (JNIEnv* env, jclass llClass, jint scriptObjectInt, jstring code,
+     jstring file, jint line)
+{
+  Tracer tracer("LowLevelMoz._executeScriptWithInfo");
+  JStringWrap jcode(env, code);
+  if (!jcode.jstr()) {
+    tracer.setFail("null code string");
+    return JNI_FALSE;
+  }
+  JStringWrap jfile(env, file);
+  if (!jfile.str()) {
+    tracer.setFail("null file name");
+    return JNI_FALSE;
+  }
+  tracer.log("code=%s, file=%s, line=%d", jcode.str(), jfile.str(), line);
+  JSContext* cx = JsRootedValue::currentContext();
+  nsCOMPtr<nsIScriptContext> scriptContext(GetScriptContextFromJSContext(cx));
+
+  nsIScriptGlobalObject* scriptObject =
+      NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjectInt);
+  JSObject* scriptWindow =
+      reinterpret_cast<JSObject*>(scriptObject->GetGlobalJSObject());
+  nsXPIDLString scriptString;
+  scriptString = jcode.jstr();
+
+  nsXPIDLString aRetValue;
+  PRBool aIsUndefined;
+  if (NS_FAILED(scriptContext->EvaluateString(scriptString, scriptWindow, 0,
+      jfile.str(), line, 0, aRetValue, &aIsUndefined))) {
+    tracer.setFail("EvaluateString failed");
+    return JNI_FALSE;
+  }
+  return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _invoke
+ * Signature: (ILjava/lang/String;I[I)I
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1invoke
+    (JNIEnv* env, jclass, jint scriptObjInt, jstring methodName, jint jsThisInt,
+     jintArray jsArgsInt, jint jsRetValInt)
+{
+  Tracer tracer("LowLevelMoz._invoke");
+
+  JStringWrap methodStr(env, methodName);
+  if (!methodStr.str()) {
+    tracer.setFail("null method name");
+    return JNI_FALSE;
+  }
+  JsRootedValue* jsThisRV = reinterpret_cast<JsRootedValue*>(jsThisInt);
+  jint jsArgc = env->GetArrayLength(jsArgsInt);
+  tracer.log("method=%s, jsthis=%08x, #args=%d", methodStr.str(), jsThisInt,
+     jsArgc);
+  JSContext* cx = JsRootedValue::currentContext();
+  nsIScriptGlobalObject* scriptObject =
+      NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjInt);
+  JSObject* scriptWindow
+      = reinterpret_cast<JSObject*>(scriptObject->GetGlobalJSObject());
+
+  jsval fval;
+  if (!JS_GetProperty(cx, scriptWindow, methodStr.str(), &fval)) {
+    tracer.setFail("JS_GetProperty(method) failed");
+    return JNI_FALSE;
+  }
+  JSFunction* jsFunction = JS_ValueToFunction(cx, fval);
+  if (!jsFunction) {
+    tracer.setFail("JS_ValueToFunction failed");
+    return JNI_FALSE;
+  }
+  
+  // extract arguments in jsval form
+  nsAutoArrayPtr<jint> jsargvals(new jint[jsArgc]);
+  if (!jsargvals) {
+    tracer.setFail("failed to allocate arg array");
+    return JNI_FALSE;
+  }
+  env->GetIntArrayRegion(jsArgsInt, 0, jsArgc, jsargvals);
+  if (env->ExceptionCheck()) {
+    tracer.setFail("copy from Java array failed");
+    return JNI_FALSE;
+  }
+  nsAutoArrayPtr<jsval> jsargs(new jsval[jsArgc]);
+  for (int i = 0; i < jsArgc; ++i) {
+    JsRootedValue* arg = reinterpret_cast<JsRootedValue*>(jsargvals[i]);
+    jsargs[i] = arg->getValue();
+  }
+
+  jsval jsrval;
+  JSObject* jsThis;
+  if (jsThisRV->isNull()) {
+    jsThis = scriptWindow;
+  } else {
+    jsThis = jsThisRV->getObject();
+  }
+  
+  PrintJSValue(cx, OBJECT_TO_JSVAL(jsThis), "jsThis=");
+  for (int i = 0; i < jsArgc; ++i) {
+    char buf[256];
+    snprintf(buf, sizeof(buf), "arg[%d]=", i);
+    PrintJSValue(cx, jsargs[i], buf);
+  }
+  //tracer.log("fval = %08x, args=%08x", fval, jsargs.get());
+  if (!JS_CallFunctionValue(cx, jsThis, fval, jsArgc, jsargs.get(), &jsrval)) {
+    tracer.setFail("JS_CallFunctionValue failed");
+    return JNI_FALSE;
+  }
+
+  PrintJSValue(cx, jsrval, "return value=");
+  JsRootedValue* returnVal = reinterpret_cast<JsRootedValue*>(jsRetValInt);
+  returnVal->setValue(jsrval);
+  return JNI_TRUE;
+}
+
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _raiseJavaScriptException
+ * Signature: ()Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1raiseJavaScriptException
+    (JNIEnv* env, jclass)
+{
+  Tracer tracer("LowLevelMoz._raiseJavaScriptException");
+  JS_SetPendingException(JsRootedValue::currentContext(), JSVAL_NULL);
+  return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _registerExternalFactoryHandler
+ * Signature: ()Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1registerExternalFactoryHandler
+    (JNIEnv* env, jclass llClass)
+{
+  if (!InitGlobals(env, llClass))
+    return JNI_FALSE;
+
+  // tracing isn't setup until after InitGlobals is called
+  Tracer tracer("LowLevelMoz._registerExternalFactoryHandler");
+
+  char buf[256];
+  sprintf(buf, " jniEnv=%08x, llClass=%08x", (unsigned)env, (unsigned)llClass);
+  tracer.log(buf);
+  
+  // Register "window.external" as our own class
+  if (NS_FAILED(nsComponentManager::RegisterFactory(
+      kGwtExternalCID, "externalFactory", GWT_EXTERNAL_CONTRACTID,
+      new nsRpExternalFactory(), PR_TRUE))) {
+    tracer.setFail("RegisterFactory failed");
+    return JNI_FALSE;
+  }
+
+  nsCOMPtr<nsICategoryManager> categoryManager =
+      do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
+  if (!categoryManager) {
+    tracer.setFail("unable to get category manager");
+    return JNI_FALSE;
+  }
+
+  nsXPIDLCString previous;
+  if (NS_FAILED(categoryManager->AddCategoryEntry(
+      JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY, "external", GWT_EXTERNAL_CONTRACTID,
+      PR_TRUE, PR_TRUE, getter_Copies(previous)))) {
+    tracer.setFail("AddCategoryEntry failed");
+    return JNI_FALSE;
+  }
+
+  return JNI_TRUE;
+}
diff --git a/jni/linux/Makefile b/jni/linux/Makefile
new file mode 100644
index 0000000..8b3a8cf
--- /dev/null
+++ b/jni/linux/Makefile
@@ -0,0 +1,153 @@
+# 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.
+
+##
+# Target settings
+##
+#JAVA_HOME
+#JAVA_HOME=/usr/lib/j2sdk1.5-sun
+
+# set GWT_TOOLS only if it is not already defined
+GWT_TOOLS ?= ../../../tools
+
+GWT_ROOT = ../../
+OBJDIR  := $(GWT_ROOT)build/out/jni/linux/
+OUTDIR  := $(GWT_ROOT)build/jni/linux/
+OUT     := $(OUTDIR)libgwt-ll.so
+STAGING := $(GWT_ROOT)build/staging/gwt-linux-0.0.0/
+
+##
+# The location to get .class files from for javah
+##
+CLASSDIR := $(GWT_ROOT)build/out/dev/linux/bin
+
+# use this instead if you want to use eclipse to build the class files during
+# development
+#CLASSDIR := $(GWT_ROOT)eclipse/dev/linux/bin
+
+##
+# Tools
+##
+CXX      := g++
+AR       := ar
+STRIP    := strip
+LD       := $(CXX)
+JAVAH    := $(JAVA_HOME)/bin/javah
+
+##
+# List of source, object, and dependency paths plus the path to them
+##
+SRCDIRS := ./:../core/
+VPATH   := .:../core
+SRCS    := gwt-ll.cpp LowLevelMoz.cpp JsValueMoz.cpp Tracer.cpp \
+	ExternalWrapper.cpp NativeWrapper.cpp JsRootedValue.cpp
+OBJS    := $(addprefix $(OBJDIR),$(SRCS:.cpp=.o))
+DEPS    := $(addprefix $(OBJDIR),$(SRCS:.cpp=.d))
+
+MOZDIR = $(GWT_TOOLS)/sdk/mozilla-1.7.12
+MOZINC = $(MOZDIR)/include
+MOZLIB = $(MOZDIR)/lib
+
+##
+# Include path configuration
+##
+SYSINCS := \
+    $(JAVA_HOME)/include \
+    $(JAVA_HOME)/include/linux \
+    $(MOZINC) $(MOZINC)/extra
+
+INCS := $(OBJDIR)
+INCS := $(addprefix -I ,$(INCS)) $(addprefix -isystem ,$(SYSINCS))
+
+##
+# Libraries and library path
+##
+LIBS    = xpcomglue_s
+LIBPATH = -L$(MOZLIB)
+LIBS     := $(addprefix -l,$(LIBS))
+
+# for notes on auto-dependency generation, see
+#   http://make.paulandlesley.org/autodep.html
+# -MP obviates the need for sed hackery
+CFLAGS   := -ggdb -m32 -Os -fPIC -fno-omit-frame-pointer -fno-strict-aliasing -D_REENTRANT -MMD -MP -Wno-system-headers $(CFLAGS)
+LDFLAGS  := -ggdb -m32 -s -fPIC -fno-omit-frame-pointer -fno-strict-aliasing -D_REENTRANT -Wl,-shared-gcc $(LDFLAGS)
+
+#-------------------------------------------------------------------------------
+# Rules
+#-------------------------------------------------------------------------------
+
+##
+# default rule
+##
+all: $(OUT)
+
+# install into prebuilt directory
+install: $(OUT)
+	cp $(OUT) prebuilt/
+
+##
+# Include the dependency rules
+##
+-include $(DEPS)
+
+##
+# javah-generated headers for native methods
+##
+$(OBJDIR)LowLevelMoz.h : $(CLASSDIR)/com/google/gwt/dev/shell/moz/LowLevelMoz.class
+	$(JAVAH) -classpath $(CLASSDIR) -o $(OBJDIR)LowLevelMoz.h com.google.gwt.dev.shell.moz.LowLevelMoz
+
+$(OBJDIR)JsValueMoz.h : $(CLASSDIR)/com/google/gwt/dev/shell/moz/JsValueMoz.class
+	$(JAVAH) -classpath $(CLASSDIR) -o $(OBJDIR)JsValueMoz.h com.google.gwt.dev.shell.moz.JsValueMoz
+
+##
+# Dependency rules for generated headers
+# TODO(jat): autogenerate these and others
+##
+$(OBJDIR)LowLevelMoz.o: $(OBJDIR)LowLevelMoz.h $(JAVA_HOME)/include/jni.h
+$(OBJDIR)JsValueMoz.o: $(OBJDIR)JsValueMoz.h $(JAVA_HOME)/include/jni.h
+
+##
+# Compilation rule for cpp files
+##
+$(OBJDIR)%.o : $(SRCDIR)%.cpp
+	@[ -d $(OBJDIR) ] || mkdir -p $(OBJDIR)
+	$(CXX) -c $(CFLAGS) $(INCS) -o $@ $<
+
+# generate preprocessed output files upon request for debugging
+%.i : $(SRCDIR)%.cpp
+	$(CXX) -E $(CFLAGS) $(INCS) -o $@ $<
+
+%.I : $(SRCDIR)%.cpp
+	$(CXX) -E -dDI $(CFLAGS) $(INCS) -o $@ $<
+
+##
+# Actual output file
+##
+$(OUT): $(OBJS) $(MOZLIB)/libxpcomglue_s.a
+	@[ -d $(OUTDIR) ] || mkdir -p $(OUTDIR)
+	$(LD) -shared $(LDFLAGS) $(LIBPATH) -o $@ $^ $(LIBS)
+	$(STRIP) --strip-unneeded $@
+
+##
+# copy to staging area for hosted-mode development
+##
+staging: $(OUT)
+	@[ -d $(STAGING) ] || mkdir -p $(STAGING)
+	cp $(OUT) $(STAGING)
+
+##
+# Clean rule
+##
+clean:
+	@-rm -rf $(OBJDIR) $(OUT)
diff --git a/jni/linux/NativeWrapper.cpp b/jni/linux/NativeWrapper.cpp
new file mode 100644
index 0000000..38958d0
--- /dev/null
+++ b/jni/linux/NativeWrapper.cpp
@@ -0,0 +1,211 @@
+/*
+ * 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.
+ */
+
+/*
+ * Defines the JavaScript classes gwt_nativewrapper_class and
+ * gwt_functionwrapper_class, which interface via JNI to Java objects.
+ */
+
+#include <jni.h>
+#include "JsRootedValue.h"
+#include "gwt-jni.h"
+#include "Tracer.h"
+
+/*
+ * Helper function to get reference Java attributes from Javascript.
+ * 
+ * cx - JSContext pointer
+ * obj - JavaScript object which is a wrapped Java object
+ * id - property name, as a jsval string
+ * dispClass - output parameter of DispatchMethod subclass
+ * dispObj - output parameter of Java object
+ * jident - output parameter of property name as a Java string
+ */
+static JSBool getJavaPropertyStats(JSContext *cx, JSObject *obj, jsval id,
+    jclass& dispClass, jobject& dispObj, jstring& jident)
+{
+  Tracer tracer("getJavaPropertyStats");
+  if (!JSVAL_IS_STRING(id)) {
+    tracer.setFail("id is not a string");
+    return JS_FALSE;
+  }
+
+  jident = savedJNIEnv->NewString(JS_GetStringChars(JSVAL_TO_STRING(id)),
+      JS_GetStringLength(JSVAL_TO_STRING(id)));
+  if (!jident || savedJNIEnv->ExceptionCheck()) {
+    tracer.setFail("unable to create Java string");
+    return JS_FALSE;
+  }
+
+  dispObj = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+  if (!dispObj) {
+    tracer.setFail("can't get dispatch object");
+    return JS_FALSE;
+  }
+
+  dispClass = savedJNIEnv->GetObjectClass(dispObj);
+  if (savedJNIEnv->ExceptionCheck()) {
+    tracer.setFail("can't get class of dispatch object");
+    return JS_FALSE;
+  }
+
+  return JS_TRUE;
+}
+  
+/*
+ * 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;
+}
+
+static JSBool JS_DLL_CALLBACK gwt_nativewrapper_getProperty(JSContext *cx,
+    JSObject *obj, jsval id, jsval *vp)
+{
+  Tracer tracer("gwt_nativewrapper_getProperty");
+  tracer.log("context=%08x, obj=%08x", unsigned(cx), unsigned(obj));
+  JsRootedValue::ContextManager context(cx);
+
+  jclass dispClass;
+  jobject dispObj;
+  jstring ident;
+  if (!getJavaPropertyStats(cx, obj, id, dispClass, dispObj, ident)) {
+    tracer.setFail("getJavaPropertyStats failed");
+    return JS_FALSE;
+  }
+  JsRootedValue* js_rooted_value = GetFieldAsRootedValue(cx, dispClass,
+      dispObj, ident);
+  if (!js_rooted_value) {
+    tracer.setFail("can't get field");
+    return JS_FALSE;
+  }
+  *vp = js_rooted_value->getValue();
+  return JS_TRUE;
+}
+
+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) {
+    // 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)
+{
+  Tracer tracer("gwt_nativewrapper_setProperty");
+  tracer.log("context=%08x", unsigned(cx));
+  JsRootedValue::ContextManager context(cx);
+  jclass dispClass;
+  jobject dispObj;
+  jstring ident;
+  if (!getJavaPropertyStats(cx, obj, id, dispClass, dispObj, ident)) {
+    tracer.setFail("getJavaPropertyStats failed");
+    return JS_FALSE;
+  }
+  JsRootedValue* js_rooted_value = new JsRootedValue(*vp); 
+  if (!SetFieldFromRootedValue(cx, dispClass, dispObj, ident,
+      js_rooted_value)) {
+    tracer.setFail("can't set field");
+    return JS_FALSE;
+  }
+  return JS_TRUE;
+}
+
+JSClass gwt_nativewrapper_class = {
+  "gwt_nativewrapper_class", JSCLASS_HAS_PRIVATE,
+  JS_PropertyStub, JS_PropertyStub, gwt_nativewrapper_getProperty,
+  gwt_nativewrapper_setProperty, JS_EnumerateStub, JS_ResolveStub,
+  JS_ConvertStub, gwt_nativewrapper_finalize,
+  JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+JSClass gwt_functionwrapper_class = {
+  "gwt_functionwrapper_class", JSCLASS_HAS_PRIVATE,
+  JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, gwt_nativewrapper_finalize,
+  JSCLASS_NO_OPTIONAL_MEMBERS
+};
diff --git a/jni/linux/Tracer.cpp b/jni/linux/Tracer.cpp
new file mode 100644
index 0000000..e5f3189
--- /dev/null
+++ b/jni/linux/Tracer.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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 "Tracer.h"
+
+#ifdef ENABLE_TRACING
+
+// initialize static fields
+FILE* Tracer::outfp = 0;
+JNIEnv* Tracer::jniEnv = 0;
+jclass Tracer::traceClass;
+jmethodID Tracer::traceMethod;
+int Tracer::indentation = 0;
+Tracer::LogLevel Tracer::logLevel = Tracer::LEVEL_WARNING;
+
+/*
+ * Sets a JNI environment and Java class to pass trace messages to.
+ * 
+ * env - JNI environment to use for trace calls
+ * clazz - Java class, which must provide static void trace(String)
+ */
+bool Tracer::setJava(JNIEnv* env, jclass clazz) {
+  jniEnv = env;
+  if (!env) {
+    return true;
+  }
+  traceClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+  if (!traceClass || env->ExceptionCheck()) {
+    return false;
+  }
+  traceMethod = env->GetStaticMethodID(traceClass, "trace",
+    "(Ljava/lang/String;)V");
+  if (!traceMethod || env->ExceptionCheck()) {
+    return false;
+  }
+
+  jstring msg = jniEnv->NewStringUTF("== Java trace started ==");
+  jniEnv->CallStaticVoidMethod(traceClass, traceMethod, msg);
+  return true;
+}
+
+#endif // ENABLE_TRACING
+
+/*
+ * Throw a HostedModeException and log a failure message.
+ * 
+ * Creates a new HostedModeException with the failure message,
+ * and also logs the failure message 
+ * 
+ * env - JNI environment to throw the exception in
+ * msg - failure message 
+ */
+void Tracer::throwHostedModeException(JNIEnv* env, const char* msg) {
+#ifdef ENABLE_TRACING
+  setFail(msg);
+#endif // ENABLE_TRACING
+  jclass exceptionClass
+      = env->FindClass("com/google/gwt/dev/shell/HostedModeException");
+  env->ThrowNew(exceptionClass, msg);
+}
diff --git a/jni/linux/Tracer.h b/jni/linux/Tracer.h
new file mode 100644
index 0000000..ef9fd7d
--- /dev/null
+++ b/jni/linux/Tracer.h
@@ -0,0 +1,297 @@
+/*
+ * 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.
+ */
+#ifndef JNI_LINUX_TRACER_H_
+#define JNI_LINUX_TRACER_H_
+
+#include <cstdio>
+#include <cstdarg>
+#include <cstring>
+#include <jni.h>
+
+// comment this out to remove almost all runtime overhead (with usual compiler
+// support) from tracing.
+//#define ENABLE_TRACING
+
+/*
+ * Utility class for tracing.  This class is intended to be used as follows:
+ * 
+ * {
+ *   Tracer tracer("method name");
+ *   ... do work
+ *   if (fail) {
+ *      tracer.setFail("failure explanation");
+ *      return;
+ *   }
+ *   if (fail2) {
+ *      tracer.throwHostedModeException("failure explanation");
+ *      return;
+ *   }
+ *   return;
+ * }
+ * 
+ * The class automatically logs an enter message when it is created, as well
+ * as leave/fail messages when it is destroyed.  Logging is performed to a
+ * file or to a Java static member function on a class (or both) -- these
+ * are configured by using static member functions setFile() and setJava().
+ * 
+ * This class knows about the Java class
+ *   com.google.gwt.dev.shell.HostedModeException
+ * and throws a new instance of that exception if requested.
+ */
+class Tracer {
+public:
+  enum LogLevel {
+    LEVEL_ERROR = 0,
+    LEVEL_WARNING,
+    LEVEL_NOTICE,
+    LEVEL_INFO,
+    LEVEL_DEBUG,
+    LEVEL_DEBUG_V1,
+    LEVEL_DEBUG_V2,
+  };
+protected:
+#ifdef ENABLE_TRACING
+  // static variables that specify where logging is performed.  This are
+  // set by calling setFile() and setJava().
+  static FILE*     outfp;
+  static JNIEnv*   jniEnv;
+  static jclass    traceClass;
+  static jmethodID traceMethod;
+  static int       indentation;
+  static LogLevel  logLevel;
+
+  // method is set when the instance is created.
+  const char*		method_;
+  // fail_msg is set to indicate a failure has occurred.
+  const char*		fail_msg_;
+  // level of this trace object
+  LogLevel  log_level_;
+#endif
+  
+public:
+  /*
+   * Set the logging level.
+   */
+  static void setLevel(LogLevel level) {
+#ifdef ENABLE_TRACING
+    logLevel = level;
+#endif
+  }
+  
+protected:
+  /*
+   * Log a message (with supplied prefix) to the configured file.
+   * Only called if a file was specified and successfully opened for writing.
+   */
+  static void logFile(const char* msg) {
+#ifdef ENABLE_TRACING
+    for (int i = 0; i < indentation; ++i) {
+      putc(' ', outfp);
+    }
+    fputs(msg, outfp);
+    putc('\n', outfp);
+    fflush(outfp);
+#else
+    (void)msg; // avoid unused warning
+#endif
+  }
+
+  /*
+   * Log a message (with supplied prefix) to the configured Java class.
+   * Only called if a file was specified and successfully accessed.
+   * 
+   * Call static void trace(String msg) on the configured class. 
+   */
+  static void logJava(const char* msg) {
+#ifdef ENABLE_TRACING
+    // TODO(jat): fixed buffer size
+    char buf[512];
+    for (int i = 0; (i < indentation) && (i < int(sizeof(buf))); ++i) {
+      buf[i] = ' ';
+    }
+    strncpy(buf + indentation, msg, sizeof(buf) - indentation);
+    buf[sizeof(buf) - 1] = 0; // ensure null termination
+    jstring str = jniEnv->NewStringUTF(buf);
+    jniEnv->CallStaticVoidMethod(traceClass, traceMethod, str);
+#else
+    (void)msg; // avoid unused warning
+#endif
+  }
+
+  /*
+   * Log a message to a file and/or class with the default logging level.
+   * 
+   * If the preprocessor symbol DISABLE_TRACING has been defined, this is
+   * completely removed from the code path.
+   */
+  void logPrefix(const char* prefix) {
+#ifdef ENABLE_TRACING
+    logPrefix(prefix, log_level_);
+#else
+    (void)prefix; // avoid unused warning
+#endif
+  }
+  
+  /*
+   * Log a message to a file and/or class.
+   * 
+   * If the preprocessor symbol DISABLE_TRACING has been defined, this is
+   * completely removed from the code path.
+   */
+  void logPrefix(const char* prefix, LogLevel level) {
+#ifdef ENABLE_TRACING
+    if (level>logLevel) return;
+    log("%-5.5s %s%s%s", prefix, method_, fail_msg_ ? ": " : "",
+        fail_msg_ ? fail_msg_ : "");
+#endif
+  }
+    
+public:
+  /*
+   * Create an instance with the specified method name and no failure
+   * message.  Log an ENTER message.
+   */
+  Tracer(const char* method, LogLevel log_level = LEVEL_ERROR)
+#ifdef ENABLE_TRACING
+      : method_(method), fail_msg_(0), log_level_(log_level) {
+    log("ENTER %s", method);
+    indentation++;
+#else
+  { (void)method; (void)log_level; // avoid unused warnings
+#endif
+  }
+
+  /*
+   * Create an instance with the specified method name and no failure
+   * message.  Log an ENTER message and the this pointer.
+   */
+  Tracer(const char* method, const void* objThis,
+      LogLevel log_level = LEVEL_ERROR)
+#ifdef ENABLE_TRACING
+      : method_(method), fail_msg_(0), log_level_(log_level) {
+    log("ENTER %s(this=%08x)", method, unsigned(objThis));
+    indentation++;
+#else
+  { (void)method; (void)objThis; (void)log_level; // avoid unused warnings
+#endif
+  }
+
+  /*
+   * Destroy the instance and log a fail or leave message.
+   */
+  ~Tracer() {
+#ifdef ENABLE_TRACING
+    --indentation;
+    if(fail_msg_) {
+      logPrefix("*FAIL", LEVEL_ERROR);
+    } else {
+      logPrefix("LEAVE");
+    }
+#endif
+  }
+  
+  /*
+   * Specify a filename to receive logging output.  Close any previously
+   * opened file.  If a null filename is passed, disable logging to a
+   * file.
+   * 
+   * filename - the file path to receive logging output.  This file is
+   *     truncated if it already exists.
+   * 
+   * Returns false on failure.
+   */
+  static bool setFile(const char* filename) {
+#ifdef ENABLE_TRACING
+    if (outfp) {
+      fclose(outfp);
+      outfp = 0;
+    }
+    if (!filename) {
+      return true;
+    }
+    outfp = fopen(filename, "w");
+    if (!outfp) {
+      return false;
+    }
+    fprintf(outfp, "== started logging ==\n");
+    fflush(outfp);
+#else
+    (void)filename; // avoid unused warning
+#endif
+    return true;
+  }
+  
+  /*
+   * Specify a Java class to receive logging output.  The supplied class
+   * must have a static void trace(String) member function which is called
+   * for output.  Logging to a Java class is disabled if the supplied JNI
+   * environment is null.
+   * 
+   * env - JNI environment
+   * clazz - the Java class to receive logging output
+   * 
+   * Returns false on failure.
+   */ 
+  static bool setJava(JNIEnv* env, jclass clazz)
+#ifdef ENABLE_TRACING  
+  ;
+#else
+  // inline a null body if we aren't debugging; avoid unused warnings
+  { (void)env; (void)clazz; return true; }
+#endif
+  
+  /*
+   * Set a failure message, overwriting any previously specified failure
+   * message.  Passing a null string will remove any previous failure
+   * notification.
+   */
+  void setFail(const char* fail_msg) {
+#ifdef ENABLE_TRACING
+    fail_msg_ = fail_msg;
+#else
+    (void)fail_msg; // avoid unused warning
+#endif
+  }
+  
+  /*
+   * Throw a Java HostedModeException as well as set a failure message to
+   * be logged.
+   * 
+   * env - JNI environment to throw exception into
+   * fail_msg - failure message 
+   */
+  void throwHostedModeException(JNIEnv* env, const char* fail_msg);
+  
+  /*
+   * Log an arbitrary message.
+   */
+  static void log(const char* format, ...) {
+#ifdef ENABLE_TRACING
+    va_list args;
+    va_start(args, format);
+    char msg[512]; // TODO(jat): fixed size buffer
+    vsnprintf(msg, sizeof(msg), format, args);
+    msg[sizeof(msg) - 1] = 0; // ensure null termination
+    if(outfp) logFile(msg);
+    if(jniEnv) logJava(msg);
+    va_end(args);
+#else
+    (void)format; // avoid unused warning
+#endif
+  }
+};
+
+#endif /* JNI_LINUX_TRACER_H_ */
diff --git a/jni/linux/build.xml b/jni/linux/build.xml
new file mode 100755
index 0000000..5f0db6b
--- /dev/null
+++ b/jni/linux/build.xml
@@ -0,0 +1,18 @@
+<project name="jni-linux" default="build" basedir=".">
+  <property name="gwt.root" location="../.." />
+  <property name="project.tail" value="jni/linux" />
+  <import file="${gwt.root}/common.ant.xml" />
+
+  <target name="build" description="Builds a JNI lib">
+    <mkdir dir="${project.jni}" />
+    <!-- TODO: Actually build this from source! -->
+    <copy todir="${project.jni}">
+      <fileset dir="prebuilt" />
+    </copy>
+  </target>
+
+  <target name="clean" description="Cleans this project's intermediate and output files">
+    <delete dir="${project.build}" failonerror="false" />
+    <delete dir="${project.jni}" failonerror="false" />
+  </target>
+</project>
diff --git a/jni/linux/gwt-jni.h b/jni/linux/gwt-jni.h
new file mode 100644
index 0000000..c477f1c
--- /dev/null
+++ b/jni/linux/gwt-jni.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+#ifndef JNI_LINUX_GWT_JNI_H_
+#define JNI_LINUX_GWT_JNI_H_
+
+#include <jni.h>
+#include "JsRootedValue.h"
+#include "JStringWrap.h"
+
+extern JNIEnv* savedJNIEnv;
+extern jclass lowLevelMozClass;
+
+extern nsCID kGwtExternalCID;
+
+// JavaScript class objects
+extern JSClass gwt_nativewrapper_class;
+extern JSClass gwt_functionwrapper_class;
+
+#endif /*JNI_LINUX_GWT_JNI_H_*/
diff --git a/jni/linux/mozilla-headers.h b/jni/linux/mozilla-headers.h
new file mode 100644
index 0000000..6259b41
--- /dev/null
+++ b/jni/linux/mozilla-headers.h
@@ -0,0 +1,30 @@
+/*
+ * 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 all of the necessary Mozilla headers.
+#include "mozilla-config.h"
+#include "nsIServiceManagerUtils.h"
+#include "nsComponentManagerUtils.h"
+#include "nsICategoryManager.h"
+#include "nsIScriptNameSpaceManager.h"
+#include "nsIScriptObjectOwner.h"
+#include "nsIScriptGlobalObject.h"
+#include "nsIScriptContext.h"
+#include "nsIDOMWindow.h"
+#include "nsIXPConnect.h"
+#include "nsIFactory.h"
+#include "nsCOMPtr.h"
+#include "nsAutoPtr.h"
diff --git a/jni/linux/prebuilt/libgwt-ll.so b/jni/linux/prebuilt/libgwt-ll.so
new file mode 100755
index 0000000..97ead651
--- /dev/null
+++ b/jni/linux/prebuilt/libgwt-ll.so
Binary files differ
diff --git a/jni/mac/JStringWrap.h b/jni/mac/JStringWrap.h
new file mode 100644
index 0000000..e17981f
--- /dev/null
+++ b/jni/mac/JStringWrap.h
@@ -0,0 +1,42 @@
+/* 
+ * 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.
+ */
+#ifndef JSTRINGWRAP_H
+#define JSTRINGWRAP_H
+
+#include <jni.h>
+
+/*
+ * Wrap a Java String and automatically clean up temporary storage allocated
+ * for accessing its contents.
+ */
+struct JStringWrap
+{
+  JStringWrap(JNIEnv* env, jstring str): env(env), s(str), p(0), jp(0) { }
+  ~JStringWrap() {
+  	if (p) env->ReleaseStringUTFChars(s, p);
+  	if (jp) env->ReleaseStringChars(s, jp);
+  }
+  const char* str() { if (!p) p = env->GetStringUTFChars(s, 0); return p; }
+  const jchar* jstr() { if (!jp) jp = env->GetStringChars(s, 0); return jp; }
+  jsize length() { return env->GetStringLength(s); }
+private:
+  JNIEnv* env;
+  jstring s;
+  const char* p;
+  const jchar* jp;
+};
+
+#endif
diff --git a/jni/mac/Makefile b/jni/mac/Makefile
new file mode 100644
index 0000000..867b511
--- /dev/null
+++ b/jni/mac/Makefile
@@ -0,0 +1,89 @@
+# Copyright 2008 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.
+
+CC = g++
+JAVAH = javah
+
+##
+# Try a GWT_TOOLS default if it isn't set
+##
+GWT_TOOLS ?= ../../../tools
+GWT_ROOT ?= ../..
+
+##
+# The location to get .class files for javah
+##
+CLASSDIR := $(GWT_ROOT)/build/out/dev/mac/bin
+
+##
+# External SWT products.
+##
+SWT_ORIGINAL_SRC = $(GWT_TOOLS)/lib/eclipse/org.eclipse.swt.carbon-macosx-3.2.1.src.zip
+SWT_PATCH_DIR = ./swt-build
+SWT_LIBS=$(SWT_PATCH_DIR)/libswt-webkit-carbon-3235.jnilib \
+	$(SWT_PATCH_DIR)/libswt-agl-carbon-3235.jnilib \
+	$(SWT_PATCH_DIR)/libswt-carbon-3235.jnilib \
+	$(SWT_PATCH_DIR)/libswt-pi-carbon-3235.jnilib
+
+GWT_LL_LIB = libgwt-ll.jnilib
+GWT_LL_OBJS = gwt-ll.o java-dispatch.o gwt-webkit.o trace.o
+GWT_LL_JNI = gwt-webkit.h
+
+TARGETS = $(GWT_LL_LIB) $(SWT_LIBS)
+ARCHS = -arch i386 -arch ppc
+CFLAGS = -I/System/Library/Frameworks/JavaScriptCore.framework/Headers -I/System/Library/Frameworks/JavaVM.framework/Headers
+LFLAGS = -bundle -framework JavaScriptCore
+
+ALL : $(TARGETS)
+
+##
+# Unpack and patch SWT source.
+##
+$(SWT_PATCH_DIR): $(SWT_ORIGINAL_SRC) ./org.eclipse.swt/webkit.c
+	unzip $(SWT_ORIGINAL_SRC) -d $(SWT_PATCH_DIR)
+	cp ./org.eclipse.swt/webkit.c  $(SWT_PATCH_DIR)
+
+##
+# Build SWT.
+##
+$(SWT_LIBS):$(SWT_PATCH_DIR)
+	make -C $(SWT_PATCH_DIR) -f make_macosx.mak
+
+##
+# Build core gwt-ll object.
+##
+gwt-ll.o : ../core/gwt-ll.cpp
+	$(CC) -c -Wall -o $@ $(ARCHS) $(CFLAGS) $<
+
+##
+# General coff target.
+##
+%.o : %.cpp
+	$(CC) -c -Wall -o $@ $(ARCHS) $(CFLAGS) $<
+
+##
+# Generate JNI Header
+##
+gwt-webkit.h : $(CLASSDIR)/com/google/gwt/dev/shell/mac/LowLevelSaf.class
+	$(JAVAH) -classpath $(CLASSDIR) -o gwt-webkit.h com.google.gwt.dev.shell.mac.LowLevelSaf
+
+##
+# Build gwt-ll library.
+##
+$(GWT_LL_LIB) : $(GWT_LL_JNI) $(GWT_LL_OBJS)
+	$(CC) -Wall -o $@ $(ARCHS) $(LFLAGS) $(GWT_LL_OBJS)
+
+clean:
+	rm -f $(GWT_LL_JNI) $(GWT_LL_OBJS) $(TARGETS)
+	rm -rf $(SWT_PATCH_DIR)
diff --git a/jni/mac/build.xml b/jni/mac/build.xml
new file mode 100755
index 0000000..66b6580
--- /dev/null
+++ b/jni/mac/build.xml
@@ -0,0 +1,18 @@
+<project name="jni-mac" default="build" basedir=".">
+  <property name="gwt.root" location="../.." />
+  <property name="project.tail" value="jni/mac" />
+  <import file="${gwt.root}/common.ant.xml" />
+
+  <target name="build" description="Builds a JNI lib">
+    <mkdir dir="${project.jni}" />
+    <!-- TODO: Actually build this from source! -->
+    <copy todir="${project.jni}">
+      <fileset dir="prebuilt" />
+    </copy>
+  </target>
+
+  <target name="clean" description="Cleans this project's intermediate and output files">
+    <delete dir="${project.build}" failonerror="false" />
+    <delete dir="${project.jni}" failonerror="false" />
+  </target>
+</project>
diff --git a/jni/mac/gwt-webkit.cpp b/jni/mac/gwt-webkit.cpp
new file mode 100644
index 0000000..477b312
--- /dev/null
+++ b/jni/mac/gwt-webkit.cpp
@@ -0,0 +1,886 @@
+/*
+ * Copyright 2008 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 <iostream>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include "gwt-webkit.h"
+#include "JStringWrap.h"
+#include "java-dispatch.h"
+#include "trace.h"
+
+
+// http://unixjunkie.blogspot.com/2006/07/access-argc-and-argv-from-anywhere.html
+extern "C" int *_NSGetArgc(void);
+extern "C" char ***_NSGetArgv(void);
+
+/*
+ *
+ */
+JSContextRef ToJSContextRef(jint context) {
+  return reinterpret_cast<JSContextRef>(context);
+}
+
+/*
+ *
+ */
+JSValueRef ToJSValueRef(jint value) {
+  return reinterpret_cast<JSValueRef>(value);
+}
+
+/*
+ *
+ */
+JSObjectRef ToJSObjectRef(JSContextRef jsContext, jint object,
+    JSValueRef* jsException) {
+  JSValueRef jsValue = reinterpret_cast<JSValueRef>(object);
+  if (!jsValue || !JSValueIsObject(jsContext, jsValue)) {
+    return NULL;
+  }
+  return JSValueToObject(jsContext, jsValue, jsException);
+}
+
+/*
+ *
+ */
+JSObjectRef ToJSObjectRef(JSContextRef jsContext, JSValueRef jsValue,
+    JSValueRef* jsException) {
+  if (!jsValue || !JSValueIsObject(jsContext, jsValue)) {
+    return NULL;
+  }
+  return JSValueToObject(jsContext, jsValue, jsException);
+}
+
+/*
+ *
+ */
+JSObjectRef GetStringConstructor(JSContextRef jsContext,
+    JSValueRef* jsException) {
+  // This could only be cached relative to jsContext.
+  JSStringRef script = JSStringCreateWithUTF8CString("(String)");
+  JSValueRef ctorVal = JSEvaluateScript(jsContext, script, NULL, NULL, 0, jsException);
+  JSStringRelease(script);
+  return ToJSObjectRef(jsContext, ctorVal, jsException);
+}
+
+/*
+ *
+ */
+bool IsObjectOfStringConstructor(JSContextRef jsContext, JSValueRef jsValue,
+    JSValueRef* jsException) {
+  JSObjectRef jsObject = ToJSObjectRef(jsContext, jsValue, jsException);
+  if (!jsObject) {
+    return false;
+  }
+  JSObjectRef stringCtor = GetStringConstructor(jsContext, jsException);
+  if (!stringCtor) {
+    return false;
+  }
+  return JSValueIsInstanceOfConstructor(jsContext, jsObject, stringCtor,
+      jsException);
+}
+
+#if 0 // For debugging purposes only.
+void PrintJSString(JSStringRef jsString)
+{
+  size_t length = JSStringGetMaximumUTF8CStringSize(jsString);
+  char* buffer = new char[length];
+  JSStringGetUTF8CString(jsString, buffer, length);
+  std::cerr << "JSString: " << buffer << std::endl;
+  delete[] buffer;
+}
+
+void PrintJSValue(JSContextRef jsContext, JSValueRef jsValue)
+{
+  JSValueRef jsException = NULL;
+  JSStringRef jsResult = JSValueToStringCopy(jsContext, jsValue,
+      &jsException);
+  if (!jsException && jsValue) {
+    PrintJSString(jsResult);
+  } else {
+    std::cerr << "Could not convert the value to string." << std::endl;
+  }
+}
+#endif
+
+/*
+ *
+ */
+JSStringRef ToJSStringRef(JNIEnv* env, jstring jstr) {
+  if (!jstr) {
+    return NULL;
+  }
+
+  JStringWrap jstrw(env, jstr);
+  if (!jstrw.jstr()) {
+    return NULL;
+  }
+
+  return JSStringCreateWithCharacters(static_cast<const JSChar*>(jstrw.jstr()),
+      static_cast<size_t>(jstrw.length()));
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsNull
+    (JNIEnv *env, jclass klass, jint context, jint value) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+  TR_LEAVE();
+  return static_cast<jboolean>(JSValueIsNull(jsContext, jsValue));
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsUndefined
+    (JNIEnv *env, jclass klass, jint context, jint value) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+  TR_LEAVE();
+  return static_cast<jboolean>(JSValueIsUndefined(jsContext, jsValue));
+}
+
+/*
+ *
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getJsUndefined
+    (JNIEnv *env, jclass klass, jint context) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  if (!jsContext) {
+    return static_cast<jint>(NULL);
+  }
+
+  JSValueRef jsUndefined = JSValueMakeUndefined(jsContext);
+  JSValueProtectChecked(jsContext, jsUndefined);
+  TR_LEAVE();
+  return reinterpret_cast<jint>(jsUndefined);
+}
+
+/*
+ *
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getJsNull
+    (JNIEnv *env, jclass klass, jint context) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  if (!jsContext) {
+    return static_cast<jint>(NULL);
+  }
+  JSValueRef jsNull = JSValueMakeNull(jsContext);
+  JSValueProtectChecked(jsContext, jsNull);
+  TR_LEAVE();
+  return reinterpret_cast<jint>(jsNull);
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsBoolean
+    (JNIEnv *env, jclass klass, jint context, jint value) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+  TR_LEAVE();
+  return static_cast<jboolean>(JSValueIsBoolean(jsContext, jsValue));
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsNumber
+    (JNIEnv *env, jclass klass, jint context, jint value) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+  TR_LEAVE();
+  return static_cast<jboolean>(JSValueIsNumber(jsContext, jsValue));
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toJsBooleanImpl
+    (JNIEnv *env, jclass klass, jint context, jboolean jValue, jintArray rval) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  if (!jsContext) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueRef jsValue = JSValueMakeBoolean(jsContext, static_cast<bool>(jValue));
+
+  env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<const jint*>(&jsValue));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+  JSValueProtectChecked(jsContext, jsValue);
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_gcUnprotect
+    (JNIEnv *env, jclass klass, jint context, jint value) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    return;
+  }
+  JSValueUnprotectChecked(jsContext, jsValue);
+  TR_LEAVE();
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toJsNumberImpl
+    (JNIEnv *env, jclass klass, jint context, jdouble jValue, jintArray rval) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  if (!jsContext) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueRef jsValue = JSValueMakeNumber(jsContext, static_cast<jdouble>(jValue));
+
+  env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<const jint*>(&jsValue));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueProtectChecked(jsContext, jsValue);
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_executeScriptWithInfoImpl
+    (JNIEnv *env, jclass klass, jint context, jstring jScript, jstring jUrl,
+    jint jLine, jintArray rval) {
+  TR_ENTER();
+  JSValueRef jsException = NULL;
+
+  JSContextRef jsContext = ToJSContextRef(context);
+  if (!jsContext) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSStringRef jsScript = ToJSStringRef(env, jScript);
+  if (!jsScript) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSStringRef jsUrl = ToJSStringRef(env, jUrl);
+
+  // Evaluate will set this to global object.
+  JSValueRef jsResult = JSEvaluateScript(jsContext, jsScript, NULL, jsUrl,
+      static_cast<int>(jLine), &jsException);
+  if (jsException) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSStringRelease(jsScript);
+  if (jsUrl) {
+    JSStringRelease(jsUrl);
+  }
+
+  env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<const jint*>(&jsResult));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueProtectChecked(jsContext, jsResult);
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toJsStringImpl
+    (JNIEnv *env, jclass klass, jint context, jstring jValue, jintArray rval) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  if (!jsContext) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSStringRef jsString = ToJSStringRef(env, jValue);
+  if (!jsString) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueRef jsValue = JSValueMakeString(jsContext, jsString);
+  JSStringRelease(jsString);
+
+  env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<const jint*>(&jsValue));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueProtectChecked(jsContext, jsValue);
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsStringImpl
+    (JNIEnv *env, jclass klass, jint context, jint value, jbooleanArray rval) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  bool isString = JSValueIsString(jsContext, jsValue);
+  if (!isString) {
+    JSValueRef jsException = NULL;
+    isString = IsObjectOfStringConstructor(jsContext, jsValue, &jsException);
+    if (jsException) {
+      TR_FAIL();
+      return JNI_FALSE;
+    }
+  }
+
+  jboolean jIsString = static_cast<jboolean>(isString);
+  env->SetBooleanArrayRegion(rval, 0, 1, &jIsString);
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_invokeImpl
+    (JNIEnv *env, jclass klass, jint context, jint scriptValue,
+    jstring jMethodName, jint thisVal, jintArray jArgs, jint jArgsLength,
+    jintArray rval) {
+  TR_ENTER();
+
+  JSContextRef jsContext = ToJSContextRef(context);
+  if (!jsContext) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSObjectRef jsScriptObj = ToJSObjectRef(jsContext, scriptValue, NULL);
+  if (!jsScriptObj) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueRef jsThisVal = ToJSValueRef(thisVal);
+  JSObjectRef jsThisObj = NULL;
+  // If thisVal is null, jsNull, or jsUndefined use the script object
+  // as this.
+  if (!jsThisVal || JSValueIsNull(jsContext, jsThisVal)
+      || JSValueIsUndefined(jsContext, jsThisVal)) {
+    jsThisObj = jsScriptObj;
+  } else {
+    // If we are given a value, ensure that it is an object.
+    jsThisObj = ToJSObjectRef(jsContext, jsThisVal, NULL);
+    if (!jsThisObj) {
+      TR_FAIL();
+      return JNI_FALSE;
+    }
+  }
+
+  JSStringRef jsMethodName = ToJSStringRef(env, jMethodName);
+  if (!jsMethodName) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSObjectRef jsMethod = ToJSObjectRef(jsContext, JSObjectGetProperty(jsContext,
+      jsScriptObj, jsMethodName, NULL), NULL);
+  if (!jsMethod || !JSObjectIsFunction(jsContext, jsMethod)) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSStringRelease(jsMethodName);
+
+  // NOTE (knorton): Fix for 64-bit.
+  JSValueRef* jsArgs = new JSValueRef[static_cast<size_t>(jArgsLength)];
+  env->GetIntArrayRegion(jArgs, 0, jArgsLength,
+      reinterpret_cast<jint*>(jsArgs));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    delete[] jsArgs;
+    return JNI_FALSE;
+  }
+
+  JSValueRef jsException = NULL;
+  JSValueRef jsResult = JSObjectCallAsFunction(jsContext, jsMethod, jsThisObj,
+      static_cast<size_t>(jArgsLength), jsArgs, &jsException);
+  if (jsException) {
+    TR_FAIL();
+    delete[] jsArgs;
+    return JNI_FALSE;
+  }
+  delete[] jsArgs;
+
+  env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<const jint*>(&jsResult));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueProtectChecked(jsContext, jsResult);
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsObject
+    (JNIEnv *env, jclass klass, jint context, jint value) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  TR_LEAVE();
+  return static_cast<jboolean>(JSValueIsObject(jsContext, jsValue));
+}
+
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toBooleanImpl
+    (JNIEnv *env, jclass klass, jint context, jint value, jbooleanArray rval) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  jboolean jResult = static_cast<jboolean>(JSValueToBoolean(jsContext, jsValue));
+  env->SetBooleanArrayRegion(rval, 0, 1, &jResult);
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toDoubleImpl
+    (JNIEnv *env, jclass klass, jint context, jint value, jdoubleArray rval) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueRef jsException = NULL;
+  double result = JSValueToNumber(jsContext, jsValue, &jsException);
+  if (jsException) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  env->SetDoubleArrayRegion(rval, 0, 1, static_cast<jdouble*>(&result));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toStringImpl
+    (JNIEnv *env, jclass klass, jint context, jint value, jobjectArray rval) {
+  TR_ENTER();
+  JSValueRef jsException = NULL;
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  jstring jResult = NULL;
+   // Convert all objects to their string representation, EXCEPT
+   // null and undefined which will be returned as a true NULL.
+  if (!JSValueIsNull(jsContext, jsValue) &&
+      !JSValueIsUndefined(jsContext, jsValue)) {
+    JSStringRef jsResult = JSValueToStringCopy(jsContext, jsValue, &jsException);
+    if (jsException) {
+      TR_FAIL();
+      return JNI_FALSE;
+    }
+
+    jResult = env->NewString(
+        static_cast<const jchar*>(JSStringGetCharactersPtr(jsResult)),
+        static_cast<jsize>(JSStringGetLength(jsResult)));
+    if (env->ExceptionCheck()) {
+      TR_FAIL();
+      return JNI_FALSE;
+    }
+
+    JSStringRelease(jsResult);
+  }
+
+  env->SetObjectArrayElement(rval, 0, jResult);
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_wrapDispatchObjectImpl
+    (JNIEnv *env, jclass klass, jint context, jobject dispatch, jintArray rval) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  if (!jsContext) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSObjectRef jsDispatch = gwt::DispatchObjectCreate(jsContext, dispatch);
+  if (!jsDispatch || env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<jint*>(&jsDispatch));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueProtectChecked(jsContext, jsDispatch);
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_unwrapDispatchObjectImpl
+    (JNIEnv *env, jclass klass, jint context, jint value, jobjectArray rval) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  if (!JSValueIsObjectOfClass(jsContext, jsValue, gwt::GetDispatchObjectClass())) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSObjectRef jsObject = ToJSObjectRef(jsContext, jsValue, NULL);
+  if (!jsObject) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  env->SetObjectArrayElement(rval, 0, reinterpret_cast<jobject>(JSObjectGetPrivate(jsObject)));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_initImpl
+    (JNIEnv *env, jclass klass, jclass dispatchObjectClass,
+    jclass dispatchMethodClass, jclass lowLevelSafClass) {
+  TR_ENTER();
+  TR_LEAVE();
+  return static_cast<jboolean>(gwt::Initialize(env, dispatchObjectClass, dispatchMethodClass, lowLevelSafClass));
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_wrapDispatchMethodImpl
+    (JNIEnv *env, jclass klass, jint context, jstring name, jobject jDispatch,
+    jintArray rval) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  if (!jsContext) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JStringWrap nameWrap(env, name);
+  std::string nameStr(nameWrap.str());
+  JSObjectRef jsDispatch = gwt::DispatchMethodCreate(jsContext, nameStr,
+      jDispatch);
+  if (!jsDispatch || env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<jint*>(&jsDispatch));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueProtectChecked(jsContext, jsDispatch);
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jstring JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getTypeString
+    (JNIEnv *env, jclass klass, jint context, jint value) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    return NULL;
+  }
+
+  switch (JSValueGetType(jsContext, jsValue)) {
+    case kJSTypeUndefined:
+      return env->NewStringUTF("undefined");
+    case kJSTypeNull:
+      return env->NewStringUTF("null");
+    case kJSTypeBoolean:
+      return env->NewStringUTF("boolean");
+    case kJSTypeNumber:
+      return env->NewStringUTF("number");
+    case kJSTypeString:
+      return env->NewStringUTF("string");
+    case kJSTypeObject:
+      return (JSValueIsObjectOfClass(jsContext, jsValue, gwt::GetDispatchObjectClass()))
+        ? env->NewStringUTF("Java object") : env->NewStringUTF("JavaScript object");
+    default:
+      return env->NewStringUTF("unknown");
+  }
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isDispatchObjectImpl
+    (JNIEnv *env, jclass klass, jint context, jint value, jbooleanArray rval) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  jboolean jIsDispatchObject = static_cast<jboolean>(JSValueIsObjectOfClass(
+      jsContext, jsValue, gwt::GetDispatchObjectClass()));
+  env->SetBooleanArrayRegion(rval, 0, 1, &jIsDispatchObject);
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getArgc
+    (JNIEnv *env, jclass klass) {
+  return *_NSGetArgc();
+}
+
+/*
+ *
+ */
+JNIEXPORT jstring JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getArgv
+    (JNIEnv *env, jclass klass, jint index) {
+  int argc = *_NSGetArgc();
+  if (index < 0 || index >= argc) {
+    return 0;
+  }
+  char **argv = *_NSGetArgv();
+  return env->NewStringUTF(argv[index]);
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getGlobalJsObjectImpl
+    (JNIEnv *env, jclass klass, jint context, jintArray rval) {
+  TR_ENTER();
+
+  JSContextRef jsContext = ToJSContextRef(context);
+  if (!jsContext) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSObjectRef jsGlobalObject = JSContextGetGlobalObject(jsContext);
+  env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<jint*>(&jsGlobalObject));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueProtectChecked(jsContext, jsGlobalObject);
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_gcProtect
+    (JNIEnv *env, jclass klass, jint context, jint value) {
+  TR_ENTER();
+
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    return;
+  }
+
+  JSValueProtectChecked(jsContext, jsValue);
+  TR_LEAVE();
+}
+
+/*
+ *
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_retainJsGlobalContext
+    (JNIEnv *env, jclass klass, jint context) {
+  TR_ENTER();
+  JSGlobalContextRef jsContext = reinterpret_cast<JSGlobalContextRef>(context);
+  if (!jsContext) {
+    TR_FAIL();
+    return;
+  }
+  JSGlobalContextRetain(jsContext);
+  TR_LEAVE();
+}
+
+/*
+ *
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_releaseJsGlobalContext
+    (JNIEnv *env, jclass klass, jint context) {
+  TR_ENTER();
+  JSGlobalContextRef jsContext = reinterpret_cast<JSGlobalContextRef>(context);
+  if (!jsContext) {
+    TR_FAIL();
+    return;
+  }
+  JSGlobalContextRelease(jsContext);
+  TR_LEAVE();
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isGcProtected
+    (JNIEnv *env, jclass klass, jint value) {
+  JSValueRef jsValue = ToJSValueRef(value);
+  TR_ENTER();
+  TR_LEAVE();
+  return static_cast<jboolean>(JSValueIsProtected(jsValue));
+}
+
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsValueProtectionCheckingEnabledImpl
+    (JNIEnv *env, jclass klass) {
+  TR_ENTER();
+  TR_LEAVE();
+  return static_cast<jboolean>(JSValueProtectCheckingIsEnabled());
+}
diff --git a/jni/mac/java-dispatch.cpp b/jni/mac/java-dispatch.cpp
new file mode 100644
index 0000000..fafab11
--- /dev/null
+++ b/jni/mac/java-dispatch.cpp
@@ -0,0 +1,524 @@
+/*
+ * Copyright 2008 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 <string>
+#include <sstream>
+#include "jni.h"
+#include "java-dispatch.h"
+#include "trace.h"
+#include "JStringWrap.h"
+
+namespace gwt {
+
+  /*
+   * Declarations for private functions.
+   */
+  JSClassRef DispatchObjectClassCreate();
+
+  JSClassRef DispatchMethodClassCreate();
+
+  JSValueRef DispatchObjectGetProperty(JSContextRef, JSObjectRef, JSStringRef,
+                                       JSValueRef*);
+
+  JSValueRef DispatchObjectToString(JSContextRef, JSObjectRef, JSObjectRef,
+                                    size_t, const JSValueRef*, JSValueRef*);
+
+  bool DispatchObjectSetProperty(JSContextRef, JSObjectRef, JSStringRef,
+                                 JSValueRef, JSValueRef*);
+
+  void DispatchObjectFinalize(JSObjectRef);
+
+  JSValueRef DispatchMethodCallAsFunction(JSContextRef, JSObjectRef,
+                                          JSObjectRef, size_t,
+                                          const JSValueRef*, JSValueRef*);
+
+  JSValueRef DispatchMethodGetToString(JSContextRef, JSObjectRef, JSStringRef,
+                                       JSValueRef*);
+
+  JSValueRef DispatchMethodToString(JSContextRef, JSObjectRef, JSObjectRef,
+                                    size_t, const JSValueRef*, JSValueRef*);
+
+  void DispatchMethodFinalize(JSObjectRef);
+
+  /*
+   * Call this when an underlying Java Object should be freed.
+   */
+  void ReleaseJavaObject(jobject jObject);
+
+
+  /*
+   * The class definition stuct for DispatchObjects.
+   */
+  static JSClassDefinition _dispatchObjectClassDef = { 0,
+      kJSClassAttributeNone, "DispatchObject", 0, 0, 0, 0,
+      DispatchObjectFinalize, 0, DispatchObjectGetProperty,
+      DispatchObjectSetProperty, 0, 0, 0, 0, 0, 0 };
+
+  /*
+   * The class definition structs for DispatchMethods.
+   */
+  static JSStaticValue _dispatchMethodStaticValues[] = {
+    { "toString", DispatchMethodGetToString, 0, kJSPropertyAttributeNone },
+    { 0, 0, 0, 0 }
+  };
+  static JSClassDefinition _dispatchMethodClassDef = { 0,
+      kJSClassAttributeNoAutomaticPrototype, "DispatchMethod", 0,
+      _dispatchMethodStaticValues, 0, 0, DispatchMethodFinalize, 0, 0, 0, 0,
+      0, DispatchMethodCallAsFunction, 0, 0, 0 };
+
+  /*
+   * The classes used to create DispatchObjects and DispatchMethods.
+   */
+  static JSClassRef _dispatchObjectClass = DispatchObjectClassCreate();
+  static JSClassRef _dispatchMethodClass = DispatchMethodClassCreate();
+
+  /*
+   * Java class and method references needed to do delegation.
+   */
+  
+  /*
+   * The main JVM, used by foreign threads to attach.
+   */
+  static JavaVM* _javaVM;
+
+  /*
+   * Only valid for the main thread!  WebKit can finalized on a foreign thread.
+   */
+  static JNIEnv* _javaEnv;
+
+  static jclass _javaDispatchObjectClass;
+  static jclass _javaDispatchMethodClass;
+  static jclass _lowLevelSafClass;
+  static jmethodID _javaDispatchObjectSetFieldMethod;
+  static jmethodID _javaDispatchObjectGetFieldMethod;
+  static jmethodID _javaDispatchMethodInvokeMethod;
+  static jmethodID _javaDispatchObjectToStringMethod;
+  static jmethodID _lowLevelSafReleaseObject;
+
+  /*
+   * Structure to hold DispatchMethod private data.
+   *
+   * NOTE: utf8Name is defensively copied.
+   */
+  class DispatchMethodData {
+   public:
+    DispatchMethodData(jobject jObject, std::string& utf8Name)
+        : _jObject(jObject), _utf8Name(utf8Name) { }
+    ~DispatchMethodData() {
+      ReleaseJavaObject(_jObject);
+    }
+    jobject _jObject;
+    std::string _utf8Name;
+  };
+
+/*
+ * The following takes the prototype from the Function constructor, this allows
+ * us to easily support call and apply on our objects that support CallAsFunction.
+ *
+ * NOTE: The return value is not protected.
+ */
+JSValueRef GetFunctionPrototype(JSContextRef jsContext, JSValueRef* exception) {
+  TR_ENTER();
+  JSObjectRef globalObject = JSContextGetGlobalObject(jsContext);
+  JSStringRef fnPropName= JSStringCreateWithUTF8CString("Function");
+  JSValueRef fnCtorValue = JSObjectGetProperty(jsContext, globalObject,
+      fnPropName, exception);
+  JSStringRelease(fnPropName);
+  if (!fnCtorValue) {
+    return JSValueMakeUndefined(jsContext);
+  }
+
+  JSObjectRef fnCtorObject = JSValueToObject(jsContext, fnCtorValue, exception);
+  if (!fnCtorObject) {
+    return JSValueMakeUndefined(jsContext);
+  }
+
+  JSStringRef protoPropName = JSStringCreateWithUTF8CString("prototype");
+  JSValueRef fnPrototype = JSObjectGetProperty(jsContext, fnCtorObject,
+      protoPropName, exception);
+  JSStringRelease(protoPropName);
+  if (!fnPrototype) {
+    return JSValueMakeUndefined(jsContext);
+  }
+
+  TR_LEAVE();
+  return fnPrototype;
+}
+
+/*
+ *
+ */
+JSClassRef GetDispatchObjectClass() {
+  TR_ENTER();
+  TR_LEAVE();
+  return _dispatchObjectClass;
+}
+
+/*
+ *
+ */
+JSClassRef GetDispatchMethodClass() {
+  TR_ENTER();
+  TR_LEAVE();
+  return _dispatchMethodClass;
+}
+
+/*
+ *
+ */
+JSClassRef DispatchObjectClassCreate() {
+  TR_ENTER();
+  JSClassRef dispClass = JSClassCreate(&_dispatchObjectClassDef);
+  JSClassRetain(dispClass);
+  TR_LEAVE();
+  return dispClass;
+}
+
+/*
+ *
+ */
+JSClassRef DispatchMethodClassCreate() {
+  TR_ENTER();
+  JSClassRef dispClass = JSClassCreate(&_dispatchMethodClassDef);
+  JSClassRetain(dispClass);
+  TR_LEAVE();
+  return dispClass;
+}
+
+/*
+ * NOTE: The object returned from this function is not protected.
+ */
+JSObjectRef DispatchObjectCreate(JSContextRef jsContext, jobject jObject) {
+  TR_ENTER();
+  JSObjectRef dispInst = JSObjectMake(jsContext, _dispatchObjectClass,
+      _javaEnv->NewGlobalRef(jObject));
+  TR_LEAVE();
+  return dispInst;
+}
+
+/*
+ * NOTE: The object returned from this function is not protected.
+ */
+JSObjectRef DispatchMethodCreate(JSContextRef jsContext, std::string& name,
+    jobject jObject) {
+  TR_ENTER();
+ 
+  JSObjectRef dispInst = JSObjectMake(jsContext, _dispatchMethodClass,
+      new DispatchMethodData(_javaEnv->NewGlobalRef(jObject), name));
+
+  // This could only be cached relative to jsContext.
+  JSValueRef fnProtoValue = GetFunctionPrototype(jsContext, NULL);
+  JSObjectSetPrototype(jsContext, dispInst, fnProtoValue);
+  TR_LEAVE();
+  return dispInst;
+}
+
+/*
+ * NOTE: The value returned from this function is not protected, but all
+ * JSValues that are passed into Java are protected before the invocation.
+ */
+JSValueRef DispatchObjectGetProperty(JSContextRef jsContext,
+    JSObjectRef jsObject, JSStringRef jsPropertyName,
+    JSValueRef* jsException) {
+  TR_ENTER();
+
+  // If you call toString on a DispatchObject, you should get the results
+  // of the java object's toString invcation.
+  if (JSStringIsEqualToUTF8CString(jsPropertyName, "toString")) {
+    JSObjectRef jsFunction = JSObjectMakeFunctionWithCallback(jsContext,
+        jsPropertyName, DispatchObjectToString);
+    return jsFunction;
+  }
+
+  // The class check is omitted because it should not be possible to tear off
+  // a getter.
+  jobject jObject = reinterpret_cast<jobject>(JSObjectGetPrivate(jsObject));
+
+  jstring jPropertyName = _javaEnv->NewString(
+      static_cast<const jchar*>(JSStringGetCharactersPtr(jsPropertyName)),
+      static_cast<jsize>(JSStringGetLength(jsPropertyName)));
+  if (!jObject || !jPropertyName || _javaEnv->ExceptionCheck()) {
+    TR_FAIL();
+    _javaEnv->ExceptionClear();
+    return JSValueMakeUndefined(jsContext);
+  }
+
+  JSValueRef jsResult = reinterpret_cast<JSValueRef>(
+      _javaEnv->CallIntMethod(jObject, _javaDispatchObjectGetFieldMethod,
+      reinterpret_cast<jint>(jsContext),
+      jPropertyName));
+  if (!jsResult || _javaEnv->ExceptionCheck()) {
+    TR_FAIL();
+    _javaEnv->ExceptionClear();
+    return JSValueMakeUndefined(jsContext);
+  }
+
+  // Java left us an extra reference to eat.
+  JSValueUnprotectChecked(jsContext, jsResult);
+  TR_LEAVE();
+  return jsResult;
+}
+
+/*
+ *
+ */
+bool DispatchObjectSetProperty(JSContextRef jsContext, JSObjectRef jsObject,
+    JSStringRef jsPropertyName, JSValueRef jsValue, JSValueRef* jsException) {
+  TR_ENTER();
+
+  // The class check is omitted because it should not be possible to tear off
+  // a getter.
+  jobject jObject = reinterpret_cast<jobject>(JSObjectGetPrivate(jsObject));
+
+  jstring jPropertyName = _javaEnv->NewString(
+      static_cast<const jchar*>(JSStringGetCharactersPtr(jsPropertyName)),
+      static_cast<jsize>(JSStringGetLength(jsPropertyName)));
+  if (!jObject || !jPropertyName || _javaEnv->ExceptionCheck()) {
+    _javaEnv->ExceptionClear();
+    return false;
+  }
+
+  JSValueProtectChecked(jsContext, jsValue);
+
+  _javaEnv->CallIntMethod(jObject, _javaDispatchObjectSetFieldMethod,
+      reinterpret_cast<jint>(jsContext), jPropertyName,
+      reinterpret_cast<jint>(jsValue));
+  if (_javaEnv->ExceptionCheck()) {
+    _javaEnv->ExceptionClear();
+    return false;
+  }
+
+  TR_LEAVE();
+  return true;
+}
+
+/*
+ *
+ */
+void DispatchObjectFinalize(JSObjectRef jsObject) {
+  TR_ENTER();
+  jobject jObject = reinterpret_cast<jobject>(JSObjectGetPrivate(jsObject));
+  ReleaseJavaObject(jObject);
+  TR_LEAVE();
+}
+
+/*
+ *
+ */
+void DispatchMethodFinalize(JSObjectRef jsObject) {
+  TR_ENTER();
+  DispatchMethodData* data = reinterpret_cast<DispatchMethodData*>(
+      JSObjectGetPrivate(jsObject));
+  delete data;
+  TR_LEAVE();
+}
+
+/*
+ * NOTE: The value returned from this function is not protected.
+ */
+JSValueRef DispatchObjectToString(JSContextRef jsContext, JSObjectRef,
+    JSObjectRef jsThis, size_t, const JSValueRef*, JSValueRef*) {
+  TR_ENTER();
+
+  // This function cannot be torn off and applied to any JSValue. If this does
+  // not reference a DispatchObject, return undefined.
+  if (!JSValueIsObjectOfClass(jsContext, jsThis, GetDispatchObjectClass())) {
+    return JSValueMakeUndefined(jsContext);
+  }
+
+  jobject jObject = reinterpret_cast<jobject>(JSObjectGetPrivate(jsThis));
+  jstring jResult = reinterpret_cast<jstring>(
+      _javaEnv->CallObjectMethod(jObject, _javaDispatchObjectToStringMethod));
+  if (_javaEnv->ExceptionCheck()) {
+    return JSValueMakeUndefined(jsContext);
+  } else if (!jResult) {
+    return JSValueMakeNull(jsContext);
+  } else {
+    JStringWrap result(_javaEnv, jResult);
+    JSStringRef resultString = JSStringCreateWithCharacters(
+        static_cast<const JSChar*>(result.jstr()),
+        static_cast<size_t>(result.length()));
+    JSValueRef jsResultString = JSValueMakeString(jsContext, resultString);
+    JSStringRelease(resultString);
+    return jsResultString;
+  }
+  TR_LEAVE();
+}
+
+/*
+ *
+ */
+JSValueRef DispatchMethodCallAsFunction(JSContextRef jsContext,
+    JSObjectRef jsFunction, JSObjectRef jsThis, size_t argumentCount,
+    const JSValueRef arguments[], JSValueRef* exception) {
+  TR_ENTER();
+
+  // We don't need to check the class here because we take the private
+  // data from jsFunction and not jsThis.
+
+  DispatchMethodData* data = reinterpret_cast<DispatchMethodData*>(
+      JSObjectGetPrivate(jsFunction));
+  jobject jObject = data->_jObject;
+
+  jintArray jArguments = _javaEnv->NewIntArray(argumentCount);
+  if (!jArguments || _javaEnv->ExceptionCheck()) {
+    return JSValueMakeUndefined(jsContext);
+  }
+
+  // This single element int array will be passed into the java call to allow the
+  // called java method to raise an exception. We will check for a non-null value
+  // after the call is dispatched.
+  jintArray jException = _javaEnv->NewIntArray(1);
+  if (!jException || _javaEnv->ExceptionCheck()) {
+    return JNI_FALSE;
+  }
+
+  for (size_t i = 0; i < argumentCount; ++i) {
+    JSValueRef arg = arguments[i];
+    // Java will take ownership of the arguments.
+    JSValueProtectChecked(jsContext, arg);
+    _javaEnv->SetIntArrayRegion(jArguments, i, 1, reinterpret_cast<jint*>(&arg));
+    if (_javaEnv->ExceptionCheck()) {
+      return JSValueMakeUndefined(jsContext);
+    }
+  }
+
+  // Java will take ownership of this.
+  JSValueProtectChecked(jsContext, jsThis);
+
+  JSValueRef jsResult = reinterpret_cast<JSValueRef>(_javaEnv->CallIntMethod(jObject,
+      _javaDispatchMethodInvokeMethod, reinterpret_cast<jint>(jsContext),
+      reinterpret_cast<jint>(jsThis), jArguments, jException));
+  if (_javaEnv->ExceptionCheck()) {
+    return JSValueMakeUndefined(jsContext);
+  }
+
+  JSValueRef jsException = NULL;
+  _javaEnv->GetIntArrayRegion(jException, 0, 1, reinterpret_cast<jint*>(&jsException));
+  if (!_javaEnv->ExceptionCheck() && jsException) {
+    // If the java dispatch set an exception, then we pass it back to our caller.
+	if (exception) {
+      *exception = jsException;
+	}
+    // Java left us an extra reference to eat.
+    JSValueUnprotectChecked(jsContext, jsException);
+  }
+
+  // Java left us an extra reference to eat.
+  JSValueUnprotectChecked(jsContext, jsResult);
+  TR_LEAVE();
+  return jsResult;
+}
+
+/*
+ * NOTE: The object returned from this function is not protected.
+ */
+JSValueRef DispatchMethodToString(JSContextRef jsContext, JSObjectRef,
+    JSObjectRef thisObject, size_t, const JSValueRef*, JSValueRef*) {
+  TR_ENTER();
+  
+  // This function cannot be torn off and applied to any JSValue. If this does
+  // not reference a DispatchMethod, return undefined.
+  if (!JSValueIsObjectOfClass(jsContext, thisObject, GetDispatchMethodClass())) {
+    return JSValueMakeUndefined(jsContext);
+  }
+
+  std::ostringstream ss;
+  DispatchMethodData* data = reinterpret_cast<DispatchMethodData*>(
+      JSObjectGetPrivate(thisObject));
+  ss << "function " << data->_utf8Name << "() {\n    [native code]\n}\n";
+  JSStringRef stringRep = JSStringCreateWithUTF8CString(ss.str().c_str());
+  JSValueRef jsStringRep = JSValueMakeString(jsContext, stringRep);
+  JSStringRelease(stringRep);
+  TR_LEAVE();
+  return jsStringRep;
+}
+
+/*
+ * NOTE: The object returned from this function is not protected.
+ */
+JSValueRef DispatchMethodGetToString(JSContextRef jsContext,
+    JSObjectRef jsObject, JSStringRef jsPropertyName, JSValueRef* jsException) {
+  TR_ENTER();
+  JSObjectRef toStringFn = JSObjectMakeFunctionWithCallback(jsContext,
+      jsPropertyName, DispatchMethodToString);
+  TR_LEAVE();
+  return toStringFn;
+}
+
+/*
+ *
+ */
+bool Initialize(JNIEnv* javaEnv, jclass javaDispatchObjectClass,
+    jclass javaDispatchMethodClass, jclass lowLevelSafClass) {
+  TR_ENTER();
+  if (!javaEnv || !javaDispatchObjectClass || !javaDispatchMethodClass
+      || !lowLevelSafClass) {
+    return false;
+  }
+
+  _javaVM = 0;
+  javaEnv->GetJavaVM(&_javaVM);
+
+  _javaEnv = javaEnv;
+  _javaDispatchObjectClass = static_cast<jclass>(
+      javaEnv->NewGlobalRef(javaDispatchObjectClass));
+  _javaDispatchMethodClass = static_cast<jclass>(
+      javaEnv->NewGlobalRef(javaDispatchMethodClass));
+  _lowLevelSafClass = static_cast<jclass>(
+      javaEnv->NewGlobalRef(lowLevelSafClass));
+  _javaDispatchObjectSetFieldMethod = javaEnv->GetMethodID(
+      javaDispatchObjectClass, "setField", "(ILjava/lang/String;I)V");
+  _javaDispatchObjectGetFieldMethod = javaEnv->GetMethodID(
+      javaDispatchObjectClass, "getField", "(ILjava/lang/String;)I");
+  _javaDispatchMethodInvokeMethod = javaEnv->GetMethodID(
+      javaDispatchMethodClass, "invoke", "(II[I[I)I");
+  _javaDispatchObjectToStringMethod = javaEnv->GetMethodID(
+      javaDispatchObjectClass, "toString", "()Ljava/lang/String;");
+  _lowLevelSafReleaseObject = javaEnv->GetStaticMethodID(
+      lowLevelSafClass, "releaseObject", "(Ljava/lang/Object;)V");
+
+  if (!_javaVM
+      || !_javaDispatchObjectSetFieldMethod || !_javaDispatchObjectGetFieldMethod
+      || !_javaDispatchMethodInvokeMethod || !_javaDispatchObjectToStringMethod
+      || !_lowLevelSafReleaseObject || javaEnv->ExceptionCheck()) {
+    return false;
+  }
+
+  TR_LEAVE();
+  return true;
+}
+
+void ReleaseJavaObject(jobject jObject) {
+  // Tricky: this call may be on a foreign thread.
+  JNIEnv* javaEnv = 0;
+  if ((_javaVM->AttachCurrentThreadAsDaemon(reinterpret_cast<void**>(&javaEnv),
+      NULL) < 0) || !javaEnv) {
+    TR_FAIL();
+    return;
+  }
+
+  // Tell the Java code we're done with this object.
+  javaEnv->CallStaticVoidMethod(_lowLevelSafClass, _lowLevelSafReleaseObject,
+      jObject);
+  if (javaEnv->ExceptionCheck()) {
+    TR_FAIL();
+    return;
+  }
+  javaEnv->DeleteGlobalRef(jObject);
+}
+
+} // namespace gwt
diff --git a/jni/mac/java-dispatch.h b/jni/mac/java-dispatch.h
new file mode 100644
index 0000000..f8fa80b
--- /dev/null
+++ b/jni/mac/java-dispatch.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2008 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.
+ */
+
+#ifndef JAVA_DISPATCHER_H__
+#define JAVA_DISPATCHER_H__
+#include <iostream>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include <jni.h>
+
+namespace gwt {
+
+/*
+ * Initializes static members needed by DispatchObject, DispatchMethod,
+ * and LowLevelSaf.  This should be called before before calling anything
+ * else.
+ */
+bool Initialize(JNIEnv*, jclass, jclass, jclass);
+
+/*
+ * Returns a shared reference to the DispatchObject class
+ */
+JSClassRef GetDispatchObjectClass();
+
+/*
+ * Constructs a new DispatchObject.
+ *
+ * jContext - the JavaScript context
+ * jObject - the java instance of DispatchObject to which
+ *   this instance will dispatch calls
+ */
+JSObjectRef DispatchObjectCreate(JSContextRef jContext, jobject jObject);
+
+/*
+ * Returns a shared reference to the DispatchMethod class
+ */
+JSClassRef GetDispatchMethodClass();
+
+/*
+ * Constructs a new DispatchMethod object.
+ *
+ * jsContext - the JavaScript context
+ * name - the name of the method (used in toString)
+ * jObject - the java instance of DispatchMethod to which this object will
+ *   delegate calls.
+ */
+JSObjectRef DispatchMethodCreate(JSContextRef jsContext, std::string& name,
+                                 jobject jObject);
+
+
+} // namespace gwt
+
+#endif // JAVA_DISPATCHER_H__
diff --git a/jni/mac/org.eclipse.swt/webkit.c b/jni/mac/org.eclipse.swt/webkit.c
new file mode 100644
index 0000000..3b704ec
--- /dev/null
+++ b/jni/mac/org.eclipse.swt/webkit.c
@@ -0,0 +1,250 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+// Modified by Google
+#include <Carbon/Carbon.h>
+#include <WebKit/WebKit.h>
+#include <WebKit/HIWebView.h>
+
+#include "jni.h"
+
+JNIEXPORT void JNICALL Java_org_eclipse_swt_browser_WebKit_WebInitForCarbon(JNIEnv *env, jclass zz) {
+	WebInitForCarbon();
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_HIWebViewCreate(JNIEnv *env, jclass zz, jintArray outView) {
+	jint *a = (*env)->GetIntArrayElements(env, outView, NULL);
+	jint status = (jint) HIWebViewCreate((HIViewRef *)a);
+	(*env)->ReleaseIntArrayElements(env, outView, a, 0);
+	return status;
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_HIWebViewGetWebView(JNIEnv *env, jclass zz, jint viewRef) {
+	return (jint) HIWebViewGetWebView((HIViewRef)viewRef);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1msgSend__II(JNIEnv *env, jclass zz, jint obj, jint sel) {
+	return (jint) objc_msgSend((void *)obj, (void *)sel);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1msgSend__III(JNIEnv *env, jclass zz, jint obj, jint sel, jint arg0) {
+	return (jint) objc_msgSend((void *)obj, (void *)sel, (void *)arg0);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1msgSend__IIII(JNIEnv *env, jclass zz, jint obj, jint sel, jint arg0, jint arg1) {
+	return (jint) objc_msgSend((void *)obj, (void *)sel, (void *)arg0, (void *)arg1);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1msgSend__IIIII(JNIEnv *env, jclass zz, jint obj, jint sel, jint arg0, jint arg1, jint arg2) {
+	return (jint) objc_msgSend((void *)obj, (void *)sel, (void *)arg0, (void *)arg1, (void *)arg2);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1msgSend__IIIIII(JNIEnv *env, jclass zz, jint obj, jint sel, jint arg0, jint arg1, jint arg2, jint arg3) {
+	return (jint) objc_msgSend((void *)obj, (void *)sel, (void *)arg0, (void *)arg1, (void *)arg2, (void *)arg3);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1getClass(JNIEnv *env, jclass zz, jbyteArray name) {
+	jbyte *a = (*env)->GetByteArrayElements(env, name, NULL);
+	jint id = (jint) objc_getClass((const char *)a);
+	(*env)->ReleaseByteArrayElements(env, name, a, 0);
+	return id;
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_sel_1registerName(JNIEnv *env, jclass zz, jbyteArray name) {
+	jbyte *a= (*env)->GetByteArrayElements(env, name, NULL);
+	jint sel= (jint) sel_registerName((const char *)a);
+	(*env)->ReleaseByteArrayElements(env, name, a, 0);
+	return sel;
+}
+
+@interface WebKitDelegate : NSObject
+{
+	int user_data;
+	int (*proc) (int sender, int user_data, int selector, int arg0, int arg1, int arg2, int arg3);
+}
+@end
+
+@implementation WebKitDelegate
+
+- (id)initWithProc:(id)prc user_data:(int)data
+{
+    [super init];
+    proc= (void *) prc;
+    user_data = data;
+    return self;
+}
+
+/* WebFrameLoadDelegate */
+
+- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
+{
+	proc((int)sender, user_data, 1, (int)error, (int)frame, 0, 0);
+}
+
+- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
+{
+	proc((int)sender, user_data, 2, (int)frame, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame
+{
+	proc((int)sender, user_data, 3, (int)title, (int)frame, 0, 0);
+}
+
+- (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame
+{
+	proc((int)sender, user_data, 4, (int)frame, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame
+{
+	proc((int)sender, user_data, 10, (int)frame, 0, 0, 0);
+}
+
+/* WebResourceLoadDelegate */
+
+- (void)webView:(WebView *)sender resource:(id)identifier didFinishLoadingFromDataSource:(WebDataSource *)dataSource
+{
+	proc((int)sender, user_data, 5, (int)identifier, (int)dataSource, 0, 0);
+}
+
+- (void)webView:(WebView *)sender resource:(id)identifier didFailLoadingWithError:(NSError *)error fromDataSource:(WebDataSource *)dataSource
+{
+	proc((int)sender, user_data, 6, (int)identifier, (int)error, (int)dataSource, 0);
+}
+
+- (id)webView:(WebView *)sender identifierForInitialRequest:(NSURLRequest *)request fromDataSource:(WebDataSource *)dataSource
+{
+    return (id) proc((int)sender, user_data, 7, (int)request, (int)dataSource, 0, 0);    
+}
+
+- (NSURLRequest *)webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource
+{
+	return (NSURLRequest *) proc((int)sender, user_data, 8, (int)identifier, (int)request, (int)redirectResponse, (int)dataSource);
+}
+
+/* handleNotification */
+
+- (void)handleNotification:(NSNotification *)notification
+{
+	proc((int)[notification object], user_data, 9, (int)notification, 0, 0, 0);
+}
+
+/* UIDelegate */
+
+- (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request
+{
+	return (WebView *) proc((int)sender, user_data, 11, (int)request, 0, 0, 0);
+}
+
+- (void)webViewShow:(WebView *)sender
+{
+	proc((int)sender, user_data, 12, 0, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender setFrame:(NSRect)frame
+{
+	proc((int)sender, user_data, 13, (int)&frame, 0, 0, 0);
+}
+
+- (void)webViewClose:(WebView *)sender
+{
+	proc((int)sender, user_data, 14, 0, 0, 0, 0);
+}
+
+- (NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary *)element defaultMenuItems:(NSArray *)defaultMenuItems
+{
+	return (NSArray *)proc((int)sender, user_data, 15, (int)element, (int)defaultMenuItems, 0, 0);
+}
+
+- (void)webView:(WebView *)sender setStatusBarVisible:(BOOL)visible
+{
+	proc((int)sender, user_data, 16, (int)visible, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender setResizable:(BOOL)resizable
+{
+	proc((int)sender, user_data, 17, (int)resizable, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender setToolbarsVisible:(BOOL)visible
+{
+	proc((int)sender, user_data, 18, (int)visible, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender setStatusText:(NSString *)text
+{
+	proc((int)sender, user_data, 23, (int)text, 0, 0, 0);
+}
+
+- (void)webViewFocus:(WebView *)sender
+{
+	proc((int)sender, user_data, 24, 0, 0, 0, 0);
+}
+
+- (void)webViewUnfocus:(WebView *)sender
+{
+	proc((int)sender, user_data, 25, 0, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message
+{
+	proc((int)sender, user_data, 26, (int)message, 0, 0, 0);
+}
+
+- (BOOL)webView:(WebView *)sender runJavaScriptConfirmPanelWithMessage:(NSString *)message
+{
+	return (BOOL) proc((int)sender, user_data, 27, (int)message, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender runOpenPanelForFileButtonWithResultListener:(id<WebOpenPanelResultListener>)resultListener
+{
+	proc((int)sender, user_data, 28, (int)resultListener, 0, 0, 0);
+}
+
+/* WebPolicyDelegate */
+- (void)webView:(WebView *)sender decidePolicyForMIMEType:(NSString *)type request:(NSURLRequest *)request frame:(WebFrame*)frame decisionListener:(id<WebPolicyDecisionListener>)listener
+{
+	proc((int)sender, user_data, 19, (int)type, (int)request, (int)frame, (int)listener);
+}
+
+- (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener
+{
+	proc((int)sender, user_data, 20, (int)actionInformation, (int)request, (int)frame, (int)listener);
+}
+
+
+- (void)webView:(WebView *)sender decidePolicyForNewWindowAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request newFrameName:(NSString *)frameName decisionListener:(id<WebPolicyDecisionListener>)listener
+{
+	proc((int)sender, user_data, 21, (int)actionInformation, (int)request, (int)frameName, (int)listener);
+}
+
+
+- (void)webView:(WebView *)sender unableToImplementPolicyWithError:(NSError *)error frame:(WebFrame *)frame
+{
+	proc((int)sender, user_data, 22, (int)error, (int)frame, 0, 0);
+}
+
+/* WebDownload */
+
+- (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename
+{
+	proc((int)download, user_data, 29, (int)download, (int)filename, 0, 0);
+}
+
+// GOOGLE: we need a notification when the window object is available so we can
+// setup our own hooks before any JavaScript runs.
+- (void)webView:(WebView *)sender windowScriptObjectAvailable:(WebScriptObject *)windowScriptObject
+{
+	proc((int)sender, user_data, 99, (int)windowScriptObject, 0, 0, 0);
+}
+
+@end
+
diff --git a/jni/mac/prebuilt/libgwt-ll.jnilib b/jni/mac/prebuilt/libgwt-ll.jnilib
new file mode 100755
index 0000000..5a4030f
--- /dev/null
+++ b/jni/mac/prebuilt/libgwt-ll.jnilib
Binary files differ
diff --git a/jni/mac/trace.cpp b/jni/mac/trace.cpp
new file mode 100644
index 0000000..2127351
--- /dev/null
+++ b/jni/mac/trace.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2008 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 <iostream>
+#include <map>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include "trace.h"
+
+#ifdef ENABLE_JSVALUE_PROTECTION_CHECKING
+static std::map<JSValueRef, int> _protectMap;
+#endif
+
+/*
+ *
+ */
+void JSValueProtectChecked(JSContextRef jsContext, JSValueRef jsValue) {
+  JSValueProtect(jsContext, jsValue);
+#ifdef ENABLE_JSVALUE_PROTECTION_CHECKING
+  _protectMap[jsValue]++;
+#endif
+}
+
+/*
+ *
+ */
+void JSValueUnprotectChecked(JSContextRef jsContext, JSValueRef jsValue) {
+#ifdef ENABLE_JSVALUE_PROTECTION_CHECKING
+  // Unrecord in a hash_map
+  unsigned count = _protectMap[jsValue];
+  if (count == 0) {
+    std::cerr << "[WARNING] JSValueUnprotect called on unprotected JSValueRef (0x"
+        << std::hex << ((unsigned)jsValue) << ")" << std::endl;
+    return;
+  }
+  _protectMap[jsValue] = count - 1;
+#else
+  JSValueUnprotect(jsContext, jsValue);
+#endif
+}
+
+bool JSValueIsProtected(JSValueRef jsValue) {
+#ifdef ENABLE_JSVALUE_PROTECTION_CHECKING
+  return _protectMap[jsValue] > 0;
+#else
+  return true;
+#endif
+}
+
+bool JSValueProtectCheckingIsEnabled() {
+#ifdef ENABLE_JSVALUE_PROTECTION_CHECKING
+  return true;
+#else
+  return false;
+#endif
+}
diff --git a/jni/mac/trace.h b/jni/mac/trace.h
new file mode 100644
index 0000000..e58ca96
--- /dev/null
+++ b/jni/mac/trace.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2008 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.
+ */
+
+#ifndef TRACE_H__
+#define TRACE_H__
+#include <iostream>
+#include <map>
+
+// Uncomment to trace enter, exit and fail for all native calls.
+// #define ENABLE_CALL_TRACE
+
+// Uncomment to double check that JSValueRef's are protected and
+// unprotected properly.
+// #define ENABLE_JSVALUE_PROTECTION_CHECKING
+
+#ifdef ENABLE_CALL_TRACE
+#define TR_ENTER() std::cout << "ENTER " << __PRETTY_FUNCTION__ << std::endl
+#define TR_LEAVE() std::cout << "LEAVE " << __PRETTY_FUNCTION__ << std::endl
+#define TR_FAIL() std::cout << "FAIL " << __FILE__ << "@" << __LINE__ \
+    << std::endl;
+#else
+#define TR_ENTER()
+#define TR_LEAVE()
+#define TR_FAIL()
+#endif // ENABLE_CALL_TRACE
+
+void JSValueUnprotectChecked(JSContextRef, JSValueRef);
+void JSValueProtectChecked(JSContextRef, JSValueRef);
+bool JSValueIsProtected(JSValueRef jsValue);
+bool JSValueProtectCheckingIsEnabled();
+
+#endif // TRACE_H__
diff --git a/jni/windows/IE6.cpp b/jni/windows/IE6.cpp
new file mode 100644
index 0000000..58330a1
--- /dev/null
+++ b/jni/windows/IE6.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2006 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.
+ */
+
+// A very slim and portable set of JNI methods for GWT.
+
+#include <jni.h>
+#include <windows.h>
+#include "wininet.h"
+
+// A home-brewed vector class to eliminate dependence on STL.
+// Reuse at your own peril, it hasn't been tested to do anything
+// more than we're actually using it for here.
+struct char_vector {
+    char_vector(long initSize=0): sz(0), cap(0), buf(0) {
+        resize(initSize);
+    }
+    
+    ~char_vector() {
+        clear();
+    }
+
+    char& operator[](long i) {
+        return buf[i];
+    }
+
+    void append(const char* start, const char* end) {
+        long len = end - start;
+        long cursize = sz;
+        resize(sz + len);
+        memcpy(&buf[cursize], start, len);
+    }
+
+    void clear() {
+        if (buf)
+            free(buf);
+        buf = 0;
+        sz = cap = 0;
+    }
+
+    void reserve(long newcap) {
+        if (newcap <= cap)
+            return;
+        char* newbuf = (char*)malloc(newcap);
+        if (!newbuf)
+            return;
+        if (buf) {
+            memcpy(newbuf, buf, sz);
+            free(buf);
+        }
+        buf = newbuf;
+        cap = newcap;
+    }
+
+    void resize(long newsize) {
+        reserve(newsize);
+        sz = newsize;
+    }
+
+    long size() {
+        return sz;
+    }
+
+private:
+    long sz;
+    long cap;
+    char* buf;
+};
+
+// Does an HTTP GET on the specified URL using the WinInet subsystem, which respects proxy settings.
+// Returns a status code such that 
+//      0  Success
+//    < 0  Failure at some step (see the code below)
+//    > 0  Windows system error code
+//
+int fetch(const char* userAgent, const char* url, char_vector& response) {
+    int status = -1;
+    HINTERNET h1 = InternetOpenA(userAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
+    if (h1 != NULL) {
+        status = -2;
+        DWORD flags = INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_COOKIES | INTERNET_FLAG_NO_UI;
+        HINTERNET h2 = InternetOpenUrlA(h1, url, "", -1L, flags, 0);
+        if (h2 != NULL) {
+            status = -3;
+            const int MAX_BUFFER = 1024 * 1024; // don't grow past this ever
+            bool notDone = true;
+            response.clear();
+            response.reserve(4096);
+            char_vector chunk(4096); // initial buffer size
+            while (notDone && chunk.size() < MAX_BUFFER) {
+                DWORD toRead = (DWORD)chunk.size();
+                DWORD didRead;
+                while (true) {
+                    if (InternetReadFile(h2, (LPVOID)&chunk[0], toRead, &didRead)) {
+                        if (didRead != 0) {
+                            // Copy to response.
+                            //
+                            response.append(&chunk[0], &chunk[0] + didRead);
+
+                            // Keep going.
+                            //
+                        } else {
+                            // EOF.
+                            //
+                            status = 0;
+                            notDone = false;
+                            break;
+                        }
+                    } else {
+                        // Oops -- why?
+                        //
+                        DWORD err = GetLastError();
+                        if (err == ERROR_INSUFFICIENT_BUFFER) {
+                            // Grow the buffer and retry.
+                            //
+                            chunk.resize(toRead * 2);
+                            break;
+                        } else {
+                            // Give up.
+                            //
+                            status = err;
+                            notDone = false;
+                            break;
+                        }
+                    }
+                }
+            }
+            InternetCloseHandle(h2);
+        }
+        InternetCloseHandle(h1);
+    }
+    return status;
+}
+
+extern "C" {
+
+class UTFChars {
+public:
+    UTFChars(JNIEnv* env, jstring str): m_env(env), m_str(str) {
+        m_ptr = env->GetStringUTFChars(str, NULL);
+    }
+
+    ~UTFChars() {
+        if (m_ptr) {
+            m_env->ReleaseStringUTFChars(m_str, m_ptr);
+        }
+    }
+
+    operator const char*() const {
+        return m_ptr;
+    }
+
+    JNIEnv* m_env;
+    jstring m_str;
+    const char* m_ptr;
+};
+
+/*
+ * Class:     com_google_gwt_dev_shell_ie_LowLevelIE6
+ * Method:    _httpGet
+ * Signature: (Ljava/lang/String;Ljava/lang/String;[[B)I
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_ie_LowLevelIE6__1httpGet(JNIEnv* env, jclass, jstring userAgent, jstring url, jobjectArray out) {
+    UTFChars userAgentChars(env, userAgent);
+    if (!userAgentChars || env->ExceptionCheck()) {
+		return -100;
+	}
+
+    UTFChars urlChars(env, url);
+    if (!urlChars || env->ExceptionCheck()) {
+		return -101;
+	}
+
+    // Do the fetch.
+    //
+    char_vector response;
+    int status = fetch(userAgentChars, urlChars, response);
+
+    if (status != 0) {
+        // Failure.
+        //
+        return status;
+    }
+
+    // Copy the response.
+    //
+    jbyteArray byteArray = env->NewByteArray(response.size());
+    if (!byteArray || env->ExceptionCheck()) {
+		return -102;
+	}
+
+    jbyte* bytes = env->GetByteArrayElements(byteArray, NULL);
+    if (!bytes || env->ExceptionCheck()) {
+		return -103;
+    }
+
+    memcpy(bytes, &response[0], response.size());
+
+    env->ReleaseByteArrayElements(byteArray, bytes, 0);
+
+    // May throw immediately after return if out array is bad.
+    //
+    env->SetObjectArrayElement(out, 0, byteArray);  
+
+	return 0;
+}
+
+} // extern "C"
diff --git a/jni/windows/Makefile b/jni/windows/Makefile
new file mode 100644
index 0000000..14da521
--- /dev/null
+++ b/jni/windows/Makefile
@@ -0,0 +1,113 @@
+# Copyright 2006 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.
+
+##
+# Target settings
+##
+GWT_ROOT = ../../
+OBJDIR  := $(GWT_ROOT)build/out/jni/win32/
+OUTDIR  := $(GWT_ROOT)build/jni/win32/
+OUT     := $(OUTDIR)gwt-ll.dll
+STAGING := $(GWT_ROOT)build/staging/gwt-windows-0.0.0/
+
+##
+# Tools
+##
+CXX      := mingw-gcc
+AR       := mingw-ar
+STRIP    := mingw-strip
+LD       := $(CXX)
+
+##
+# List of source, object, and dependency paths plus the path to them
+##
+SRCDIRS := ./:../core/
+VPATH   := .:../core
+SRCS    := gwt-ll.cpp IE6.cpp
+OBJS    := $(addprefix $(OBJDIR),$(SRCS:.cpp=.o))
+DEPS    := $(addprefix $(OBJDIR),$(SRCS:.cpp=.d))
+
+##
+# Include path configuration
+##
+SYSINCS := \
+    $(JAVA_HOME)/include \
+    $(JAVA_HOME)/include/win32
+INCS := $(addprefix -isystem ,$(SYSINCS))
+
+##
+# Libraries and library path
+##
+LIBS    := wininet
+LIBPATH := -L$(OBJDIR)
+LIBS    := $(addprefix -l,$(LIBS))
+
+# for notes on auto-dependency generation, see
+#   http://make.paulandlesley.org/autodep.html
+# -MP obviates the need for sed hackery
+CFLAGS   := -Os -fno-exceptions -fshort-wchar -c -MMD -MP -Wno-system-headers $(CFLAGS)
+LDFLAGS  := -s -Wl,--kill-at $(LDFLAGS)
+
+#-------------------------------------------------------------------------------
+# Rules
+#-------------------------------------------------------------------------------
+
+##
+# default rule
+##
+all: $(OUT)
+
+# install into prebuilt directory
+install: $(OUT)
+	cp $(OUT) prebuilt/
+
+##
+# Include the dependency rules
+##
+-include $(DEPS)
+
+##
+# Compilation rule for cpp files
+##
+$(OBJDIR)%.o : $(SRCDIR)%.cpp
+	@[ -d $(OBJDIR) ] || mkdir -p $(OBJDIR)
+	$(CXX) $(CFLAGS) $(INCS) -o $@ $<
+
+##
+# Compilation rule for .def files to lib*.a files
+##
+$(OBJDIR)lib%.a : $(SRCDIR)%.def
+	@[ -d $(OBJDIR) ] || mkdir -p $(OBJDIR)
+	mingw-dlltool -k -d $< -l $@
+	
+##
+# Actual output file
+##
+$(OUT): $(OBJS) $(OBJDIR)libwininet.a
+	@[ -d $(OUTDIR) ] || mkdir -p $(OUTDIR)
+	$(LD) -shared $(LDFLAGS) $(LIBPATH) -o $@ $^ $(LIBS)
+	$(STRIP) --strip-unneeded $@
+
+##
+# copy to staging area for hosted-mode development
+##
+staging: $(OUT)
+	@[ -d $(STAGING) ] || mkdir -p $(STAGING)
+	cp $(OUT) $(STAGING)
+
+##
+# Clean rule
+##
+clean:
+	@-rm -rf $(OBJDIR) $(OUT)
diff --git a/jni/windows/build.xml b/jni/windows/build.xml
new file mode 100755
index 0000000..f5951cf
--- /dev/null
+++ b/jni/windows/build.xml
@@ -0,0 +1,18 @@
+<project name="jni-windows" default="build" basedir=".">
+  <property name="gwt.root" location="../.." />
+  <property name="project.tail" value="jni/windows" />
+  <import file="${gwt.root}/common.ant.xml" />
+
+  <target name="build" description="Builds a JNI lib">
+    <mkdir dir="${project.jni}" />
+    <!-- TODO: Actually build this from source! -->
+    <copy todir="${project.jni}">
+      <fileset dir="prebuilt" />
+    </copy>
+  </target>
+
+  <target name="clean" description="Cleans this project's intermediate and output files">
+    <delete dir="${project.build}" failonerror="false" />
+    <delete dir="${project.jni}" failonerror="false" />
+  </target>
+</project>
diff --git a/jni/windows/gwt-ll.vcproj b/jni/windows/gwt-ll.vcproj
new file mode 100644
index 0000000..18fee56
--- /dev/null
+++ b/jni/windows/gwt-ll.vcproj
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="7.10"
+	Name="gwt-ll"
+	ProjectGUID="{AA853538-40A6-4413-A5B1-74031CB4E887}"
+	RootNamespace="gwt-ll"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="2"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\..\..\third_party\j2sdk1.4.2_09\include&quot;;&quot;$(ProjectDir)..\..\..\..\..\third_party\j2sdk1.4.2_09\include\win32&quot;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL"
+				MinimalRebuild="TRUE"
+				ExceptionHandling="FALSE"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				ForceConformanceInForLoopScope="TRUE"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="FALSE"
+				DebugInformationFormat="3"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="wininet.lib"
+				OutputFile="$(OutDir)\$(ProjectName).dll"
+				LinkIncremental="1"
+				GenerateDebugInformation="TRUE"
+				ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/$(ProjectName).lib"
+				TargetMachine="1"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+			<Tool
+				Name="VCManagedWrapperGeneratorTool"/>
+			<Tool
+				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\..\..\third_party\j2sdk1.4.2_09\include&quot;;&quot;$(ProjectDir)..\..\..\..\..\third_party\j2sdk1.4.2_09\include\win32&quot;"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL"
+				ExceptionHandling="FALSE"
+				RuntimeLibrary="0"
+				ForceConformanceInForLoopScope="TRUE"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="FALSE"
+				DebugInformationFormat="3"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="wininet.lib"
+				OutputFile="$(OutDir)\$(ProjectName).dll"
+				LinkIncremental="1"
+				GenerateDebugInformation="TRUE"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				ImportLibrary="$(OutDir)/$(ProjectName).lib"
+				TargetMachine="1"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+			<Tool
+				Name="VCManagedWrapperGeneratorTool"/>
+			<Tool
+				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+			<File
+				RelativePath="..\..\..\..\gwt-ll-core\src\main\cpp\gwt-ll.cpp">
+			</File>
+			<File
+				RelativePath=".\IE6.cpp">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/jni/windows/prebuilt/gwt-ll.dll b/jni/windows/prebuilt/gwt-ll.dll
new file mode 100755
index 0000000..49a0a1f
--- /dev/null
+++ b/jni/windows/prebuilt/gwt-ll.dll
Binary files differ
diff --git a/jni/windows/wininet.def b/jni/windows/wininet.def
new file mode 100644
index 0000000..83d6751
--- /dev/null
+++ b/jni/windows/wininet.def
@@ -0,0 +1,6 @@
+LIBRARY wininet.dll
+EXPORTS
+InternetOpenA@20        @264
+InternetOpenUrlA@24     @265
+InternetReadFile@16     @272
+InternetCloseHandle@4   @223
diff --git a/jni/windows/wininet.h b/jni/windows/wininet.h
new file mode 100644
index 0000000..935c615
--- /dev/null
+++ b/jni/windows/wininet.h
@@ -0,0 +1,20 @@
+#ifndef __wininet_h__
+#define __wininet_h__
+
+extern "C"  {
+
+#define INTERNET_OPEN_TYPE_PRECONFIG    0
+#define INTERNET_FLAG_PRAGMA_NOCACHE    0x00000100
+#define INTERNET_FLAG_RELOAD            0x80000000
+#define INTERNET_FLAG_NO_COOKIES        0x00080000
+#define INTERNET_FLAG_NO_UI             0x00000200
+
+typedef void* HINTERNET;
+HINTERNET STDAPICALLTYPE InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType, LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags);
+HINTERNET STDAPICALLTYPE InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl, LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext);
+BOOL STDAPICALLTYPE InternetReadFile(HINTERNET hFile, void* lpBuffer, DWORD dwNumberOfBytesToRead, LPDWORD lpdwNumberOfBytesRead);
+BOOL STDAPICALLTYPE InternetCloseHandle(HINTERNET hInternet);
+
+}
+
+#endif // __wininet_h__