Initial subversion import.

The following lines are to recognize contributions made before the switch
to Subversion.

Patch by: bruce, jgw, scottb, mmendez, ecc, hcc, knorton, haeberling, samgross, mat.gessel


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/jni/build.xml b/jni/build.xml
new file mode 100755
index 0000000..c7724c7
--- /dev/null
+++ b/jni/build.xml
@@ -0,0 +1,24 @@
+<project name="jni" default="all" basedir=".">

+	<property name="gwt.root" location=".." />

+	<property name="project.tail" value="jni" />
+	<import file="${gwt.root}/common.ant.xml" />

+

+	<target name="linux" description="Builds jni/linux">

+		<ant dir="linux" inheritall="false"/>

+	</target>

+	

+	<target name="windows" description="Builds jni/linux">

+		<ant dir="windows" inheritall="false"/>

+	</target>

+

+	<target name="mac" description="Builds jni/linux">

+		<ant dir="mac" inheritall="false"/>

+	</target>

+

+	<target name="clean" description="Cleans this project's intermediate and output files">

+		<delete dir="${project.build}" failonerror="false" />

+	</target>

+

+	<target name="all" depends="linux,windows,mac" description="Builds all platforms" />

+

+</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/Makefile b/jni/linux/Makefile
new file mode 100644
index 0000000..35b88fe
--- /dev/null
+++ b/jni/linux/Makefile
@@ -0,0 +1,101 @@
+# Copyright 2006 Google Inc. All Rights Reserved.
+#
+#-------------------------------------------------------------------------------
+# Macros
+#-------------------------------------------------------------------------------
+SHELL   = /bin/sh
+
+##
+# Target settings
+##
+ROOTDIR = ./
+PLATFORM:= linux
+PROGNAME:= gwt-ll
+PROG    := lib$(PROGNAME).so
+PROGDIR := ./
+OBJDIR  := $(PROGDIR)objs/
+OUT     := $(PROGDIR)image/$(PROG)
+
+##
+# Tools
+##
+CXX      := gcc
+AR       := ar
+STRIP    := strip
+LD       := $(CXX)
+
+##
+# List of source, object, and dependency paths plus the path to them
+##
+SRCDIRS := ./:../gwt-ll-core/
+VPATH   := .:../gwt-ll-core
+SRCS    := gwt-ll.cpp Moz.cpp
+OBJS    := $(addprefix $(OBJDIR),$(SRCS:.cpp=.o))
+DEPS    := $(addprefix $(OBJDIR),$(SRCS:.cpp=.d))
+
+##
+# Include path configuration
+##
+SYSINCS := \
+    $(ROOTDIR)../../third_party/j2sdk1.4.2_09/include \
+    $(ROOTDIR)../../third_party/j2sdk1.4.2_09/include/$(PLATFORM) \
+	$(ROOTDIR)../../third_party/gecko-sdk-linux/include \
+	$(ROOTDIR)../../third_party/gecko-sdk-linux/include/extra
+
+INCS := $(addprefix -i ,$(INCS)) $(addprefix -isystem ,$(SYSINCS))
+
+##
+# Libraries and library path
+##
+LIBS    = xpcomglue_s
+LIBPATH = -L../../third_party/gecko-sdk-linux/lib
+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 -fPIC -fno-omit-frame-pointer -fno-strict-aliasing -D_REENTRANT -c -MMD -MP -Wno-system-headers $(CFLAGS)
+LDFLAGS  := -s -fPIC -fno-omit-frame-pointer -fno-strict-aliasing -D_REENTRANT -Wl,-shared-gcc $(LDFLAGS)
+
+##
+# Clean macros
+##
+CLEANDIRS := $(CLEANDIRS) $(OBJDIR)
+CLEANFILES := $(CLEANFILES) $(OUT)
+
+#-------------------------------------------------------------------------------
+# Rules
+#-------------------------------------------------------------------------------
+
+##
+# default rule
+##
+all: $(OUT)
+
+##
+# Include the dependency rules
+##
+-include $(DEPS)
+
+##
+# Compilation rule for cpp files
+##
+$(OBJDIR)%.o : $(SRCDIR)%.cpp
+	@[ -d $(OBJDIR) ] || mkdir -p $(OBJDIR)
+	$(CXX) $(CFLAGS) $(INCS) -o $@ $<
+
+##
+# Actual output file
+##
+$(OUT): $(OBJS)
+	@[ -d $(PROGDIR) ] || mkdir -p $(PROGDIR)
+	@[ -d $(PROGDIR)image ] || mkdir -p $(PROGDIR)image
+	$(LD) -shared $(LDFLAGS) $(LIBPATH) -o $@ $^ $(LIBS)
+	$(STRIP) --strip-unneeded $@
+
+##
+# Clean rule
+##
+clean:
+	@-rm -f $(CLEANFILES)
+	@-rm -rf $(CLEANDIRS)
diff --git a/jni/linux/Moz.cpp b/jni/linux/Moz.cpp
new file mode 100644
index 0000000..6a174a6
--- /dev/null
+++ b/jni/linux/Moz.cpp
@@ -0,0 +1,1097 @@
+// Copyright 2005 Google Inc.
+// All Rights Reserved.
+
+// Mozilla-specific hosted-mode methods
+
+// Mozilla header files
+#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 "nsCOMPtr.h"
+#include "nsAutoPtr.h"
+
+#include <jni.h>
+
+static JNIEnv* gEnv = 0;
+static jclass gClass = 0;
+
+//#define FILETRACE
+//#define JAVATRACE
+#if defined(FILETRACE) && defined(JAVATRACE)
+#define TRACE(s) filetrace(s),javatrace(s)
+#elif defined(FILETRACE)
+#define TRACE(s) filetrace(s)
+#elif defined(JAVATRACE)
+#define TRACE(s) javatrace(s)
+#else
+#define TRACE(s) ((void)0)
+#endif
+
+#ifdef FILETRACE
+static FILE* gout = 0;
+static void filetrace(const char* s)
+{
+    fprintf(gout, s);
+    fprintf(gout, "\n");
+    fflush(gout);
+}
+#endif // FILETRACE
+
+#ifdef JAVATRACE
+static jmethodID gTraceMethod = 0;
+static void javatrace(const char* s)
+{
+    if (!gEnv->ExceptionCheck())
+    {
+        jstring out = gEnv->NewStringUTF(s);
+        if (!gEnv->ExceptionCheck())
+            gEnv->CallStaticVoidMethod(gClass, gTraceMethod, out);
+        else
+            gEnv->ExceptionClear();
+    }
+}
+#endif // JAVATRACE
+
+static bool InitGlobals(JNIEnv* env, jclass llClass)
+{
+    if (gEnv)
+        return true;
+
+#ifdef FILETRACE
+    gout = fopen("gwt-ll.log", "w");
+    filetrace("LOG STARTED");
+#endif // FILETRACE
+
+    gClass = static_cast<jclass>(env->NewGlobalRef(llClass));
+    if (!gClass || env->ExceptionCheck())
+        return false;
+
+#ifdef JAVATRACE
+    gTraceMethod = env->GetStaticMethodID(gClass, "trace", "(Ljava/lang/String;)V");
+    if (!gTraceMethod || env->ExceptionCheck())
+        return false;
+#endif // JAVATRACE
+
+    gEnv = env;
+    return true;
+}
+
+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; }
+private:
+    JNIEnv* env;
+    jstring s;
+    const char* p;
+    const jchar* jp;
+};
+
+static void hextrace(int val) {
+    char buf[20];
+    const char* hex = "0123456789ABCDEF";
+    for (int i = 7; i >= 0; --i) {
+        buf[i] = hex[val & 0xF];
+        val >>= 4;
+    }
+    buf[8] = 0;
+    TRACE(buf);
+}
+
+static JSBool gwt_invoke(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+    TRACE("ENTER gwt_invoke");
+
+    // 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)
+        return TRACE("FAIL gwt_invoke: JSTYPE_FUNCTION"), JS_FALSE;
+
+    JSObject* funObj = JSVAL_TO_OBJECT(argv[-2]);
+    jsval jsCleanupObj;
+
+    // Pull the wrapper object out of the funObj's reserved slot
+    if (!JS_GetReservedSlot(cx, funObj, 0, &jsCleanupObj))
+        return TRACE("FAIL gwt_invoke: JS_GetReservedSlot"), JS_FALSE;
+
+    JSObject* cleanupObj = JSVAL_TO_OBJECT(jsCleanupObj);
+    if (!cleanupObj)
+        return TRACE("FAIL gwt_invoke: cleanupObj"), JS_FALSE;
+
+    // Get dispMeth global ref out of the wrapper object
+    jobject dispMeth = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, cleanupObj));
+    if (!dispMeth)
+        return TRACE("FAIL gwt_invoke: dispMeth"), JS_FALSE;
+
+    jclass dispClass = gEnv->GetObjectClass(dispMeth);
+    if (!dispClass || gEnv->ExceptionCheck())
+        return TRACE("FAIL gwt_invoke: GetObjectClass"), JS_FALSE;
+
+    jmethodID invokeID = gEnv->GetMethodID(dispClass, "invoke", "(I[I)I");
+    if (!invokeID || gEnv->ExceptionCheck())
+        return TRACE("FAIL gwt_invoke: GetMethodID"), JS_FALSE;
+
+    jintArray jsargs = gEnv->NewIntArray(argc);
+    if (!jsargs || gEnv->ExceptionCheck())
+        return TRACE("FAIL gwt_invoke: NewIntArray"), JS_FALSE;
+
+    gEnv->SetIntArrayRegion(jsargs, 0, argc, (jint*)argv);
+    if (gEnv->ExceptionCheck())
+        return TRACE("FAIL gwt_invoke: SetIntArrayRegion"), JS_FALSE;
+
+    *rval = gEnv->CallIntMethod(dispMeth, invokeID, argv[-1], jsargs);
+    if (gEnv->ExceptionCheck())
+        return TRACE("FAIL gwt_invoke: java exception is active"), JS_FALSE;
+
+    if (JS_IsExceptionPending(cx))
+        return TRACE("FAIL gwt_invoke: js exception is active"), JS_FALSE;
+
+    TRACE("SUCCESS gwt_invoke");
+    return JS_TRUE;
+}
+
+static JSBool getJavaPropertyStats(JSContext *cx, JSObject *obj, jsval id, jclass& dispClass, jobject& dispObj, jstring& jident)
+{
+    if (!JSVAL_IS_STRING(id))
+        return JS_FALSE;
+
+    jident = gEnv->NewString(JS_GetStringChars(JSVAL_TO_STRING(id)), JS_GetStringLength(JSVAL_TO_STRING(id)));
+    if (!jident || gEnv->ExceptionCheck())
+        return JS_FALSE;
+
+    dispObj = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+    if (!dispObj)
+        return JS_FALSE;
+
+    dispClass = gEnv->GetObjectClass(dispObj);
+    if (gEnv->ExceptionCheck())
+        return JS_FALSE;
+
+    return JS_TRUE;
+}
+
+static JSBool JS_DLL_CALLBACK gwt_nativewrapper_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+    TRACE("ENTER gwt_nativewrapper_setProperty");
+
+    jclass dispClass;
+    jobject dispObj;
+    jstring ident;
+    if (!getJavaPropertyStats(cx,obj,id,dispClass,dispObj,ident))
+        return JS_FALSE;
+
+    jmethodID setFieldMeth = gEnv->GetMethodID(dispClass, "setField", "(Ljava/lang/String;I)V");
+    if (!setFieldMeth || gEnv->ExceptionCheck())
+        return JS_FALSE;
+
+    gEnv->CallVoidMethod(dispObj, setFieldMeth, ident, *vp);
+    if (gEnv->ExceptionCheck())
+        return JS_FALSE;
+
+    TRACE("SUCCESS gwt_nativewrapper_setProperty");
+    return JS_TRUE;
+}
+
+static JSBool JS_DLL_CALLBACK gwt_nativewrapper_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+    TRACE("ENTER gwt_nativewrapper_getProperty");
+
+    if (*vp != JSVAL_VOID)
+        return TRACE("SUCCESS, already defined"), JS_TRUE;
+
+    jclass dispClass;
+    jobject dispObj;
+    jstring ident;
+    if (!getJavaPropertyStats(cx,obj,id,dispClass,dispObj,ident))
+        return JS_FALSE;
+
+    jmethodID getFieldMeth = gEnv->GetMethodID(dispClass, "getField", "(Ljava/lang/String;)I");
+    if (!getFieldMeth || gEnv->ExceptionCheck())
+        return JS_FALSE;
+
+    *vp = gEnv->CallIntMethod(dispObj, getFieldMeth, ident);
+    if (gEnv->ExceptionCheck())
+        return JS_FALSE;
+
+    TRACE("SUCCESS gwt_nativewrapper_getProperty");
+    return JS_TRUE;
+}
+
+static void JS_DLL_CALLBACK gwt_nativewrapper_finalize(JSContext *cx, JSObject *obj)
+{
+    jobject dispObj = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+    if (dispObj)
+        gEnv->DeleteGlobalRef(dispObj);
+}
+
+static 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
+};
+
+static 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
+};
+
+static JSBool gwtOnLoad(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+    TRACE("ENTER gwtOnLoad");
+
+    if (argc < 2)
+        return JS_FALSE;
+
+    JSObject* scriptWindow = 0;
+    if (argv[0] != JSVAL_NULL && argv[0] != JSVAL_VOID) {
+        if (!JS_ValueToObject(cx, argv[0], &scriptWindow))
+            return JS_FALSE;
+    }
+
+    JSString* moduleName = 0;
+    if (argv[1] != JSVAL_NULL && argv[1] != JSVAL_VOID) {
+        moduleName = JS_ValueToString(cx, argv[1]);
+    }
+
+    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 = gEnv->NewString(JS_GetStringChars(moduleName), JS_GetStringLength(moduleName));
+        if (!jModuleName || gEnv->ExceptionCheck())
+            return JS_FALSE;
+    }
+    
+    jobject externalObject = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+    jclass objClass = gEnv->GetObjectClass(externalObject);
+    if (!objClass || gEnv->ExceptionCheck())
+        return JS_FALSE;
+    
+    jmethodID methodID = gEnv->GetMethodID(objClass, "gwtOnLoad", "(ILjava/lang/String;)Z");
+    if (!methodID || gEnv->ExceptionCheck())
+        return JS_FALSE;
+    
+    jboolean result = gEnv->CallBooleanMethod(externalObject, methodID, NS_REINTERPRET_CAST(jint, scriptGlobal.get()), jModuleName);
+    if (gEnv->ExceptionCheck())
+        return JS_FALSE;
+
+    *rval = BOOLEAN_TO_JSVAL((result == JNI_FALSE) ? JS_FALSE : JS_TRUE);
+    TRACE("SUCCESS gwtOnLoad");
+    return JS_TRUE;
+}
+
+class ExternalWrapper : public nsIScriptObjectOwner
+{
+public:
+    NS_DECL_ISUPPORTS
+    NS_IMETHOD GetScriptObject(nsIScriptContext *aContext, void** aScriptObject);
+    NS_IMETHOD SetScriptObject(void* aScriptObject);
+    ExternalWrapper(): mScriptObject(0) { }
+private:
+    ~ExternalWrapper() { }
+    void *mScriptObject;
+};
+
+NS_IMPL_ISUPPORTS1(ExternalWrapper, nsIScriptObjectOwner)
+
+static JSBool JS_DLL_CALLBACK gwt_external_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+    return JS_FALSE;
+}
+
+static JSBool JS_DLL_CALLBACK gwt_external_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+    TRACE("ENTER gwt_external_getProperty");
+
+    if (*vp != JSVAL_VOID)
+        return TRACE("SUCCESS, already defined"), JS_TRUE;
+
+    if (!JSVAL_IS_STRING(id))
+        return TRACE("FAIL 1"), JS_FALSE;
+
+    jstring jident = gEnv->NewString(JS_GetStringChars(JSVAL_TO_STRING(id)), JS_GetStringLength(JSVAL_TO_STRING(id)));
+    if (!jident || gEnv->ExceptionCheck())
+        return TRACE("FAIL 2"), JS_FALSE;
+
+    jobject externalObject = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+    jclass objClass = gEnv->GetObjectClass(externalObject);
+    if (!objClass || gEnv->ExceptionCheck())
+        return TRACE("FAIL 4"), JS_FALSE;
+
+    jmethodID methodID = gEnv->GetMethodID(objClass, "resolveReference", "(Ljava/lang/String;)I");
+    if (!methodID || gEnv->ExceptionCheck())
+        return TRACE("FAIL 5"), JS_FALSE;
+    int retval = gEnv->CallIntMethod(externalObject, methodID, jident);
+    if (gEnv->ExceptionCheck())
+        return TRACE("FAIL 6"), JS_FALSE;
+    *vp = retval;
+
+    TRACE("SUCCESS gwt_external_getProperty");
+    return JS_TRUE;
+}
+
+static void JS_DLL_CALLBACK gwt_external_finalize(JSContext *cx, JSObject *obj)
+{
+    jobject externalObject = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+    if (externalObject)
+        gEnv->DeleteGlobalRef(externalObject);
+    JS_FinalizeStub(cx,obj);
+}
+
+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
+};
+
+class nsJSObjectLocker : public nsISupports
+{
+public:
+    NS_DECL_ISUPPORTS
+    nsJSObjectLocker(JSContext* cx, jsval val): mCx(cx), mVal(val) { if (mCx && mVal) JSVAL_LOCK(mCx,mVal); }
+
+    JSContext* const mCx;
+    const jsval mVal;
+
+    // Major hack; compare other object's vtable ptrs to this one to do crude RTTI
+    static nsJSObjectLocker sJSObjectLocker;
+
+private:
+    ~nsJSObjectLocker() { if (mCx && mVal) JSVAL_UNLOCK(mCx,mVal); }
+};
+NS_IMPL_ISUPPORTS0(nsJSObjectLocker)
+
+// Major hack; compare other object's vtable ptrs to this one to do crude RTTI
+nsJSObjectLocker nsJSObjectLocker::sJSObjectLocker(0,0);
+
+NS_IMETHODIMP ExternalWrapper::GetScriptObject(nsIScriptContext *aContext, void** aScriptObject)
+{
+    TRACE("ENTER ExternalWrapper::GetScriptObject");
+
+    if (!aScriptObject)
+        return TRACE("FAIL 0"), NS_ERROR_INVALID_POINTER;
+
+    if (!mScriptObject)
+    {
+        *aScriptObject = 0;
+
+        nsIScriptGlobalObject* globalObject = aContext->GetGlobalObject();
+        nsCOMPtr<nsIDOMWindow> domWindow(do_QueryInterface(globalObject));
+        if (!domWindow)
+            return TRACE("FAIL 1"), NS_ERROR_UNEXPECTED;
+        
+        nsCOMPtr<nsIDOMWindow> topWindow;
+        domWindow->GetTop(getter_AddRefs(topWindow));
+        if (!topWindow)
+            return TRACE("FAIL 2"), NS_ERROR_UNEXPECTED;
+
+        jmethodID methodID = gEnv->GetStaticMethodID(gClass, "createExternalObjectForDOMWindow", "(I)Lcom/google/gwt/dev/shell/moz/LowLevelMoz$ExternalObject;");
+        if (!methodID || gEnv->ExceptionCheck())
+            return TRACE("FAIL 3"), NS_ERROR_UNEXPECTED;
+
+        jobject externalObject = gEnv->CallStaticObjectMethod(gClass, methodID, NS_REINTERPRET_CAST(jint, topWindow.get()));
+        if (!externalObject || gEnv->ExceptionCheck())
+            return TRACE("FAIL 4"), NS_ERROR_UNEXPECTED;
+        externalObject = gEnv->NewGlobalRef(externalObject);
+        if (!externalObject || gEnv->ExceptionCheck())
+            return TRACE("FAIL 5"), NS_ERROR_UNEXPECTED;
+
+        JSContext* cx = NS_REINTERPRET_CAST(JSContext*,aContext->GetNativeContext());
+        if (!cx)
+            return TRACE("FAIL 6"), NS_ERROR_UNEXPECTED;
+        JSObject* newObj = JS_NewObject(cx, &gwt_external_class, 0, globalObject->GetGlobalJSObject());
+        if (!newObj)
+            return TRACE("FAIL 7"), NS_ERROR_OUT_OF_MEMORY;
+        if (!JS_SetPrivate(cx, newObj, externalObject)) {
+            gEnv->DeleteGlobalRef(externalObject);
+            return TRACE("FAIL 8"), NS_ERROR_UNEXPECTED;
+        }
+        if (!JS_DefineFunction(cx, newObj, "gwtOnLoad", gwtOnLoad, 3,
+                JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
+            return TRACE("FAIL 9"), NS_ERROR_UNEXPECTED;
+
+        mScriptObject = newObj;
+    }
+
+    *aScriptObject = mScriptObject;
+    TRACE("SUCCESS ExternalWrapper::GetScriptObject");
+    return NS_OK;
+}
+
+NS_IMETHODIMP ExternalWrapper::SetScriptObject(void* aScriptObject)
+{
+    mScriptObject = aScriptObject;
+    return NS_OK;
+}
+
+class nsRpExternalFactory : public nsIFactory
+{
+public:
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIFACTORY
+    nsRpExternalFactory() { }
+private:
+    ~nsRpExternalFactory() { }
+};
+
+NS_IMPL_ISUPPORTS1(nsRpExternalFactory, nsIFactory)
+
+NS_IMETHODIMP nsRpExternalFactory::CreateInstance(nsISupports *aOuter, const nsIID & aIID, void** aResult)
+{
+    TRACE("ENTER nsRpExternalFactory::CreateInstance");
+
+    if (!aResult)
+        return NS_ERROR_INVALID_POINTER;
+
+    *aResult  = NULL;
+
+    if (aOuter)
+        return NS_ERROR_NO_AGGREGATION;
+
+    nsISupports* object = new ExternalWrapper();
+    if (!object)
+        return NS_ERROR_OUT_OF_MEMORY;
+        
+    nsresult result = object->QueryInterface(aIID, aResult);
+    if (!*aResult || NS_FAILED(result))
+        delete object;
+    else
+        TRACE("SUCCESS nsRpExternalFactory::CreateInstance");
+    return result;
+}
+
+NS_IMETHODIMP nsRpExternalFactory::LockFactory(PRBool lock)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+#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"
+
+static NS_DEFINE_CID(kGwtExternalCID, GWT_EXTERNAL_FACTORY_CID);
+
+extern "C" {
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _coerceTo31Bits
+ * Signature: (II[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1coerceTo31Bits
+  (JNIEnv* env, jclass, jint scriptObjInt, jint v, jintArray rval)
+{
+    nsIScriptGlobalObject* scriptObject = NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjInt);
+    nsCOMPtr<nsIScriptContext> scriptContext(scriptObject->GetContext());
+    if (!scriptContext)
+       return JNI_FALSE;
+    JSContext* cx = (JSContext*)scriptContext->GetNativeContext();
+
+    jint r;
+    if (!JS_ValueToECMAInt32(cx, v, &r))
+        return JNI_FALSE;
+    env->SetIntArrayRegion(rval, 0, 1, &r);
+    if (env->ExceptionCheck())
+       return JNI_FALSE;
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _coerceToBoolean
+ * Signature: (II[Z)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1coerceToBoolean
+  (JNIEnv* env, jclass, jint scriptObjInt, jint v, jbooleanArray rval)
+{
+    nsIScriptGlobalObject* scriptObject = NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjInt);
+    nsCOMPtr<nsIScriptContext> scriptContext(scriptObject->GetContext());
+    if (!scriptContext)
+       return JNI_FALSE;
+    JSContext* cx = (JSContext*)scriptContext->GetNativeContext();
+
+    JSBool r;
+    if (!JS_ValueToBoolean(cx, v, &r))
+        return JNI_FALSE;
+    jboolean jr = (r == JS_FALSE) ? JNI_FALSE : JNI_TRUE;
+    env->SetBooleanArrayRegion(rval, 0, 1, &jr);
+    if (env->ExceptionCheck())
+       return JNI_FALSE;
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _coerceToDouble
+ * Signature: (II[D)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1coerceToDouble
+  (JNIEnv* env, jclass, jint scriptObjInt, jint v, jdoubleArray rval)
+{
+    nsIScriptGlobalObject* scriptObject = NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjInt);
+    nsCOMPtr<nsIScriptContext> scriptContext(scriptObject->GetContext());
+    if (!scriptContext)
+       return JNI_FALSE;
+    JSContext* cx = (JSContext*)scriptContext->GetNativeContext();
+
+    jdouble r;
+    if (!JS_ValueToNumber(cx, v, &r))
+        return JNI_FALSE;
+    env->SetDoubleArrayRegion(rval, 0, 1, &r);
+    if (env->ExceptionCheck())
+       return JNI_FALSE;
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _coerceToString
+ * Signature: (II[Ljava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1coerceToString
+  (JNIEnv* env, jclass, jint scriptObjInt, jint v, jobjectArray rval)
+{
+    jstring jr(0);
+    if (v != JSVAL_NULL && v != JSVAL_VOID) {
+        nsIScriptGlobalObject* scriptObject = NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjInt);
+        nsCOMPtr<nsIScriptContext> scriptContext(scriptObject->GetContext());
+        if (!scriptContext)
+            return JNI_FALSE;
+        JSContext* cx = (JSContext*)scriptContext->GetNativeContext();
+
+        JSString* str = JS_ValueToString(cx, v);
+        if (!str)
+            return JNI_FALSE;
+        jr = env->NewString(JS_GetStringChars(str), JS_GetStringLength(str));
+        if (env->ExceptionCheck())
+            return JNI_FALSE;
+    }
+    env->SetObjectArrayElement(rval, 0, jr);
+    if (env->ExceptionCheck())
+       return JNI_FALSE;
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _convert31Bits
+ * Signature: (II[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1convert31Bits
+  (JNIEnv* env, jclass, int scriptObjInt, jint v, jintArray rval)
+{
+    jint r = INT_TO_JSVAL(v);
+    env->SetIntArrayRegion(rval, 0, 1, &r);
+    if (env->ExceptionCheck())
+       return JNI_FALSE;
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _convertBoolean
+ * Signature: (IZ[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1convertBoolean
+  (JNIEnv* env, jclass, int scriptObjInt, jboolean v, jintArray rval)
+{
+    jint r = BOOLEAN_TO_JSVAL((v == JNI_FALSE) ? JS_FALSE : JS_TRUE);
+    env->SetIntArrayRegion(rval, 0, 1, &r);
+    if (env->ExceptionCheck())
+       return JNI_FALSE;
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _convertDouble
+ * Signature: (ID[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1convertDouble
+  (JNIEnv* env, jclass, int scriptObjInt, jdouble v, jintArray rval)
+{
+    nsIScriptGlobalObject* scriptObject = NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjInt);
+    nsCOMPtr<nsIScriptContext> scriptContext(scriptObject->GetContext());
+    if (!scriptContext)
+       return JNI_FALSE;
+    JSContext* cx = (JSContext*)scriptContext->GetNativeContext();
+
+    jsval rv;
+    if (!JS_NewDoubleValue(cx, jsdouble(v), &rv))
+       return JNI_FALSE;
+    jint r = rv;
+    env->SetIntArrayRegion(rval, 0, 1, &r);
+    if (env->ExceptionCheck())
+       return JNI_FALSE;
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _convertString
+ * Signature: (ILjava/lang/String;[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1convertString
+  (JNIEnv* env, jclass, int scriptObjInt, jstring v, jintArray rval)
+{
+    jint r = 0;
+    if (v) {
+        JStringWrap jv(env, v);
+        if (!jv.jstr())
+            return JNI_FALSE;
+
+        nsIScriptGlobalObject* scriptObject = NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjInt);
+        nsCOMPtr<nsIScriptContext> scriptContext(scriptObject->GetContext());
+        if (!scriptContext)
+           return JNI_FALSE;
+        JSContext* cx = (JSContext*)scriptContext->GetNativeContext();
+
+        JSString* str = JS_NewUCStringCopyZ(cx, jv.jstr());
+        if (!str)
+           return JNI_FALSE;
+
+        r = STRING_TO_JSVAL(str);
+    }
+
+    env->SetIntArrayRegion(rval, 0, 1, &r);
+    if (env->ExceptionCheck())
+       return JNI_FALSE;
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _executeScript
+ * Signature: (ILjava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1executeScript
+  (JNIEnv* env, jclass llClass, jint scriptObject, jstring code)
+{
+    JStringWrap jcode(env, code);
+    if (!jcode.jstr())
+        return JNI_FALSE;
+
+    nsIScriptGlobalObject* globalObject = NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObject);
+    nsCOMPtr<nsIScriptContext> scriptContext(globalObject->GetContext());
+    nsXPIDLString scriptString;
+    scriptString = jcode.jstr();
+
+    nsXPIDLString aRetValue;
+    PRBool aIsUndefined;
+    if (NS_FAILED(scriptContext->EvaluateString(scriptString, globalObject->GetGlobalJSObject(),
+            0, __FILE__, __LINE__, 0, aRetValue, &aIsUndefined)))
+        return JNI_FALSE;
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _executeScriptWithInfo
+ * Signature: (ILjava/lang/String;Ljava/lang/String;I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1executeScriptWithInfo
+  (JNIEnv* env, jclass llClass, jint scriptObject, jstring code, jstring file, jint line)
+{
+    JStringWrap jcode(env, code);
+    if (!jcode.jstr())
+        return JNI_FALSE;
+
+    JStringWrap jfile(env, file);
+    if (!jfile.str())
+        return JNI_FALSE;
+
+    nsIScriptGlobalObject* globalObject = NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObject);
+    nsCOMPtr<nsIScriptContext> scriptContext(globalObject->GetContext());
+    nsXPIDLString scriptString;
+    scriptString = jcode.jstr();
+
+    nsXPIDLString aRetValue;
+    PRBool aIsUndefined;
+    if (NS_FAILED(scriptContext->EvaluateString(scriptString, globalObject->GetGlobalJSObject(),
+            0, jfile.str(), line, 0, aRetValue, &aIsUndefined)))
+        return JNI_FALSE;
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _invoke
+ * Signature: (ILjava/lang/String;II[I[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1invoke
+  (JNIEnv* env, jclass, int scriptObjInt, jstring methodName, jint jsthisval, jint jsargc, jintArray jsargs, jintArray rval)
+{
+    TRACE("ENTER Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1invoke");
+
+    JStringWrap methodStr(env,methodName);
+    if (!methodStr.str())
+       return TRACE("FAIL 1"), JNI_FALSE;
+
+    nsIScriptGlobalObject* scriptObject = NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjInt);
+    nsCOMPtr<nsIScriptContext> scriptContext(scriptObject->GetContext());
+    if (!scriptContext)
+       return TRACE("FAIL 2"), JNI_FALSE;
+    JSContext* cx = (JSContext*)scriptContext->GetNativeContext();
+    JSObject* scriptWindow = (JSObject*)scriptObject->GetGlobalJSObject();
+
+    jsval fval;
+    if (!JS_GetProperty(cx, scriptWindow, methodStr.str(), &fval))
+       return TRACE("FAIL 3"), JNI_FALSE;
+    if (!JS_ValueToFunction(cx, fval))
+       return TRACE("FAIL 4"), JNI_FALSE;
+
+    nsAutoArrayPtr<jint> jsargvals(new jint[jsargc]);
+    if (!jsargvals)
+       return TRACE("FAIL 5"), JNI_FALSE;
+
+    env->GetIntArrayRegion(jsargs, 0, jsargc, jsargvals);
+    if (env->ExceptionCheck())
+       return TRACE("FAIL 6"), JNI_FALSE;
+
+    jsval jsrval;
+    JSObject* jsthis = (jsthisval == JSVAL_NULL) ? scriptWindow : JSVAL_TO_OBJECT(jsthisval);
+    if (!JS_CallFunctionValue(cx, jsthis, fval, jsargc, (jsval*)jsargvals.get(), &jsrval))
+       return TRACE("FAIL 7"), JNI_FALSE;
+
+    env->SetIntArrayRegion(rval, 0, 1, (jint*)&jsrval);
+    if (env->ExceptionCheck())
+       return TRACE("FAIL 8"), JNI_FALSE;
+
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1invoke");
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _isWrappedDispatch
+ * Signature: (II[Z)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1isWrappedDispatch
+  (JNIEnv* env, jclass, jint scriptObjInt, jint jsobjval, jbooleanArray rval)
+{
+    TRACE("ENTER Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1isWrappedDispatch");
+
+    nsIScriptGlobalObject* scriptObject = NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjInt);
+    nsCOMPtr<nsIScriptContext> scriptContext(scriptObject->GetContext());
+    if (!scriptContext)
+       return JNI_FALSE;
+    JSContext* cx = (JSContext*)scriptContext->GetNativeContext();
+
+    jboolean r = JNI_FALSE;
+    if (JSVAL_IS_OBJECT(jsobjval))
+    {
+        JSObject* jsobj = JSVAL_TO_OBJECT(jsobjval);
+        if (JS_InstanceOf(cx, jsobj, &gwt_nativewrapper_class, 0))
+            r = JNI_TRUE;
+    }
+
+    env->SetBooleanArrayRegion(rval, 0, 1, &r);
+    if (env->ExceptionCheck())
+       return JNI_FALSE;
+
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1isWrappedDispatch");
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _raiseJavaScriptException
+ * Signature: (II)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1raiseJavaScriptException
+  (JNIEnv* env, jclass, jint scriptObjInt, jint jsarg)
+{
+    TRACE("ENTER Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1raiseJavaScriptException");
+
+    nsIScriptGlobalObject* scriptObject = NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjInt);
+    nsCOMPtr<nsIScriptContext> scriptContext(scriptObject->GetContext());
+    if (!scriptContext)
+       return JNI_FALSE;
+    JSContext* cx = (JSContext*)scriptContext->GetNativeContext();
+    JS_SetPendingException(cx, jsarg);
+
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1raiseJavaScriptException");
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _registerExternalFactoryHandler
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1registerExternalFactoryHandler
+  (JNIEnv* env, jclass llClass)
+{
+    if (!InitGlobals(env, llClass))
+        return JNI_FALSE;
+
+    TRACE("ENTER Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1registerExternalFactoryHandler");
+
+    // Register "window.external" as our own class
+    if (NS_FAILED(nsComponentManager::RegisterFactory(
+            kGwtExternalCID, "externalFactory", GWT_EXTERNAL_CONTRACTID,
+            new nsRpExternalFactory(), PR_TRUE)))
+        return JNI_FALSE;
+
+    nsCOMPtr<nsICategoryManager> categoryManager = do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
+    if (!categoryManager)
+        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))))
+        return JNI_FALSE;
+
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1registerExternalFactoryHandler");
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _unwrapDispatch
+ * Signature: (II[Lcom/google/gwt/dev/shell/moz/LowLevelMoz/DispatchObject;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1unwrapDispatch
+  (JNIEnv* env, jclass, jint scriptObjInt, jint jsobjval, jobjectArray rval)
+{
+    TRACE("ENTER Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1unwrapDispatch");
+
+    nsIScriptGlobalObject* scriptObject = NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjInt);
+    nsCOMPtr<nsIScriptContext> scriptContext(scriptObject->GetContext());
+    if (!scriptContext)
+       return JNI_FALSE;
+    JSContext* cx = (JSContext*)scriptContext->GetNativeContext();
+
+    if (!JSVAL_IS_OBJECT(jsobjval))
+        return JNI_FALSE;
+
+    JSObject* jsobj = JSVAL_TO_OBJECT(jsobjval);
+    if (!JS_InstanceOf(cx, jsobj, &gwt_nativewrapper_class, 0))
+        return JNI_FALSE;
+
+    jobject dispObj = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, jsobj));
+    if (!dispObj)
+        return JNI_FALSE;
+
+    env->SetObjectArrayElement(rval, 0, dispObj);
+    if (env->ExceptionCheck())
+       return JNI_FALSE;
+
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1unwrapDispatch");
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _unwrapJSObject
+ * Signature: (I[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1unwrapJSObject
+  (JNIEnv* env, jclass, jint nsISupportsPtr, jintArray rval)
+{
+    TRACE("ENTER Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1unwrapJSObject");
+
+    // MAJOR HACK: check the vtable ptr against a known "good" as a very crude RTTI
+    long *vt1 = NS_REINTERPRET_CAST(long*,NS_STATIC_CAST(nsISupports*, &nsJSObjectLocker::sJSObjectLocker));
+    long *vt2 = NS_REINTERPRET_CAST(long*,nsISupportsPtr);
+    if (*vt1 != *vt2)
+        return JNI_FALSE;
+
+    // probably safe
+    nsJSObjectLocker* jsObjectLocker = NS_STATIC_CAST(nsJSObjectLocker*, NS_REINTERPRET_CAST(nsISupports*,nsISupportsPtr));
+    jsval r = jsObjectLocker->mVal;
+    if (!JSVAL_IS_OBJECT(r))
+        return JNI_FALSE;
+
+    env->SetIntArrayRegion(rval, 0, 1, (jint*)&r);
+    if (env->ExceptionCheck())
+        return JNI_FALSE;
+
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1unwrapJSObject");
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _wrapDispatch
+ * Signature: (ILcom/google/gwt/dev/shell/moz/LowLevelMoz/DispatchObject;[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1wrapDispatch
+  (JNIEnv* env, jclass, jint scriptObjInt, jobject dispObj, jintArray rval)
+{
+    TRACE("ENTER Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1wrapDispatch");
+
+    nsIScriptGlobalObject* scriptObject = NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjInt);
+    nsCOMPtr<nsIScriptContext> scriptContext(scriptObject->GetContext());
+    if (!scriptContext)
+       return JNI_FALSE;
+
+    JSContext* cx = (JSContext*)scriptContext->GetNativeContext();
+    JSObject* scriptWindow = (JSObject*)scriptObject->GetGlobalJSObject();
+
+    JSObject* newObj = JS_NewObject(cx, &gwt_nativewrapper_class, 0, scriptWindow);
+    if (!newObj)
+        return JNI_FALSE;
+
+    jobject dispObjRef = env->NewGlobalRef(dispObj);
+    if (!dispObjRef || env->ExceptionCheck())
+        return JNI_FALSE;
+
+    if (!JS_SetPrivate(cx, newObj, dispObjRef))
+    {
+        env->DeleteGlobalRef(dispObjRef);
+        return JNI_FALSE;
+    }
+
+    // forcibly setup a "toString" method to override the default
+    jclass dispClass = env->GetObjectClass(dispObj);
+    if (env->ExceptionCheck())
+        return JS_FALSE;
+
+    jmethodID getFieldMeth = env->GetMethodID(dispClass, "getField", "(Ljava/lang/String;)I");
+    if (!getFieldMeth || env->ExceptionCheck())
+        return JS_FALSE;
+
+    jstring ident = env->NewStringUTF("@java.lang.Object::toString()");
+    if (!ident || env->ExceptionCheck())
+        return JS_FALSE;
+
+    jsval toStringFunc = env->CallIntMethod(dispObj, getFieldMeth, ident);
+    if (env->ExceptionCheck())
+        return JS_FALSE;
+
+    if (!JS_DefineProperty(cx, newObj, "toString", toStringFunc, JS_PropertyStub, JS_PropertyStub, JSPROP_READONLY | JSPROP_PERMANENT))
+        return JNI_FALSE;
+
+    env->SetIntArrayRegion(rval, 0, 1, (jint*)&newObj);
+    if (env->ExceptionCheck())
+        return JNI_FALSE;
+
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1wrapDispatch");
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _wrapFunction
+ * Signature: (ILjava/lang/String;Lcom/google/gwt/dev/shell/moz/LowLevelMoz/DispatchMethod;[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1wrapFunction
+  (JNIEnv* env, jclass, jint scriptObjInt, jstring name, jobject dispMeth, jintArray rval)
+{
+    TRACE("ENTER Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1wrapFunction");
+
+    nsIScriptGlobalObject* scriptObject = NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjInt);
+    nsCOMPtr<nsIScriptContext> scriptContext(scriptObject->GetContext());
+    if (!scriptContext)
+        return JNI_FALSE;
+    JSContext* cx = (JSContext*)scriptContext->GetNativeContext();
+    JSObject* scriptWindow = (JSObject*)scriptObject->GetGlobalJSObject();
+
+    JStringWrap nameStr(env, name);
+    if (!nameStr.str())
+        return JNI_FALSE;
+
+    JSFunction* function = JS_NewFunction(cx, gwt_invoke, 0, JSFUN_LAMBDA, 0, nameStr.str());
+    if (!function)
+        return JNI_FALSE;
+
+    JSObject* funObj = JS_GetFunctionObject(function);
+    if (!funObj)
+        return JNI_FALSE;
+
+    // Create a wrapper object to hold and clean up dispMeth
+    JSObject* cleanupObj = JS_NewObject(cx, &gwt_functionwrapper_class, 0, scriptWindow);
+    if (!cleanupObj)
+        return JNI_FALSE;
+
+    jobject dispMethRef = env->NewGlobalRef(dispMeth);
+    if (!dispMethRef || env->ExceptionCheck())
+        return JNI_FALSE;
+
+    // Store our global ref in the wrapper object
+    if (!JS_SetPrivate(cx, cleanupObj, dispMethRef))
+    {
+        env->DeleteGlobalRef(dispMethRef);
+        return JNI_FALSE;
+    }
+
+    // Store the wrapper object in funObj's reserved slot
+    if(!JS_SetReservedSlot(cx, funObj, 0, OBJECT_TO_JSVAL(cleanupObj)))
+        return JS_FALSE;
+
+    env->SetIntArrayRegion(rval, 0, 1, (jint*)&funObj);
+    if (env->ExceptionCheck())
+        return JNI_FALSE;
+
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1wrapFunction");
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method:    _wrapJSObject
+ * Signature: (II[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1wrapJSObject
+  (JNIEnv* env, jclass, jint scriptObjInt, jint jsobjval, jintArray rval)
+{
+    TRACE("ENTER Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1wrapJSObject");
+
+    if (!JSVAL_IS_OBJECT(jsobjval))
+        return JNI_FALSE;
+
+    nsIScriptGlobalObject* scriptObject = NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjInt);
+    nsCOMPtr<nsIScriptContext> scriptContext(scriptObject->GetContext());
+    if (!scriptContext)
+        return JNI_FALSE;
+    JSContext* cx = (JSContext*)scriptContext->GetNativeContext();
+
+    nsISupports* objLocker = new nsJSObjectLocker(cx, jsobjval);
+    if (!objLocker)
+        return JNI_FALSE;
+
+    jint r = (jint)objLocker;
+    env->SetIntArrayRegion(rval, 0, 1, &r);
+    if (env->ExceptionCheck())
+        return JNI_FALSE;
+
+    objLocker->AddRef();
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1wrapJSObject");
+    return JNI_TRUE;
+}
+
+} // extern "C"
diff --git a/jni/linux/build.xml b/jni/linux/build.xml
new file mode 100755
index 0000000..db0db0f
--- /dev/null
+++ b/jni/linux/build.xml
@@ -0,0 +1,20 @@
+<project name="jni-linux" default="all" 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>

+

+	<target name="all" depends="build" description="Builds and packages this project" />

+</project>

diff --git a/jni/linux/prebuilt/libgwt-ll.so b/jni/linux/prebuilt/libgwt-ll.so
new file mode 100755
index 0000000..ee03c5e
--- /dev/null
+++ b/jni/linux/prebuilt/libgwt-ll.so
Binary files differ
diff --git a/jni/mac/DispWrapper.cpp b/jni/mac/DispWrapper.cpp
new file mode 100644
index 0000000..68eb09f
--- /dev/null
+++ b/jni/mac/DispWrapper.cpp
@@ -0,0 +1,89 @@
+// Copyright 2005 Google Inc.
+// All Rights Reserved.
+
+#include "DispWrapper.h"
+#include "FunctionObject.h"
+
+using namespace KJS;
+
+const ClassInfo DispWrapper::info = {"DispWrapper", 0, 0, 0};
+
+JSValue *DispWrapper::getter(ExecState* exec, JSObject* thisObj, const Identifier& propertyName, const PropertySlot& slot) {
+	TRACE("ENTER DispWrapper::getter");
+	if (propertyName.ustring() == "toString") {
+		return new ToStringFunction();
+	}
+	if (thisObj->classInfo() == &DispWrapper::info) {
+		DispWrapper* dispWrap = static_cast<DispWrapper*>(thisObj);
+		jobject dispObj = dispWrap->dispObj;
+		jstring jpropName = gEnv->NewString((const jchar*)propertyName.data(), propertyName.size());
+		if (!jpropName || gEnv->ExceptionCheck()) {
+			gEnv->ExceptionClear();
+			return jsUndefined();
+		}
+		jint result = gEnv->CallIntMethod(dispObj, gGetFieldMeth, jpropName);
+		if (!result || gEnv->ExceptionCheck()) {
+			gEnv->ExceptionClear();
+			return jsUndefined();
+		}
+		TRACE("SUCCESS DispWrapper::getter");
+		return (JSValue*)result;
+	}
+	return jsUndefined();
+}
+
+DispWrapper::DispWrapper(jobject dispObj): dispObj(dispObj) {
+}
+
+DispWrapper::~DispWrapper() {
+	gEnv->DeleteGlobalRef(dispObj);
+}
+
+bool DispWrapper::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot) {
+	slot.setCustom(this, getter);
+	return true;
+}
+
+bool DispWrapper::canPut(ExecState *exec, const Identifier &propertyName) const {
+	return true;
+}
+
+void DispWrapper::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr) {
+	TRACE("ENTER DispWrapper::put");
+	jstring jpropName = gEnv->NewString((const jchar*)propertyName.data(), propertyName.size());
+	if (!jpropName || gEnv->ExceptionCheck()) {
+		gEnv->ExceptionClear();
+		return;
+	}
+
+	gEnv->CallVoidMethod(dispObj, gSetFieldMeth, jpropName, (jint)value);
+	if (gEnv->ExceptionCheck()) {
+		gEnv->ExceptionClear();
+		return;
+	}
+	TRACE("SUCCESS DispWrapper::put");
+}
+
+bool DispWrapper::deleteProperty(ExecState *exec, const Identifier &propertyName) {
+	return false;
+}
+
+JSValue *DispWrapper::defaultValue(ExecState *exec, JSType hint) const {
+	jstring result = (jstring)gEnv->CallObjectMethod(dispObj, gToStringMeth);
+	if (gEnv->ExceptionCheck()) {
+		return jsUndefined();
+	} else if (!result) {
+		return jsNull();
+	} else {
+		JStringWrap jresult(gEnv, result);
+		return jsString(UString((const UChar*)jresult.jstr(), jresult.length()));
+	}
+}
+
+bool DispWrapper::implementsCall() const {
+	return false;
+}
+
+JSValue *DispWrapper::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args) {
+	return jsUndefined();
+}
diff --git a/jni/mac/DispWrapper.h b/jni/mac/DispWrapper.h
new file mode 100644
index 0000000..4eed813
--- /dev/null
+++ b/jni/mac/DispWrapper.h
@@ -0,0 +1,43 @@
+// Copyright 2005 Google Inc.
+// All Rights Reserved.
+
+#ifndef DISP_WRAPPER_H
+#define DISP_WRAPPER_H
+
+#include "gwt-webkit.h"
+#include <kjs/object.h>
+
+// This class actually wraps Java objects
+class DispWrapper : public KJS::JSObject {
+public:
+	// dispObj MUST be a global ref
+    DispWrapper(jobject dispObj);
+	virtual ~DispWrapper();
+	jobject getDispObj();
+
+public:
+	// implementations of JSObject methods
+    const KJS::ClassInfo *classInfo() const { return &info; }
+
+    virtual bool getOwnPropertySlot(KJS::ExecState*, const KJS::Identifier&, KJS::PropertySlot&);
+    virtual bool canPut(KJS::ExecState*, const KJS::Identifier&) const;
+    virtual void put(KJS::ExecState*, const KJS::Identifier&, KJS::JSValue*, int);
+    virtual bool deleteProperty(KJS::ExecState*, const KJS::Identifier&);
+    virtual KJS::JSValue *defaultValue(KJS::ExecState*, KJS::JSType) const;
+    virtual bool implementsCall() const;
+    virtual KJS::JSValue *callAsFunction(KJS::ExecState*, KJS::JSObject*, const KJS::List&);
+    
+    static const KJS::ClassInfo info;
+
+private:
+	static KJS::JSValue* getter(KJS::ExecState*, KJS::JSObject*, const KJS::Identifier&, const KJS::PropertySlot&);
+
+private:
+	jobject dispObj;
+};
+
+inline jobject DispWrapper::getDispObj() {
+	return dispObj;
+}
+
+#endif
diff --git a/jni/mac/FuncWrapper.cpp b/jni/mac/FuncWrapper.cpp
new file mode 100644
index 0000000..e44ca03
--- /dev/null
+++ b/jni/mac/FuncWrapper.cpp
@@ -0,0 +1,42 @@
+// Copyright 2005 Google Inc.
+// All Rights Reserved.
+
+#include "FuncWrapper.h"
+#include <kjs/array_object.h>
+
+using namespace KJS;
+
+// FuncWrapper
+FuncWrapper::FuncWrapper(const UString& name, jobject funcObj): FunctionObject(name)
+, funcObj(funcObj) {
+}
+
+FuncWrapper::~FuncWrapper() {
+	gEnv->DeleteGlobalRef(funcObj);
+}
+
+JSValue *FuncWrapper::callAsFunction(ExecState* execState, JSObject* thisObj, const List& args) {
+    TRACE("ENTER FuncWrapper::callAsFunction");
+
+	int argc = args.size();
+    jintArray jsargs = gEnv->NewIntArray(argc);
+    if (!jsargs || gEnv->ExceptionCheck())
+        return TRACE("FAIL FuncWrapper::callAsFunction: NewIntArray"), jsUndefined();
+
+	for (int i = 0; i < argc; ++i) {
+		JSValue* arg = args[i];
+		gEnv->SetIntArrayRegion(jsargs, i, 1, (jint*)&arg);
+		if (gEnv->ExceptionCheck())
+			return TRACE("FAIL FuncWrapper::callAsFunction: SetIntArrayRegion"), jsUndefined();
+	}
+
+    jint result = gEnv->CallIntMethod(funcObj, gInvokeMeth, execState, thisObj, jsargs);
+    if (gEnv->ExceptionCheck())
+        return TRACE("FAIL FuncWrapper::callAsFunction: java exception is active"), jsUndefined();
+
+    if (execState->hadException())
+        return TRACE("FAIL FuncWrapper::callAsFunction: js exception is active"), jsUndefined();
+
+    TRACE("SUCCESS FuncWrapper::callAsFunction");
+    return (JSValue*)result;
+}
diff --git a/jni/mac/FuncWrapper.h b/jni/mac/FuncWrapper.h
new file mode 100644
index 0000000..8019754
--- /dev/null
+++ b/jni/mac/FuncWrapper.h
@@ -0,0 +1,29 @@
+// Copyright 2005 Google Inc.
+// All Rights Reserved.
+
+#ifndef FUNC_WRAPPER_H
+#define FUNC_WRAPPER_H
+
+#include "FunctionObject.h"
+#include <jni.h>
+
+// This class actually wraps Java method objects
+class FuncWrapper : public FunctionObject {
+public:
+	// funcObj MUST be a global ref
+	FuncWrapper(const KJS::UString& name, jobject funcObj);
+	virtual ~FuncWrapper();
+	jobject getFuncObj();
+
+public:
+    virtual KJS::JSValue *callAsFunction(KJS::ExecState*, KJS::JSObject*, const KJS::List&);
+
+private:
+	jobject funcObj;
+};
+
+inline jobject FuncWrapper::getFuncObj() {
+	return funcObj;
+}
+
+#endif
diff --git a/jni/mac/FunctionObject.cpp b/jni/mac/FunctionObject.cpp
new file mode 100644
index 0000000..8e013cd
--- /dev/null
+++ b/jni/mac/FunctionObject.cpp
@@ -0,0 +1,132 @@
+// Copyright 2005 Google Inc.
+// All Rights Reserved.
+
+#include "FunctionObject.h"
+#include <kjs/array_object.h>
+
+using namespace KJS;
+
+const ClassInfo FunctionObject::info = {"Function", 0, 0, 0};
+
+class CallFunction : public FunctionObject {
+public:
+	CallFunction(): FunctionObject("call") {
+	}
+
+    virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args) {
+		// Copied from FunctionProtoFunc::callAsFunction()
+		JSValue *thisArg = args[0];
+		JSObject *func = thisObj;
+
+		if (!func->implementsCall())
+			return throwError(exec, TypeError);
+
+		JSObject *callThis;
+		if (thisArg->isUndefinedOrNull())
+			callThis = exec->dynamicInterpreter()->globalObject();
+		else
+			callThis = thisArg->toObject(exec);
+
+		return func->call(exec, callThis, args.copyTail());
+	}
+};
+
+class ApplyFunction  : public FunctionObject {
+public:
+	ApplyFunction(): FunctionObject("apply") {
+	}
+
+    virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args) {
+		// Copied from FunctionProtoFunc::callAsFunction()
+		JSObject *func = thisObj;
+		if (!func->implementsCall())
+			return throwError(exec, TypeError);
+
+		JSValue *thisArg = args[0];
+		JSObject *applyThis;
+		if (thisArg->isUndefinedOrNull())
+			applyThis = exec->dynamicInterpreter()->globalObject();
+		else
+			applyThis = thisArg->toObject(exec);
+
+		JSValue *argArray = args[1];
+		List applyArgs;
+		if (!argArray->isUndefinedOrNull()) {
+			if (!argArray->isObject(&ArrayInstance::info))
+				return throwError(exec, TypeError);
+
+			JSObject *argArrayObj = static_cast<JSObject *>(argArray);
+			unsigned int length = argArrayObj->get(exec, lengthPropertyName)->toUInt32(exec);
+			for (unsigned int i = 0; i < length; ++i) {
+				applyArgs.append(argArrayObj->get(exec,i));
+			}
+		}
+		return func->call(exec, applyThis, applyArgs);
+	}
+};
+
+
+static UString makeFunctionString(const UString& name) {
+	return "\nfunction " + name + "() {\n    [native code]\n}\n";
+}
+
+JSValue *FunctionObject::getter(ExecState* exec, JSObject* obj, const Identifier& propertyName, const PropertySlot& slot) {
+	if (propertyName.ustring() == "toString") {
+		return new ToStringFunction();
+	} else if (propertyName.ustring() == "call") {
+		return new CallFunction();
+	} else if (propertyName.ustring() == "apply") {
+		return new ApplyFunction();
+	}
+	return jsUndefined();
+}
+
+FunctionObject::FunctionObject(const UString& name): name(name) {
+}
+
+bool FunctionObject::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot) {
+	if (propertyName.ustring() == "toString") {
+		slot.setCustom(this, getter);
+		return true;
+	}
+	if (propertyName.ustring() == "call") {
+		slot.setCustom(this, getter);
+		return true;
+	}
+	if (propertyName.ustring() == "apply") {
+		slot.setCustom(this, getter);
+		return true;
+	}
+	return false;
+}
+
+bool FunctionObject::canPut(ExecState *exec, const Identifier &propertyName) const {
+	return false;
+}
+
+void FunctionObject::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr) {
+}
+
+bool FunctionObject::deleteProperty(ExecState *exec, const Identifier &propertyName) {
+	return false;
+}
+
+JSValue *FunctionObject::defaultValue(ExecState *exec, JSType hint) const {
+	return jsString(makeFunctionString(name));
+}
+
+bool FunctionObject::implementsCall() const {
+	return true;
+}
+
+// ToStringFunction
+
+ToStringFunction::ToStringFunction(): FunctionObject("toString") {
+}
+
+JSValue *ToStringFunction::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args) {
+	if (!thisObj) {
+		return throwError(exec, TypeError);
+	}
+	return jsString(thisObj->toString(exec));
+}
diff --git a/jni/mac/FunctionObject.h b/jni/mac/FunctionObject.h
new file mode 100644
index 0000000..0860f5b
--- /dev/null
+++ b/jni/mac/FunctionObject.h
@@ -0,0 +1,43 @@
+// Copyright 2005 Google Inc.
+// All Rights Reserved.
+
+#ifndef FUNCTION_OBJECT_H
+#define FUNCTION_OBJECT_H
+
+#include "gwt-webkit.h"
+#include <kjs/object.h>
+
+class FunctionObject : public KJS::JSObject {
+protected:
+    FunctionObject(const KJS::UString& name);
+
+public:
+    const KJS::ClassInfo *classInfo() const { return &info; }
+
+	// shared implementations of JSObject methods
+    virtual bool getOwnPropertySlot(KJS::ExecState*, const KJS::Identifier&, KJS::PropertySlot&);
+    virtual bool canPut(KJS::ExecState*, const KJS::Identifier&) const;
+    virtual void put(KJS::ExecState*, const KJS::Identifier&, KJS::JSValue*, int);
+    virtual bool deleteProperty(KJS::ExecState*, const KJS::Identifier&);
+    virtual KJS::JSValue *defaultValue(KJS::ExecState*, KJS::JSType) const;
+    virtual bool implementsCall() const;
+	
+	// subclasses must implement
+    virtual KJS::JSValue *callAsFunction(KJS::ExecState*, KJS::JSObject*, const KJS::List&) = 0;
+    
+    static const KJS::ClassInfo info;
+
+private:
+	static KJS::JSValue* getter(KJS::ExecState*, KJS::JSObject*, const KJS::Identifier&, const KJS::PropertySlot&);
+
+private:
+	KJS::UString name;
+};
+
+class ToStringFunction : public FunctionObject {
+public:
+	ToStringFunction();
+    virtual KJS::JSValue *callAsFunction(KJS::ExecState*, KJS::JSObject*, const KJS::List&);
+};
+
+#endif
diff --git a/jni/mac/JStringWrap.h b/jni/mac/JStringWrap.h
new file mode 100644
index 0000000..2bb5c35
--- /dev/null
+++ b/jni/mac/JStringWrap.h
@@ -0,0 +1,23 @@
+// Copyright 2005 Google Inc.
+// All Rights Reserved.
+
+#ifndef JSTRINGWRAP_H
+#define JSTRINGWRAP_H
+
+#include <jni.h>
+
+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..ea0cf31
--- /dev/null
+++ b/jni/mac/Makefile
@@ -0,0 +1,31 @@
+# NOTE: THIS MAKEFILE DOES NOT WORK IN OUR BUILD SYSTEM. IT IS USED
+# TO DO THE ISOLATED BUILD OF THE MAC LIBS AND DEPENDS ON A DIFFERENT
+# DIRECTORY STRUCTURE. IT IS PUT HERE FOR ARCHIVE ONLY.
+
+GWT_LIB=../dist/libgwt-ll.jnilib
+
+CC = g++
+ARCHS = -arch i386 -arch ppc
+CFLAGS = -Wall -c $(ARCHS) -DCARBON -I /System/Library/Frameworks/JavaVM.framework/Headers -fno-exceptions -fno-rtti
+LFLAGS = -bundle $(ARCHS) -isysroot /Developer/SDKs/MacOSX10.4u.sdk
+WEBKITCFLAGS = $(CFLAGS)  -I../WebKit-15921/JavaScriptCore
+WEBKITLFLAGS = $(LFLAGS) -framework JavaScriptCore -F../dist/Frameworks
+GWT_OBJECTS = gwt-ll.o
+WEBKIT_OBJECTS = gwt-webkit.o DispWrapper.o FuncWrapper.o FunctionObject.o
+
+all: $(GWT_LIB)
+
+%.o: %.cpp
+	$(CC) -c -o $@ $< $(WEBKITCFLAGS)
+
+gwt-ll.o: ../gwt-ll-core/gwt-ll.cpp
+	$(CC) $(CFLAGS) gwt-ll.cpp
+
+$(GWT_LIB): $(GWT_OBJECTS) $(WEBKIT_OBJECTS)
+	$(CC) -o $(WEBKIT_LIB) $(WEBKITLFLAGS) $(WEBKIT_OBJECTS)
+
+install: all
+	cp *.jnilib $(OUTPUT_DIR)
+
+clean:
+	rm -f $(GWT_LIB) $(WEBKIT_LIB) *.o
diff --git a/jni/mac/build.xml b/jni/mac/build.xml
new file mode 100755
index 0000000..37146d8
--- /dev/null
+++ b/jni/mac/build.xml
@@ -0,0 +1,20 @@
+<project name="jni-mac" default="all" 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>

+

+	<target name="all" depends="build" description="Builds and packages this project" />

+</project>

diff --git a/jni/mac/gwt-ll.h b/jni/mac/gwt-ll.h
new file mode 100644
index 0000000..a2df826
--- /dev/null
+++ b/jni/mac/gwt-ll.h
@@ -0,0 +1,237 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class com_google_gwt_dev_shell_mac_LowLevelSaf */
+
+#ifndef _Included_com_google_gwt_dev_shell_mac_LowLevelSaf
+#define _Included_com_google_gwt_dev_shell_mac_LowLevelSaf
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    isNull
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isNull
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    isUndefined
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isUndefined
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    jsNull
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_jsNull
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    jsUndefined
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_jsUndefined
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _coerceToBoolean
+ * Signature: (II[Z)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1coerceToBoolean
+  (JNIEnv *, jclass, jint, jint, jbooleanArray);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _coerceToDouble
+ * Signature: (II[D)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1coerceToDouble
+  (JNIEnv *, jclass, jint, jint, jdoubleArray);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _coerceToString
+ * Signature: (II[Ljava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1coerceToString
+  (JNIEnv *, jclass, jint, jint, jobjectArray);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _convertBoolean
+ * Signature: (Z[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1convertBoolean
+  (JNIEnv *, jclass,  jboolean, jintArray);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _convertDouble
+ * Signature: (D[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1convertDouble
+  (JNIEnv *, jclass,  jdouble, jintArray);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _convertString
+ * Signature: (Ljava/lang/String;[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1convertString
+  (JNIEnv *, jclass,  jstring, jintArray);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _executeScript
+ * Signature: (ILjava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1executeScript
+  (JNIEnv *, jclass, jint, jstring);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _executeScriptWithInfo
+ * Signature: (ILjava/lang/String;Ljava/lang/String;I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1executeScriptWithInfo
+  (JNIEnv *, jclass, jint, jstring, jstring, jint);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _gcLock
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1gcLock
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _gcUnlock
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1gcUnlock
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _getArgc
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1getArgc
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _getArgv
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1getArgv
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _getGlobalExecState
+ * Signature: (I[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1getGlobalExecState
+  (JNIEnv *, jclass, jint, jintArray);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _initNative
+ * Signature: (Ljava/lang/Class;Ljava/lang/Class;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1initNative
+  (JNIEnv *, jclass, jclass, jclass);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _invoke
+ * Signature: (IILjava/lang/String;II[I[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1invoke
+  (JNIEnv *, jclass, jint, jint, jstring, jint, jint, jintArray, jintArray);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _isObject
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1isObject
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _isString
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1isString
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _isWrappedDispatch
+ * Signature: (I[Z)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1isWrappedDispatch
+  (JNIEnv *, jclass, jint, jbooleanArray);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _jsLock
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1jsLock
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _jsUnlock
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1jsUnlock
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _raiseJavaScriptException
+ * Signature: (II)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1raiseJavaScriptException
+  (JNIEnv *, jclass, jint, jint);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _unwrapDispatch
+ * Signature: (I[Lcom/google/gwt/dev/shell/mac/LowLevelSaf/DispatchObject;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1unwrapDispatch
+  (JNIEnv *, jclass, jint, jobjectArray);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _wrapDispatch
+ * Signature: (Lcom/google/gwt/dev/shell/mac/LowLevelSaf/DispatchObject;[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1wrapDispatch
+  (JNIEnv *, jclass, jobject, jintArray);
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _wrapFunction
+ * Signature: (Ljava/lang/String;Lcom/google/gwt/dev/shell/mac/LowLevelSaf/DispatchMethod;[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1wrapFunction
+  (JNIEnv *, jclass, jstring, jobject, jintArray);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/jni/mac/gwt-webkit.cpp b/jni/mac/gwt-webkit.cpp
new file mode 100644
index 0000000..ec2dfaf
--- /dev/null
+++ b/jni/mac/gwt-webkit.cpp
@@ -0,0 +1,609 @@
+// Copyright 2005 Google Inc.
+// All Rights Reserved.
+
+#include "gwt-ll.h"
+#include "DispWrapper.h"
+#include "FuncWrapper.h"
+
+JNIEnv* gEnv;
+jclass gClass;
+jclass gDispObjCls;
+jclass gDispMethCls;
+jmethodID gGetFieldMeth;
+jmethodID gSetFieldMeth;
+jmethodID gInvokeMeth;
+jmethodID gToStringMeth;
+
+using namespace KJS;
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    isNull
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isNull
+  (JNIEnv *env, jclass, jint jsval) {
+    TRACE("ENTER Java_com_google_gwt_dev_shell_mac_LowLevelSaf__isNull");
+
+  JSValue* val = (JSValue*)jsval;
+  if (!val)
+    return JNI_FALSE;
+
+    TRACE("SUCESS Java_com_google_gwt_dev_shell_mac_LowLevelSaf__isNull");
+  return val->isNull();
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    isUndefined
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isUndefined
+  (JNIEnv *env, jclass, jint jsval) {
+    TRACE("ENTER Java_com_google_gwt_dev_shell_mac_LowLevelSaf__isUndefined");
+  JSValue* val = (JSValue*)jsval;
+  if (!val)
+    return JNI_FALSE;
+
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_mac_LowLevelSaf__isUndefined");
+  return val->isUndefined();
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    jsNull
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_jsNull
+  (JNIEnv *, jclass) {
+  return (jint)jsNull();
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    jsUndefined
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_jsUndefined
+  (JNIEnv *env, jclass) {
+    return (jint)jsUndefined();
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _coerceToBoolean
+ * Signature: (II[Z)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1coerceToBoolean
+  (JNIEnv * env, jclass, jint execState, jint jsval, jbooleanArray rval) {
+    TRACE("ENTER Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1coerceToBoolean");
+
+  if (!execState || !jsval)
+    return JNI_FALSE;
+
+  jboolean result = ((JSValue*)jsval)->toBoolean((ExecState*)execState);
+  env->SetBooleanArrayRegion(rval, 0, 1, &result);
+  if (env->ExceptionCheck())
+      return JNI_FALSE;
+
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1coerceToBoolean");
+  return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _coerceToDouble
+ * Signature: (II[D)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1coerceToDouble
+  (JNIEnv *env, jclass, jint execState, jint jsval, jdoubleArray rval) {
+    TRACE("ENTER Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1coerceToDouble");
+
+  if (!execState || !jsval)
+    return JNI_FALSE;
+
+  jdouble result = ((JSValue*)jsval)->toNumber((ExecState*)execState);
+  env->SetDoubleArrayRegion(rval, 0, 1, &result);
+  if (env->ExceptionCheck())
+      return JNI_FALSE;
+
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1coerceToDouble");
+  return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _coerceToString
+ * Signature: (II[Ljava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1coerceToString
+  (JNIEnv *env, jclass, jint execState, jint jsval, jobjectArray rval) {
+    TRACE("ENTER Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1coerceToString");
+
+  JSValue *val = (JSValue*)jsval;
+  if (!execState || !val)
+    return JNI_FALSE;
+
+  /* 
+   * Convert all objects to their string representation, EXCEPT
+   * null and undefined which will be returned as a true NULL.
+   */
+  jstring result = NULL;
+  if (!val->isNull() && !val->isUndefined()) {
+    UString str = val->toString((ExecState*)execState);
+    result = env->NewString((const jchar*)str.data(), str.size());
+    if (env->ExceptionCheck())
+      return JNI_FALSE;
+  }
+
+  env->SetObjectArrayElement(rval,0,result);
+  if (env->ExceptionCheck())
+    return JNI_FALSE;
+
+  TRACE("SUCCESS Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1coerceToString");
+  return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _convertBoolean
+ * Signature: (IZ[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1convertBoolean
+  (JNIEnv *env, jclass, jboolean jval, jintArray rval) {
+    TRACE("ENTER Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1convertBoolean");
+
+  JSValue *jsval = (jval == JNI_FALSE) ? jsBoolean(false) : jsBoolean(true);
+  if (!jsval)
+    return JNI_FALSE;
+
+  env->SetIntArrayRegion(rval,0,1,(const jint*)&jsval);
+  if (env->ExceptionCheck())
+    return JNI_FALSE;
+  
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1convertBoolean");
+  return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _convertDouble
+ * Signature: (ID[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1convertDouble
+  (JNIEnv *env, jclass, jdouble jval, jintArray rval) {
+    TRACE("ENTER Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1convertDouble");
+
+  JSValue *jsval = jsNumber(jval);
+  if (!jsval)
+    return JNI_FALSE;
+
+  env->SetIntArrayRegion(rval,0,1,(const jint*)&jsval);
+  if (env->ExceptionCheck())
+    return JNI_FALSE;
+
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1convertDouble");
+  return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _convertString
+ * Signature: (ILjava/lang/String;[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1convertString
+  (JNIEnv *env, jclass, jstring jval, jintArray rval) {
+    TRACE("ENTER Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1convertString");
+
+  JStringWrap jstr(env, jval);
+  if (!jstr.jstr())
+    return JNI_FALSE;
+  
+  JSValue *jsval = jsString(UString((const UChar*)jstr.jstr(), jstr.length()));
+  /*
+   * TODO / LEAK / HACK: We will be persisting these objects on the java side,
+   * so in order to keep the JS GC from collecting our objects when they are
+   * away, we need to add them to the protect list. This should be refactored
+   * out in favor of better memory mgmt scheme.
+   */
+  gcProtectNullTolerant(jsval);
+  if (!jsval)
+    return JNI_FALSE;
+
+  env->SetIntArrayRegion(rval,0,1,(const jint*)&jsval);
+  if (env->ExceptionCheck())
+    return JNI_FALSE;
+
+  TRACE("SUCCESS Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1convertString");
+  return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _executeScript
+ * Signature: (ILjava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1executeScript
+  (JNIEnv* env, jclass, jint execState, jstring code) {
+    TRACE("ENTER Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1executeScript"); 
+  if (!execState || !code)
+    return JNI_FALSE;
+
+  JStringWrap jcode(env, code);
+  if (!jcode.jstr())
+    return JNI_FALSE;
+
+  Interpreter* interp = ((ExecState*)execState)->dynamicInterpreter();
+  if (!interp)
+    return JNI_FALSE;
+
+  interp->evaluate(UString(), 0, (const UChar*)jcode.jstr(), jcode.length());
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1executeScript");
+  return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _executeScriptWithInfo
+ * Signature: (ILjava/lang/String;Ljava/lang/String;I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1executeScriptWithInfo
+  (JNIEnv* env, jclass, jint execState, jstring code, jstring file, jint line) {
+    TRACE("ENTER Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1executeScriptWithInfo");
+  if (!execState || !code || !file)
+    return JNI_FALSE;
+
+  JStringWrap jcode(env, code);
+  if (!jcode.jstr())
+    return JNI_FALSE;
+
+  JStringWrap jfile(env, file);
+  if (!jcode.jstr())
+    return JNI_FALSE;
+
+  Interpreter* interp = ((ExecState*)execState)->dynamicInterpreter();
+  if (!interp)
+    return JNI_FALSE;
+
+  interp->evaluate(UString((const UChar*)jfile.jstr(), jfile.length()), line, (const UChar*)jcode.jstr(), jcode.length());
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1executeScriptWithInfo");
+  return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _gcLock
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1gcLock
+  (JNIEnv *, jclass, jint jsval) {
+  gcProtectNullTolerant((JSValue*)jsval);
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _gcUnlock
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1gcUnlock
+  (JNIEnv *, jclass, jint jsval) {
+  gcUnprotectNullTolerant((JSValue*)jsval);
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _getGlobalExecState
+ * Signature: (I[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1getGlobalExecState
+  (JNIEnv *env, jclass, jint scriptObject, jintArray rval) {
+    TRACE("ENTER Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1getGlobalExecState");
+
+  if (!scriptObject || !((JSValue*)scriptObject)->isObject())
+    return JNI_FALSE;
+
+  Interpreter* interp = Interpreter::interpreterWithGlobalObject((JSObject*)scriptObject);
+  if (!interp)
+    return JNI_FALSE;
+
+  ExecState* execState = interp->globalExec();
+    env->SetIntArrayRegion(rval, 0, 1, (jint*)&execState);
+    if (env->ExceptionCheck())
+        return JNI_FALSE;
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1getGlobalExecState");
+  return JNI_TRUE;
+
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _initNative
+ * Signature: (Ljava/lang/Class;Ljava/lang/Class;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1initNative
+  (JNIEnv* env, jclass llClass, jclass dispObjCls, jclass dispMethCls) {
+  Interpreter::setShouldPrintExceptions(true);
+  gEnv = env;
+  gClass =  static_cast<jclass>(env->NewGlobalRef(llClass));
+  gDispObjCls = static_cast<jclass>(env->NewGlobalRef(dispObjCls));
+  gDispMethCls = static_cast<jclass>(env->NewGlobalRef(dispMethCls));
+  if (!gClass || !gDispObjCls || !gDispMethCls || env->ExceptionCheck()) {
+    return false;
+  }
+
+  gGetFieldMeth = env->GetMethodID(gDispObjCls, "getField", "(Ljava/lang/String;)I");
+  gSetFieldMeth = env->GetMethodID(gDispObjCls, "setField", "(Ljava/lang/String;I)V");
+  gInvokeMeth = env->GetMethodID(gDispMethCls, "invoke", "(II[I)I");
+  gToStringMeth = env->GetMethodID(gDispObjCls, "toString", "()Ljava/lang/String;");
+  if (!gGetFieldMeth || !gSetFieldMeth || !gInvokeMeth || !gToStringMeth || env->ExceptionCheck()) {
+    return false;
+  }
+
+#ifdef FILETRACE
+    gout = fopen("gwt-ll.log", "w");
+    filetrace("LOG STARTED");
+#endif // FILETRACE
+
+#ifdef JAVATRACE
+    gTraceMethod = env->GetStaticMethodID(gClass, "trace", "(Ljava/lang/String;)V");
+    if (!gTraceMethod || env->ExceptionCheck())
+        return false;
+#endif // JAVATRACE
+
+  return true;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _invoke
+ * Signature: (IILjava/lang/String;II[I[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1invoke
+  (JNIEnv* env, jclass, jint jsexecState, jint jsScriptObject, jstring method, jint jsthis, jint argc, jintArray argv, jintArray rval) {
+    TRACE("ENTER Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1invoke");
+
+  if (!jsexecState || !jsScriptObject || !method || !rval)
+    return JNI_FALSE;
+  
+  ExecState* execState = (ExecState*)jsexecState;
+
+  JSObject* scriptObj = (JSObject*)jsScriptObject;
+  if (!scriptObj->isObject())
+    return JNI_FALSE;
+
+  JStringWrap jmethod(env, method);
+  if (!jmethod.jstr())
+    return JNI_FALSE;
+
+  JSObject* thisObj = (JSObject*)jsthis;
+  if (!thisObj || thisObj->isNull() || thisObj->isUndefined()) {
+    thisObj = scriptObj;
+  }
+  if (!thisObj->isObject())
+    return JNI_FALSE;
+
+  JSValue* maybeFunc = scriptObj->get(execState, Identifier((const UChar*)jmethod.jstr(), jmethod.length()));
+  if (!maybeFunc || !maybeFunc->isObject())
+    return JNI_FALSE;
+  
+  JSObject* func = (JSObject*)maybeFunc;
+  if (!func->implementsCall())
+    return JNI_FALSE;
+
+  List args;
+  for (int i = 0; i < argc; ++i) {
+    jint argi;
+    env->GetIntArrayRegion(argv, i, 1, &argi);
+    if (env->ExceptionCheck())
+      return JNI_FALSE;
+
+    if (argi) {
+      args.append((JSValue*)argi);
+    } else {
+      args.append(jsNull());
+    }
+  }
+
+  JSValue* result = func->call(execState, thisObj, args);
+    env->SetIntArrayRegion(rval, 0, 1, (jint*)&result);
+    if (env->ExceptionCheck())
+        return JNI_FALSE;
+
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1invoke");
+  return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _isObject
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1isObject
+  (JNIEnv *, jclass, jint jsval) {
+  if (!jsval)
+    return JNI_FALSE;
+  return ((JSValue*)jsval)->isObject() ? JNI_TRUE : JNI_FALSE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _isString
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1isString
+  (JNIEnv *, jclass, jint jsval) {
+  if (!jsval)
+    return JNI_FALSE;
+  return ((JSValue*)jsval)->isString() ? JNI_TRUE : JNI_FALSE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _isWrappedDispatch
+ * Signature: (I[Z)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1isWrappedDispatch
+  (JNIEnv* env, jclass, jint jsval, jbooleanArray rval) {
+    TRACE("ENTER Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1isWrappedDispatch");
+  if (!jsval)
+    return JNI_FALSE;
+
+  JSValue* val = (JSValue*)jsval;
+  jboolean result = val->isObject(&DispWrapper::info) ? JNI_TRUE : JNI_FALSE;
+
+    env->SetBooleanArrayRegion(rval, 0, 1, &result);
+    if (env->ExceptionCheck())
+        return JNI_FALSE;
+
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1isWrappedDispatch");
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _jsLock
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1jsLock
+  (JNIEnv *, jclass) {
+  JSLock::lock();
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _jsUnlock
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1jsUnlock
+  (JNIEnv *, jclass) {
+  JSLock::unlock();
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _raiseJavaScriptException
+ * Signature: (II)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1raiseJavaScriptException
+  (JNIEnv *env, jclass, jint execState, jint jsval) {
+    TRACE("ENTER Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1raiseJavaScriptException");
+
+  if (!execState || !jsval)
+    return JNI_FALSE;
+
+  ((ExecState*)execState)->setException((JSValue*)jsval);
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1raiseJavaScriptException");
+  return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _unwrapDispatch
+ * Signature: (I[Lcom/google/gwt/dev/shell/mac/LowLevelSaf/DispatchObject;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1unwrapDispatch
+  (JNIEnv* env, jclass, jint jsval, jobjectArray rval) {
+    TRACE("ENTER Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1unwrapDispatch");
+  if (!jsval)
+    return JNI_FALSE;
+
+  JSValue* val = (JSValue*)jsval;
+  if (!val->isObject(&DispWrapper::info))
+    return JNI_FALSE;
+
+  DispWrapper* wrapper = static_cast<DispWrapper*>(val);
+    env->SetObjectArrayElement(rval, 0, wrapper->getDispObj());
+    if (env->ExceptionCheck())
+        return JNI_FALSE;
+
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1unwrapDispatch");
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _wrapDispatch
+ * Signature: (Lcom/google/gwt/dev/shell/mac/LowLevelSaf/DispatchObject;[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1wrapDispatch
+  (JNIEnv* env, jclass, jobject dispObj, jintArray rval) {
+    TRACE("ENTER Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1wrapDispatch");
+
+    jobject dispObjRef = env->NewGlobalRef(dispObj);
+    if (!dispObjRef || env->ExceptionCheck())
+        return JNI_FALSE;
+  
+  DispWrapper* wrapper = new DispWrapper(dispObjRef);
+  /*
+   * TODO / LEAK / HACK: We will be persisting these objects on the java side,
+   * so in order to keep the JS GC from collecting our objects when they are
+   * away, we need to add them to the protect list. This should be refactored
+   * out in favor of better memory mgmt scheme.
+   */
+  gcProtectNullTolerant(wrapper);
+    env->SetIntArrayRegion(rval, 0, 1, (jint*)&wrapper);
+    if (env->ExceptionCheck())
+        return JNI_FALSE;
+
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1wrapDispatch");
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     com_google_gwt_dev_shell_mac_LowLevelSaf
+ * Method:    _wrapFunction
+ * Signature: (Ljava/lang/String;Lcom/google/gwt/dev/shell/mac/LowLevelSaf/DispatchMethod;[I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1wrapFunction
+  (JNIEnv* env, jclass, jstring name, jobject dispMeth, jintArray rval) {
+    TRACE("ENTER Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1wrapFunction");
+
+    jobject dispMethRef = env->NewGlobalRef(dispMeth);
+    if (!dispMethRef || env->ExceptionCheck())
+        return JNI_FALSE;
+  
+  JStringWrap jname(env, name);
+  if (!jname.jstr())
+    return JNI_FALSE;
+  
+  FuncWrapper* wrapper = new FuncWrapper(UString((const UChar*)jname.jstr(), jname.length()), dispMethRef);
+  /*
+   * TODO / LEAK / HACK: We will be persisting these objects on the java side,
+   * so in order to keep the JS GC from collecting our objects when they are
+   * away, we need to add them to the protect list. This should be refactored
+   * out in favor of better memory mgmt scheme.
+   */
+  gcProtectNullTolerant(wrapper);
+    env->SetIntArrayRegion(rval, 0, 1, (jint*)&wrapper);
+    if (env->ExceptionCheck())
+        return JNI_FALSE;
+
+    TRACE("SUCCESS Java_com_google_gwt_dev_shell_mac_LowLevelSaf__1wrapFunction");
+    return JNI_TRUE;
+}
+
+#ifdef FILETRACE
+FILE* gout = 0;
+void filetrace(const char* s)
+{
+    fprintf(gout, s);
+    fprintf(gout, "\n");
+    fflush(gout);
+}
+#endif // FILETRACE
+
+#ifdef JAVATRACE
+jmethodID gTraceMethod = 0;
+void javatrace(const char* s)
+{
+    if (!gEnv->ExceptionCheck())
+    {
+        jstring out = gEnv->NewStringUTF(s);
+        if (!gEnv->ExceptionCheck())
+            gEnv->CallStaticVoidMethod(gClass, gTraceMethod, out);
+        else
+            gEnv->ExceptionClear();
+    }
+}
+#endif // JAVATRACE
+
diff --git a/jni/mac/gwt-webkit.h b/jni/mac/gwt-webkit.h
new file mode 100644
index 0000000..88db9f7
--- /dev/null
+++ b/jni/mac/gwt-webkit.h
@@ -0,0 +1,41 @@
+// Copyright 2005 Google Inc.
+// All Rights Reserved.
+
+#ifndef GWT_WEBKIT_H
+#define GWT_WEBKIT_H
+
+#include <jni.h>
+#include "JStringWrap.h"
+
+extern JNIEnv* gEnv;
+extern jclass gClass;
+extern jclass gDispObjCls;
+extern jclass gDispMethCls;
+extern jmethodID gSetFieldMeth;
+extern jmethodID gGetFieldMeth;
+extern jmethodID gInvokeMeth;
+extern jmethodID gToStringMeth;
+
+//#define FILETRACE
+//#define JAVATRACE
+#if defined(FILETRACE) && defined(JAVATRACE)
+#define TRACE(s) filetrace(s),javatrace(s)
+#elif defined(FILETRACE)
+#define TRACE(s) filetrace(s)
+#elif defined(JAVATRACE)
+#define TRACE(s) javatrace(s)
+#else
+#define TRACE(s) ((void)0)
+#endif
+
+#ifdef FILETRACE
+extern FILE* gout;
+void filetrace(const char* s);
+#endif // FILETRACE
+
+#ifdef JAVATRACE
+extern jmethodID gTraceMethod;
+void javatrace(const char* s);
+#endif // JAVATRACE
+
+#endif
diff --git a/jni/mac/prebuilt/libgwt-ll.jnilib b/jni/mac/prebuilt/libgwt-ll.jnilib
new file mode 100755
index 0000000..2d036c6
--- /dev/null
+++ b/jni/mac/prebuilt/libgwt-ll.jnilib
Binary files differ
diff --git a/jni/mac/prebuilt/libgwt-webkit.jnilib b/jni/mac/prebuilt/libgwt-webkit.jnilib
new file mode 100755
index 0000000..0fdd5b4
--- /dev/null
+++ b/jni/mac/prebuilt/libgwt-webkit.jnilib
Binary files differ
diff --git a/jni/windows/IE6.cpp b/jni/windows/IE6.cpp
new file mode 100644
index 0000000..0014768
--- /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..b00624c
--- /dev/null
+++ b/jni/windows/Makefile
@@ -0,0 +1,107 @@
+# Copyright 2006 Google Inc. All Rights Reserved.
+#
+#-------------------------------------------------------------------------------
+# Macros
+#-------------------------------------------------------------------------------
+SHELL   = /bin/sh
+
+##
+# Target settings
+##
+ROOTDIR = ./
+PROGNAME:= gwt-ll
+PROG    := $(PROGNAME).dll
+PROGDIR := ./
+OBJDIR  := $(PROGDIR)objs/
+OUT     := $(PROGDIR)image/$(PROG)
+
+##
+# 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 := ./:../gwt-ll-core/
+VPATH   := .:../gwt-ll-core
+SRCS    := gwt-ll.cpp IE6.cpp
+OBJS    := $(addprefix $(OBJDIR),$(SRCS:.cpp=.o))
+DEPS    := $(addprefix $(OBJDIR),$(SRCS:.cpp=.d))
+
+##
+# Include path configuration
+##
+SYSINCS := $(ROOTDIR)../../third_party/j2sdk1.4.2_09/include \
+           $(ROOTDIR)../../third_party/j2sdk1.4.2_09/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)
+
+##
+# Clean macros
+##
+CLEANDIRS := $(CLEANDIRS) $(OBJDIR)
+CLEANFILES := $(CLEANFILES) $(OUT)
+
+#-------------------------------------------------------------------------------
+# Rules
+#-------------------------------------------------------------------------------
+
+##
+# default rule
+##
+all: $(OBJDIR)libwininet.a $(OUT)
+
+##
+# 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)
+	@[ -d $(PROGDIR) ] || mkdir -p $(PROGDIR)
+	@[ -d $(PROGDIR)image ] || mkdir -p $(PROGDIR)image
+	$(LD) -shared $(LDFLAGS) $(LIBPATH) -o $@ $^ $(LIBS)
+	$(STRIP) --strip-unneeded $@
+
+##
+# Clean rule
+##
+clean: clean-wininet
+	@-rm -f $(CLEANFILES)
+	@-rm -rf $(CLEANDIRS)
+	
+clean-wininet:
+	@-rm -f $(OBJDIR)libwininet.a
+	
diff --git a/jni/windows/build.xml b/jni/windows/build.xml
new file mode 100755
index 0000000..9c65e9a
--- /dev/null
+++ b/jni/windows/build.xml
@@ -0,0 +1,20 @@
+<project name="jni-windows" default="all" 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>

+

+	<target name="all" depends="build" description="Builds and packages this project" />

+</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__