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

Patch by: scottb
Review by: jat


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6390 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/jni/mac/JStringWrap.h b/jni/mac/JStringWrap.h
new file mode 100644
index 0000000..e17981f
--- /dev/null
+++ b/jni/mac/JStringWrap.h
@@ -0,0 +1,42 @@
+/* 
+ * Copyright 2007 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+#ifndef JSTRINGWRAP_H
+#define JSTRINGWRAP_H
+
+#include <jni.h>
+
+/*
+ * Wrap a Java String and automatically clean up temporary storage allocated
+ * for accessing its contents.
+ */
+struct JStringWrap
+{
+  JStringWrap(JNIEnv* env, jstring str): env(env), s(str), p(0), jp(0) { }
+  ~JStringWrap() {
+  	if (p) env->ReleaseStringUTFChars(s, p);
+  	if (jp) env->ReleaseStringChars(s, jp);
+  }
+  const char* str() { if (!p) p = env->GetStringUTFChars(s, 0); return p; }
+  const jchar* jstr() { if (!jp) jp = env->GetStringChars(s, 0); return jp; }
+  jsize length() { return env->GetStringLength(s); }
+private:
+  JNIEnv* env;
+  jstring s;
+  const char* p;
+  const jchar* jp;
+};
+
+#endif
diff --git a/jni/mac/Makefile b/jni/mac/Makefile
new file mode 100644
index 0000000..867b511
--- /dev/null
+++ b/jni/mac/Makefile
@@ -0,0 +1,89 @@
+# Copyright 2008 Google Inc.
+# 
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+# 
+# http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+CC = g++
+JAVAH = javah
+
+##
+# Try a GWT_TOOLS default if it isn't set
+##
+GWT_TOOLS ?= ../../../tools
+GWT_ROOT ?= ../..
+
+##
+# The location to get .class files for javah
+##
+CLASSDIR := $(GWT_ROOT)/build/out/dev/mac/bin
+
+##
+# External SWT products.
+##
+SWT_ORIGINAL_SRC = $(GWT_TOOLS)/lib/eclipse/org.eclipse.swt.carbon-macosx-3.2.1.src.zip
+SWT_PATCH_DIR = ./swt-build
+SWT_LIBS=$(SWT_PATCH_DIR)/libswt-webkit-carbon-3235.jnilib \
+	$(SWT_PATCH_DIR)/libswt-agl-carbon-3235.jnilib \
+	$(SWT_PATCH_DIR)/libswt-carbon-3235.jnilib \
+	$(SWT_PATCH_DIR)/libswt-pi-carbon-3235.jnilib
+
+GWT_LL_LIB = libgwt-ll.jnilib
+GWT_LL_OBJS = gwt-ll.o java-dispatch.o gwt-webkit.o trace.o
+GWT_LL_JNI = gwt-webkit.h
+
+TARGETS = $(GWT_LL_LIB) $(SWT_LIBS)
+ARCHS = -arch i386 -arch ppc
+CFLAGS = -I/System/Library/Frameworks/JavaScriptCore.framework/Headers -I/System/Library/Frameworks/JavaVM.framework/Headers
+LFLAGS = -bundle -framework JavaScriptCore
+
+ALL : $(TARGETS)
+
+##
+# Unpack and patch SWT source.
+##
+$(SWT_PATCH_DIR): $(SWT_ORIGINAL_SRC) ./org.eclipse.swt/webkit.c
+	unzip $(SWT_ORIGINAL_SRC) -d $(SWT_PATCH_DIR)
+	cp ./org.eclipse.swt/webkit.c  $(SWT_PATCH_DIR)
+
+##
+# Build SWT.
+##
+$(SWT_LIBS):$(SWT_PATCH_DIR)
+	make -C $(SWT_PATCH_DIR) -f make_macosx.mak
+
+##
+# Build core gwt-ll object.
+##
+gwt-ll.o : ../core/gwt-ll.cpp
+	$(CC) -c -Wall -o $@ $(ARCHS) $(CFLAGS) $<
+
+##
+# General coff target.
+##
+%.o : %.cpp
+	$(CC) -c -Wall -o $@ $(ARCHS) $(CFLAGS) $<
+
+##
+# Generate JNI Header
+##
+gwt-webkit.h : $(CLASSDIR)/com/google/gwt/dev/shell/mac/LowLevelSaf.class
+	$(JAVAH) -classpath $(CLASSDIR) -o gwt-webkit.h com.google.gwt.dev.shell.mac.LowLevelSaf
+
+##
+# Build gwt-ll library.
+##
+$(GWT_LL_LIB) : $(GWT_LL_JNI) $(GWT_LL_OBJS)
+	$(CC) -Wall -o $@ $(ARCHS) $(LFLAGS) $(GWT_LL_OBJS)
+
+clean:
+	rm -f $(GWT_LL_JNI) $(GWT_LL_OBJS) $(TARGETS)
+	rm -rf $(SWT_PATCH_DIR)
diff --git a/jni/mac/build.xml b/jni/mac/build.xml
new file mode 100755
index 0000000..66b6580
--- /dev/null
+++ b/jni/mac/build.xml
@@ -0,0 +1,18 @@
+<project name="jni-mac" default="build" basedir=".">
+  <property name="gwt.root" location="../.." />
+  <property name="project.tail" value="jni/mac" />
+  <import file="${gwt.root}/common.ant.xml" />
+
+  <target name="build" description="Builds a JNI lib">
+    <mkdir dir="${project.jni}" />
+    <!-- TODO: Actually build this from source! -->
+    <copy todir="${project.jni}">
+      <fileset dir="prebuilt" />
+    </copy>
+  </target>
+
+  <target name="clean" description="Cleans this project's intermediate and output files">
+    <delete dir="${project.build}" failonerror="false" />
+    <delete dir="${project.jni}" failonerror="false" />
+  </target>
+</project>
diff --git a/jni/mac/gwt-webkit.cpp b/jni/mac/gwt-webkit.cpp
new file mode 100644
index 0000000..477b312
--- /dev/null
+++ b/jni/mac/gwt-webkit.cpp
@@ -0,0 +1,886 @@
+/*
+ * Copyright 2008 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <iostream>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include "gwt-webkit.h"
+#include "JStringWrap.h"
+#include "java-dispatch.h"
+#include "trace.h"
+
+
+// http://unixjunkie.blogspot.com/2006/07/access-argc-and-argv-from-anywhere.html
+extern "C" int *_NSGetArgc(void);
+extern "C" char ***_NSGetArgv(void);
+
+/*
+ *
+ */
+JSContextRef ToJSContextRef(jint context) {
+  return reinterpret_cast<JSContextRef>(context);
+}
+
+/*
+ *
+ */
+JSValueRef ToJSValueRef(jint value) {
+  return reinterpret_cast<JSValueRef>(value);
+}
+
+/*
+ *
+ */
+JSObjectRef ToJSObjectRef(JSContextRef jsContext, jint object,
+    JSValueRef* jsException) {
+  JSValueRef jsValue = reinterpret_cast<JSValueRef>(object);
+  if (!jsValue || !JSValueIsObject(jsContext, jsValue)) {
+    return NULL;
+  }
+  return JSValueToObject(jsContext, jsValue, jsException);
+}
+
+/*
+ *
+ */
+JSObjectRef ToJSObjectRef(JSContextRef jsContext, JSValueRef jsValue,
+    JSValueRef* jsException) {
+  if (!jsValue || !JSValueIsObject(jsContext, jsValue)) {
+    return NULL;
+  }
+  return JSValueToObject(jsContext, jsValue, jsException);
+}
+
+/*
+ *
+ */
+JSObjectRef GetStringConstructor(JSContextRef jsContext,
+    JSValueRef* jsException) {
+  // This could only be cached relative to jsContext.
+  JSStringRef script = JSStringCreateWithUTF8CString("(String)");
+  JSValueRef ctorVal = JSEvaluateScript(jsContext, script, NULL, NULL, 0, jsException);
+  JSStringRelease(script);
+  return ToJSObjectRef(jsContext, ctorVal, jsException);
+}
+
+/*
+ *
+ */
+bool IsObjectOfStringConstructor(JSContextRef jsContext, JSValueRef jsValue,
+    JSValueRef* jsException) {
+  JSObjectRef jsObject = ToJSObjectRef(jsContext, jsValue, jsException);
+  if (!jsObject) {
+    return false;
+  }
+  JSObjectRef stringCtor = GetStringConstructor(jsContext, jsException);
+  if (!stringCtor) {
+    return false;
+  }
+  return JSValueIsInstanceOfConstructor(jsContext, jsObject, stringCtor,
+      jsException);
+}
+
+#if 0 // For debugging purposes only.
+void PrintJSString(JSStringRef jsString)
+{
+  size_t length = JSStringGetMaximumUTF8CStringSize(jsString);
+  char* buffer = new char[length];
+  JSStringGetUTF8CString(jsString, buffer, length);
+  std::cerr << "JSString: " << buffer << std::endl;
+  delete[] buffer;
+}
+
+void PrintJSValue(JSContextRef jsContext, JSValueRef jsValue)
+{
+  JSValueRef jsException = NULL;
+  JSStringRef jsResult = JSValueToStringCopy(jsContext, jsValue,
+      &jsException);
+  if (!jsException && jsValue) {
+    PrintJSString(jsResult);
+  } else {
+    std::cerr << "Could not convert the value to string." << std::endl;
+  }
+}
+#endif
+
+/*
+ *
+ */
+JSStringRef ToJSStringRef(JNIEnv* env, jstring jstr) {
+  if (!jstr) {
+    return NULL;
+  }
+
+  JStringWrap jstrw(env, jstr);
+  if (!jstrw.jstr()) {
+    return NULL;
+  }
+
+  return JSStringCreateWithCharacters(static_cast<const JSChar*>(jstrw.jstr()),
+      static_cast<size_t>(jstrw.length()));
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsNull
+    (JNIEnv *env, jclass klass, jint context, jint value) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+  TR_LEAVE();
+  return static_cast<jboolean>(JSValueIsNull(jsContext, jsValue));
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsUndefined
+    (JNIEnv *env, jclass klass, jint context, jint value) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+  TR_LEAVE();
+  return static_cast<jboolean>(JSValueIsUndefined(jsContext, jsValue));
+}
+
+/*
+ *
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getJsUndefined
+    (JNIEnv *env, jclass klass, jint context) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  if (!jsContext) {
+    return static_cast<jint>(NULL);
+  }
+
+  JSValueRef jsUndefined = JSValueMakeUndefined(jsContext);
+  JSValueProtectChecked(jsContext, jsUndefined);
+  TR_LEAVE();
+  return reinterpret_cast<jint>(jsUndefined);
+}
+
+/*
+ *
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getJsNull
+    (JNIEnv *env, jclass klass, jint context) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  if (!jsContext) {
+    return static_cast<jint>(NULL);
+  }
+  JSValueRef jsNull = JSValueMakeNull(jsContext);
+  JSValueProtectChecked(jsContext, jsNull);
+  TR_LEAVE();
+  return reinterpret_cast<jint>(jsNull);
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsBoolean
+    (JNIEnv *env, jclass klass, jint context, jint value) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+  TR_LEAVE();
+  return static_cast<jboolean>(JSValueIsBoolean(jsContext, jsValue));
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsNumber
+    (JNIEnv *env, jclass klass, jint context, jint value) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+  TR_LEAVE();
+  return static_cast<jboolean>(JSValueIsNumber(jsContext, jsValue));
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toJsBooleanImpl
+    (JNIEnv *env, jclass klass, jint context, jboolean jValue, jintArray rval) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  if (!jsContext) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueRef jsValue = JSValueMakeBoolean(jsContext, static_cast<bool>(jValue));
+
+  env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<const jint*>(&jsValue));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+  JSValueProtectChecked(jsContext, jsValue);
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_gcUnprotect
+    (JNIEnv *env, jclass klass, jint context, jint value) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    return;
+  }
+  JSValueUnprotectChecked(jsContext, jsValue);
+  TR_LEAVE();
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toJsNumberImpl
+    (JNIEnv *env, jclass klass, jint context, jdouble jValue, jintArray rval) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  if (!jsContext) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueRef jsValue = JSValueMakeNumber(jsContext, static_cast<jdouble>(jValue));
+
+  env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<const jint*>(&jsValue));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueProtectChecked(jsContext, jsValue);
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_executeScriptWithInfoImpl
+    (JNIEnv *env, jclass klass, jint context, jstring jScript, jstring jUrl,
+    jint jLine, jintArray rval) {
+  TR_ENTER();
+  JSValueRef jsException = NULL;
+
+  JSContextRef jsContext = ToJSContextRef(context);
+  if (!jsContext) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSStringRef jsScript = ToJSStringRef(env, jScript);
+  if (!jsScript) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSStringRef jsUrl = ToJSStringRef(env, jUrl);
+
+  // Evaluate will set this to global object.
+  JSValueRef jsResult = JSEvaluateScript(jsContext, jsScript, NULL, jsUrl,
+      static_cast<int>(jLine), &jsException);
+  if (jsException) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSStringRelease(jsScript);
+  if (jsUrl) {
+    JSStringRelease(jsUrl);
+  }
+
+  env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<const jint*>(&jsResult));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueProtectChecked(jsContext, jsResult);
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toJsStringImpl
+    (JNIEnv *env, jclass klass, jint context, jstring jValue, jintArray rval) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  if (!jsContext) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSStringRef jsString = ToJSStringRef(env, jValue);
+  if (!jsString) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueRef jsValue = JSValueMakeString(jsContext, jsString);
+  JSStringRelease(jsString);
+
+  env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<const jint*>(&jsValue));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueProtectChecked(jsContext, jsValue);
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsStringImpl
+    (JNIEnv *env, jclass klass, jint context, jint value, jbooleanArray rval) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  bool isString = JSValueIsString(jsContext, jsValue);
+  if (!isString) {
+    JSValueRef jsException = NULL;
+    isString = IsObjectOfStringConstructor(jsContext, jsValue, &jsException);
+    if (jsException) {
+      TR_FAIL();
+      return JNI_FALSE;
+    }
+  }
+
+  jboolean jIsString = static_cast<jboolean>(isString);
+  env->SetBooleanArrayRegion(rval, 0, 1, &jIsString);
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_invokeImpl
+    (JNIEnv *env, jclass klass, jint context, jint scriptValue,
+    jstring jMethodName, jint thisVal, jintArray jArgs, jint jArgsLength,
+    jintArray rval) {
+  TR_ENTER();
+
+  JSContextRef jsContext = ToJSContextRef(context);
+  if (!jsContext) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSObjectRef jsScriptObj = ToJSObjectRef(jsContext, scriptValue, NULL);
+  if (!jsScriptObj) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueRef jsThisVal = ToJSValueRef(thisVal);
+  JSObjectRef jsThisObj = NULL;
+  // If thisVal is null, jsNull, or jsUndefined use the script object
+  // as this.
+  if (!jsThisVal || JSValueIsNull(jsContext, jsThisVal)
+      || JSValueIsUndefined(jsContext, jsThisVal)) {
+    jsThisObj = jsScriptObj;
+  } else {
+    // If we are given a value, ensure that it is an object.
+    jsThisObj = ToJSObjectRef(jsContext, jsThisVal, NULL);
+    if (!jsThisObj) {
+      TR_FAIL();
+      return JNI_FALSE;
+    }
+  }
+
+  JSStringRef jsMethodName = ToJSStringRef(env, jMethodName);
+  if (!jsMethodName) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSObjectRef jsMethod = ToJSObjectRef(jsContext, JSObjectGetProperty(jsContext,
+      jsScriptObj, jsMethodName, NULL), NULL);
+  if (!jsMethod || !JSObjectIsFunction(jsContext, jsMethod)) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSStringRelease(jsMethodName);
+
+  // NOTE (knorton): Fix for 64-bit.
+  JSValueRef* jsArgs = new JSValueRef[static_cast<size_t>(jArgsLength)];
+  env->GetIntArrayRegion(jArgs, 0, jArgsLength,
+      reinterpret_cast<jint*>(jsArgs));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    delete[] jsArgs;
+    return JNI_FALSE;
+  }
+
+  JSValueRef jsException = NULL;
+  JSValueRef jsResult = JSObjectCallAsFunction(jsContext, jsMethod, jsThisObj,
+      static_cast<size_t>(jArgsLength), jsArgs, &jsException);
+  if (jsException) {
+    TR_FAIL();
+    delete[] jsArgs;
+    return JNI_FALSE;
+  }
+  delete[] jsArgs;
+
+  env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<const jint*>(&jsResult));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueProtectChecked(jsContext, jsResult);
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsObject
+    (JNIEnv *env, jclass klass, jint context, jint value) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  TR_LEAVE();
+  return static_cast<jboolean>(JSValueIsObject(jsContext, jsValue));
+}
+
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toBooleanImpl
+    (JNIEnv *env, jclass klass, jint context, jint value, jbooleanArray rval) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  jboolean jResult = static_cast<jboolean>(JSValueToBoolean(jsContext, jsValue));
+  env->SetBooleanArrayRegion(rval, 0, 1, &jResult);
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toDoubleImpl
+    (JNIEnv *env, jclass klass, jint context, jint value, jdoubleArray rval) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueRef jsException = NULL;
+  double result = JSValueToNumber(jsContext, jsValue, &jsException);
+  if (jsException) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  env->SetDoubleArrayRegion(rval, 0, 1, static_cast<jdouble*>(&result));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toStringImpl
+    (JNIEnv *env, jclass klass, jint context, jint value, jobjectArray rval) {
+  TR_ENTER();
+  JSValueRef jsException = NULL;
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  jstring jResult = NULL;
+   // Convert all objects to their string representation, EXCEPT
+   // null and undefined which will be returned as a true NULL.
+  if (!JSValueIsNull(jsContext, jsValue) &&
+      !JSValueIsUndefined(jsContext, jsValue)) {
+    JSStringRef jsResult = JSValueToStringCopy(jsContext, jsValue, &jsException);
+    if (jsException) {
+      TR_FAIL();
+      return JNI_FALSE;
+    }
+
+    jResult = env->NewString(
+        static_cast<const jchar*>(JSStringGetCharactersPtr(jsResult)),
+        static_cast<jsize>(JSStringGetLength(jsResult)));
+    if (env->ExceptionCheck()) {
+      TR_FAIL();
+      return JNI_FALSE;
+    }
+
+    JSStringRelease(jsResult);
+  }
+
+  env->SetObjectArrayElement(rval, 0, jResult);
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_wrapDispatchObjectImpl
+    (JNIEnv *env, jclass klass, jint context, jobject dispatch, jintArray rval) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  if (!jsContext) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSObjectRef jsDispatch = gwt::DispatchObjectCreate(jsContext, dispatch);
+  if (!jsDispatch || env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<jint*>(&jsDispatch));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueProtectChecked(jsContext, jsDispatch);
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_unwrapDispatchObjectImpl
+    (JNIEnv *env, jclass klass, jint context, jint value, jobjectArray rval) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  if (!JSValueIsObjectOfClass(jsContext, jsValue, gwt::GetDispatchObjectClass())) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSObjectRef jsObject = ToJSObjectRef(jsContext, jsValue, NULL);
+  if (!jsObject) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  env->SetObjectArrayElement(rval, 0, reinterpret_cast<jobject>(JSObjectGetPrivate(jsObject)));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_initImpl
+    (JNIEnv *env, jclass klass, jclass dispatchObjectClass,
+    jclass dispatchMethodClass, jclass lowLevelSafClass) {
+  TR_ENTER();
+  TR_LEAVE();
+  return static_cast<jboolean>(gwt::Initialize(env, dispatchObjectClass, dispatchMethodClass, lowLevelSafClass));
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_wrapDispatchMethodImpl
+    (JNIEnv *env, jclass klass, jint context, jstring name, jobject jDispatch,
+    jintArray rval) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  if (!jsContext) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JStringWrap nameWrap(env, name);
+  std::string nameStr(nameWrap.str());
+  JSObjectRef jsDispatch = gwt::DispatchMethodCreate(jsContext, nameStr,
+      jDispatch);
+  if (!jsDispatch || env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<jint*>(&jsDispatch));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueProtectChecked(jsContext, jsDispatch);
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jstring JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getTypeString
+    (JNIEnv *env, jclass klass, jint context, jint value) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    return NULL;
+  }
+
+  switch (JSValueGetType(jsContext, jsValue)) {
+    case kJSTypeUndefined:
+      return env->NewStringUTF("undefined");
+    case kJSTypeNull:
+      return env->NewStringUTF("null");
+    case kJSTypeBoolean:
+      return env->NewStringUTF("boolean");
+    case kJSTypeNumber:
+      return env->NewStringUTF("number");
+    case kJSTypeString:
+      return env->NewStringUTF("string");
+    case kJSTypeObject:
+      return (JSValueIsObjectOfClass(jsContext, jsValue, gwt::GetDispatchObjectClass()))
+        ? env->NewStringUTF("Java object") : env->NewStringUTF("JavaScript object");
+    default:
+      return env->NewStringUTF("unknown");
+  }
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isDispatchObjectImpl
+    (JNIEnv *env, jclass klass, jint context, jint value, jbooleanArray rval) {
+  TR_ENTER();
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  jboolean jIsDispatchObject = static_cast<jboolean>(JSValueIsObjectOfClass(
+      jsContext, jsValue, gwt::GetDispatchObjectClass()));
+  env->SetBooleanArrayRegion(rval, 0, 1, &jIsDispatchObject);
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getArgc
+    (JNIEnv *env, jclass klass) {
+  return *_NSGetArgc();
+}
+
+/*
+ *
+ */
+JNIEXPORT jstring JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getArgv
+    (JNIEnv *env, jclass klass, jint index) {
+  int argc = *_NSGetArgc();
+  if (index < 0 || index >= argc) {
+    return 0;
+  }
+  char **argv = *_NSGetArgv();
+  return env->NewStringUTF(argv[index]);
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getGlobalJsObjectImpl
+    (JNIEnv *env, jclass klass, jint context, jintArray rval) {
+  TR_ENTER();
+
+  JSContextRef jsContext = ToJSContextRef(context);
+  if (!jsContext) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSObjectRef jsGlobalObject = JSContextGetGlobalObject(jsContext);
+  env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<jint*>(&jsGlobalObject));
+  if (env->ExceptionCheck()) {
+    TR_FAIL();
+    return JNI_FALSE;
+  }
+
+  JSValueProtectChecked(jsContext, jsGlobalObject);
+
+  TR_LEAVE();
+  return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_gcProtect
+    (JNIEnv *env, jclass klass, jint context, jint value) {
+  TR_ENTER();
+
+  JSContextRef jsContext = ToJSContextRef(context);
+  JSValueRef jsValue = ToJSValueRef(value);
+  if (!jsContext || !jsValue) {
+    return;
+  }
+
+  JSValueProtectChecked(jsContext, jsValue);
+  TR_LEAVE();
+}
+
+/*
+ *
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_retainJsGlobalContext
+    (JNIEnv *env, jclass klass, jint context) {
+  TR_ENTER();
+  JSGlobalContextRef jsContext = reinterpret_cast<JSGlobalContextRef>(context);
+  if (!jsContext) {
+    TR_FAIL();
+    return;
+  }
+  JSGlobalContextRetain(jsContext);
+  TR_LEAVE();
+}
+
+/*
+ *
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_releaseJsGlobalContext
+    (JNIEnv *env, jclass klass, jint context) {
+  TR_ENTER();
+  JSGlobalContextRef jsContext = reinterpret_cast<JSGlobalContextRef>(context);
+  if (!jsContext) {
+    TR_FAIL();
+    return;
+  }
+  JSGlobalContextRelease(jsContext);
+  TR_LEAVE();
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isGcProtected
+    (JNIEnv *env, jclass klass, jint value) {
+  JSValueRef jsValue = ToJSValueRef(value);
+  TR_ENTER();
+  TR_LEAVE();
+  return static_cast<jboolean>(JSValueIsProtected(jsValue));
+}
+
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsValueProtectionCheckingEnabledImpl
+    (JNIEnv *env, jclass klass) {
+  TR_ENTER();
+  TR_LEAVE();
+  return static_cast<jboolean>(JSValueProtectCheckingIsEnabled());
+}
diff --git a/jni/mac/java-dispatch.cpp b/jni/mac/java-dispatch.cpp
new file mode 100644
index 0000000..fafab11
--- /dev/null
+++ b/jni/mac/java-dispatch.cpp
@@ -0,0 +1,524 @@
+/*
+ * Copyright 2008 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <string>
+#include <sstream>
+#include "jni.h"
+#include "java-dispatch.h"
+#include "trace.h"
+#include "JStringWrap.h"
+
+namespace gwt {
+
+  /*
+   * Declarations for private functions.
+   */
+  JSClassRef DispatchObjectClassCreate();
+
+  JSClassRef DispatchMethodClassCreate();
+
+  JSValueRef DispatchObjectGetProperty(JSContextRef, JSObjectRef, JSStringRef,
+                                       JSValueRef*);
+
+  JSValueRef DispatchObjectToString(JSContextRef, JSObjectRef, JSObjectRef,
+                                    size_t, const JSValueRef*, JSValueRef*);
+
+  bool DispatchObjectSetProperty(JSContextRef, JSObjectRef, JSStringRef,
+                                 JSValueRef, JSValueRef*);
+
+  void DispatchObjectFinalize(JSObjectRef);
+
+  JSValueRef DispatchMethodCallAsFunction(JSContextRef, JSObjectRef,
+                                          JSObjectRef, size_t,
+                                          const JSValueRef*, JSValueRef*);
+
+  JSValueRef DispatchMethodGetToString(JSContextRef, JSObjectRef, JSStringRef,
+                                       JSValueRef*);
+
+  JSValueRef DispatchMethodToString(JSContextRef, JSObjectRef, JSObjectRef,
+                                    size_t, const JSValueRef*, JSValueRef*);
+
+  void DispatchMethodFinalize(JSObjectRef);
+
+  /*
+   * Call this when an underlying Java Object should be freed.
+   */
+  void ReleaseJavaObject(jobject jObject);
+
+
+  /*
+   * The class definition stuct for DispatchObjects.
+   */
+  static JSClassDefinition _dispatchObjectClassDef = { 0,
+      kJSClassAttributeNone, "DispatchObject", 0, 0, 0, 0,
+      DispatchObjectFinalize, 0, DispatchObjectGetProperty,
+      DispatchObjectSetProperty, 0, 0, 0, 0, 0, 0 };
+
+  /*
+   * The class definition structs for DispatchMethods.
+   */
+  static JSStaticValue _dispatchMethodStaticValues[] = {
+    { "toString", DispatchMethodGetToString, 0, kJSPropertyAttributeNone },
+    { 0, 0, 0, 0 }
+  };
+  static JSClassDefinition _dispatchMethodClassDef = { 0,
+      kJSClassAttributeNoAutomaticPrototype, "DispatchMethod", 0,
+      _dispatchMethodStaticValues, 0, 0, DispatchMethodFinalize, 0, 0, 0, 0,
+      0, DispatchMethodCallAsFunction, 0, 0, 0 };
+
+  /*
+   * The classes used to create DispatchObjects and DispatchMethods.
+   */
+  static JSClassRef _dispatchObjectClass = DispatchObjectClassCreate();
+  static JSClassRef _dispatchMethodClass = DispatchMethodClassCreate();
+
+  /*
+   * Java class and method references needed to do delegation.
+   */
+  
+  /*
+   * The main JVM, used by foreign threads to attach.
+   */
+  static JavaVM* _javaVM;
+
+  /*
+   * Only valid for the main thread!  WebKit can finalized on a foreign thread.
+   */
+  static JNIEnv* _javaEnv;
+
+  static jclass _javaDispatchObjectClass;
+  static jclass _javaDispatchMethodClass;
+  static jclass _lowLevelSafClass;
+  static jmethodID _javaDispatchObjectSetFieldMethod;
+  static jmethodID _javaDispatchObjectGetFieldMethod;
+  static jmethodID _javaDispatchMethodInvokeMethod;
+  static jmethodID _javaDispatchObjectToStringMethod;
+  static jmethodID _lowLevelSafReleaseObject;
+
+  /*
+   * Structure to hold DispatchMethod private data.
+   *
+   * NOTE: utf8Name is defensively copied.
+   */
+  class DispatchMethodData {
+   public:
+    DispatchMethodData(jobject jObject, std::string& utf8Name)
+        : _jObject(jObject), _utf8Name(utf8Name) { }
+    ~DispatchMethodData() {
+      ReleaseJavaObject(_jObject);
+    }
+    jobject _jObject;
+    std::string _utf8Name;
+  };
+
+/*
+ * The following takes the prototype from the Function constructor, this allows
+ * us to easily support call and apply on our objects that support CallAsFunction.
+ *
+ * NOTE: The return value is not protected.
+ */
+JSValueRef GetFunctionPrototype(JSContextRef jsContext, JSValueRef* exception) {
+  TR_ENTER();
+  JSObjectRef globalObject = JSContextGetGlobalObject(jsContext);
+  JSStringRef fnPropName= JSStringCreateWithUTF8CString("Function");
+  JSValueRef fnCtorValue = JSObjectGetProperty(jsContext, globalObject,
+      fnPropName, exception);
+  JSStringRelease(fnPropName);
+  if (!fnCtorValue) {
+    return JSValueMakeUndefined(jsContext);
+  }
+
+  JSObjectRef fnCtorObject = JSValueToObject(jsContext, fnCtorValue, exception);
+  if (!fnCtorObject) {
+    return JSValueMakeUndefined(jsContext);
+  }
+
+  JSStringRef protoPropName = JSStringCreateWithUTF8CString("prototype");
+  JSValueRef fnPrototype = JSObjectGetProperty(jsContext, fnCtorObject,
+      protoPropName, exception);
+  JSStringRelease(protoPropName);
+  if (!fnPrototype) {
+    return JSValueMakeUndefined(jsContext);
+  }
+
+  TR_LEAVE();
+  return fnPrototype;
+}
+
+/*
+ *
+ */
+JSClassRef GetDispatchObjectClass() {
+  TR_ENTER();
+  TR_LEAVE();
+  return _dispatchObjectClass;
+}
+
+/*
+ *
+ */
+JSClassRef GetDispatchMethodClass() {
+  TR_ENTER();
+  TR_LEAVE();
+  return _dispatchMethodClass;
+}
+
+/*
+ *
+ */
+JSClassRef DispatchObjectClassCreate() {
+  TR_ENTER();
+  JSClassRef dispClass = JSClassCreate(&_dispatchObjectClassDef);
+  JSClassRetain(dispClass);
+  TR_LEAVE();
+  return dispClass;
+}
+
+/*
+ *
+ */
+JSClassRef DispatchMethodClassCreate() {
+  TR_ENTER();
+  JSClassRef dispClass = JSClassCreate(&_dispatchMethodClassDef);
+  JSClassRetain(dispClass);
+  TR_LEAVE();
+  return dispClass;
+}
+
+/*
+ * NOTE: The object returned from this function is not protected.
+ */
+JSObjectRef DispatchObjectCreate(JSContextRef jsContext, jobject jObject) {
+  TR_ENTER();
+  JSObjectRef dispInst = JSObjectMake(jsContext, _dispatchObjectClass,
+      _javaEnv->NewGlobalRef(jObject));
+  TR_LEAVE();
+  return dispInst;
+}
+
+/*
+ * NOTE: The object returned from this function is not protected.
+ */
+JSObjectRef DispatchMethodCreate(JSContextRef jsContext, std::string& name,
+    jobject jObject) {
+  TR_ENTER();
+ 
+  JSObjectRef dispInst = JSObjectMake(jsContext, _dispatchMethodClass,
+      new DispatchMethodData(_javaEnv->NewGlobalRef(jObject), name));
+
+  // This could only be cached relative to jsContext.
+  JSValueRef fnProtoValue = GetFunctionPrototype(jsContext, NULL);
+  JSObjectSetPrototype(jsContext, dispInst, fnProtoValue);
+  TR_LEAVE();
+  return dispInst;
+}
+
+/*
+ * NOTE: The value returned from this function is not protected, but all
+ * JSValues that are passed into Java are protected before the invocation.
+ */
+JSValueRef DispatchObjectGetProperty(JSContextRef jsContext,
+    JSObjectRef jsObject, JSStringRef jsPropertyName,
+    JSValueRef* jsException) {
+  TR_ENTER();
+
+  // If you call toString on a DispatchObject, you should get the results
+  // of the java object's toString invcation.
+  if (JSStringIsEqualToUTF8CString(jsPropertyName, "toString")) {
+    JSObjectRef jsFunction = JSObjectMakeFunctionWithCallback(jsContext,
+        jsPropertyName, DispatchObjectToString);
+    return jsFunction;
+  }
+
+  // The class check is omitted because it should not be possible to tear off
+  // a getter.
+  jobject jObject = reinterpret_cast<jobject>(JSObjectGetPrivate(jsObject));
+
+  jstring jPropertyName = _javaEnv->NewString(
+      static_cast<const jchar*>(JSStringGetCharactersPtr(jsPropertyName)),
+      static_cast<jsize>(JSStringGetLength(jsPropertyName)));
+  if (!jObject || !jPropertyName || _javaEnv->ExceptionCheck()) {
+    TR_FAIL();
+    _javaEnv->ExceptionClear();
+    return JSValueMakeUndefined(jsContext);
+  }
+
+  JSValueRef jsResult = reinterpret_cast<JSValueRef>(
+      _javaEnv->CallIntMethod(jObject, _javaDispatchObjectGetFieldMethod,
+      reinterpret_cast<jint>(jsContext),
+      jPropertyName));
+  if (!jsResult || _javaEnv->ExceptionCheck()) {
+    TR_FAIL();
+    _javaEnv->ExceptionClear();
+    return JSValueMakeUndefined(jsContext);
+  }
+
+  // Java left us an extra reference to eat.
+  JSValueUnprotectChecked(jsContext, jsResult);
+  TR_LEAVE();
+  return jsResult;
+}
+
+/*
+ *
+ */
+bool DispatchObjectSetProperty(JSContextRef jsContext, JSObjectRef jsObject,
+    JSStringRef jsPropertyName, JSValueRef jsValue, JSValueRef* jsException) {
+  TR_ENTER();
+
+  // The class check is omitted because it should not be possible to tear off
+  // a getter.
+  jobject jObject = reinterpret_cast<jobject>(JSObjectGetPrivate(jsObject));
+
+  jstring jPropertyName = _javaEnv->NewString(
+      static_cast<const jchar*>(JSStringGetCharactersPtr(jsPropertyName)),
+      static_cast<jsize>(JSStringGetLength(jsPropertyName)));
+  if (!jObject || !jPropertyName || _javaEnv->ExceptionCheck()) {
+    _javaEnv->ExceptionClear();
+    return false;
+  }
+
+  JSValueProtectChecked(jsContext, jsValue);
+
+  _javaEnv->CallIntMethod(jObject, _javaDispatchObjectSetFieldMethod,
+      reinterpret_cast<jint>(jsContext), jPropertyName,
+      reinterpret_cast<jint>(jsValue));
+  if (_javaEnv->ExceptionCheck()) {
+    _javaEnv->ExceptionClear();
+    return false;
+  }
+
+  TR_LEAVE();
+  return true;
+}
+
+/*
+ *
+ */
+void DispatchObjectFinalize(JSObjectRef jsObject) {
+  TR_ENTER();
+  jobject jObject = reinterpret_cast<jobject>(JSObjectGetPrivate(jsObject));
+  ReleaseJavaObject(jObject);
+  TR_LEAVE();
+}
+
+/*
+ *
+ */
+void DispatchMethodFinalize(JSObjectRef jsObject) {
+  TR_ENTER();
+  DispatchMethodData* data = reinterpret_cast<DispatchMethodData*>(
+      JSObjectGetPrivate(jsObject));
+  delete data;
+  TR_LEAVE();
+}
+
+/*
+ * NOTE: The value returned from this function is not protected.
+ */
+JSValueRef DispatchObjectToString(JSContextRef jsContext, JSObjectRef,
+    JSObjectRef jsThis, size_t, const JSValueRef*, JSValueRef*) {
+  TR_ENTER();
+
+  // This function cannot be torn off and applied to any JSValue. If this does
+  // not reference a DispatchObject, return undefined.
+  if (!JSValueIsObjectOfClass(jsContext, jsThis, GetDispatchObjectClass())) {
+    return JSValueMakeUndefined(jsContext);
+  }
+
+  jobject jObject = reinterpret_cast<jobject>(JSObjectGetPrivate(jsThis));
+  jstring jResult = reinterpret_cast<jstring>(
+      _javaEnv->CallObjectMethod(jObject, _javaDispatchObjectToStringMethod));
+  if (_javaEnv->ExceptionCheck()) {
+    return JSValueMakeUndefined(jsContext);
+  } else if (!jResult) {
+    return JSValueMakeNull(jsContext);
+  } else {
+    JStringWrap result(_javaEnv, jResult);
+    JSStringRef resultString = JSStringCreateWithCharacters(
+        static_cast<const JSChar*>(result.jstr()),
+        static_cast<size_t>(result.length()));
+    JSValueRef jsResultString = JSValueMakeString(jsContext, resultString);
+    JSStringRelease(resultString);
+    return jsResultString;
+  }
+  TR_LEAVE();
+}
+
+/*
+ *
+ */
+JSValueRef DispatchMethodCallAsFunction(JSContextRef jsContext,
+    JSObjectRef jsFunction, JSObjectRef jsThis, size_t argumentCount,
+    const JSValueRef arguments[], JSValueRef* exception) {
+  TR_ENTER();
+
+  // We don't need to check the class here because we take the private
+  // data from jsFunction and not jsThis.
+
+  DispatchMethodData* data = reinterpret_cast<DispatchMethodData*>(
+      JSObjectGetPrivate(jsFunction));
+  jobject jObject = data->_jObject;
+
+  jintArray jArguments = _javaEnv->NewIntArray(argumentCount);
+  if (!jArguments || _javaEnv->ExceptionCheck()) {
+    return JSValueMakeUndefined(jsContext);
+  }
+
+  // This single element int array will be passed into the java call to allow the
+  // called java method to raise an exception. We will check for a non-null value
+  // after the call is dispatched.
+  jintArray jException = _javaEnv->NewIntArray(1);
+  if (!jException || _javaEnv->ExceptionCheck()) {
+    return JNI_FALSE;
+  }
+
+  for (size_t i = 0; i < argumentCount; ++i) {
+    JSValueRef arg = arguments[i];
+    // Java will take ownership of the arguments.
+    JSValueProtectChecked(jsContext, arg);
+    _javaEnv->SetIntArrayRegion(jArguments, i, 1, reinterpret_cast<jint*>(&arg));
+    if (_javaEnv->ExceptionCheck()) {
+      return JSValueMakeUndefined(jsContext);
+    }
+  }
+
+  // Java will take ownership of this.
+  JSValueProtectChecked(jsContext, jsThis);
+
+  JSValueRef jsResult = reinterpret_cast<JSValueRef>(_javaEnv->CallIntMethod(jObject,
+      _javaDispatchMethodInvokeMethod, reinterpret_cast<jint>(jsContext),
+      reinterpret_cast<jint>(jsThis), jArguments, jException));
+  if (_javaEnv->ExceptionCheck()) {
+    return JSValueMakeUndefined(jsContext);
+  }
+
+  JSValueRef jsException = NULL;
+  _javaEnv->GetIntArrayRegion(jException, 0, 1, reinterpret_cast<jint*>(&jsException));
+  if (!_javaEnv->ExceptionCheck() && jsException) {
+    // If the java dispatch set an exception, then we pass it back to our caller.
+	if (exception) {
+      *exception = jsException;
+	}
+    // Java left us an extra reference to eat.
+    JSValueUnprotectChecked(jsContext, jsException);
+  }
+
+  // Java left us an extra reference to eat.
+  JSValueUnprotectChecked(jsContext, jsResult);
+  TR_LEAVE();
+  return jsResult;
+}
+
+/*
+ * NOTE: The object returned from this function is not protected.
+ */
+JSValueRef DispatchMethodToString(JSContextRef jsContext, JSObjectRef,
+    JSObjectRef thisObject, size_t, const JSValueRef*, JSValueRef*) {
+  TR_ENTER();
+  
+  // This function cannot be torn off and applied to any JSValue. If this does
+  // not reference a DispatchMethod, return undefined.
+  if (!JSValueIsObjectOfClass(jsContext, thisObject, GetDispatchMethodClass())) {
+    return JSValueMakeUndefined(jsContext);
+  }
+
+  std::ostringstream ss;
+  DispatchMethodData* data = reinterpret_cast<DispatchMethodData*>(
+      JSObjectGetPrivate(thisObject));
+  ss << "function " << data->_utf8Name << "() {\n    [native code]\n}\n";
+  JSStringRef stringRep = JSStringCreateWithUTF8CString(ss.str().c_str());
+  JSValueRef jsStringRep = JSValueMakeString(jsContext, stringRep);
+  JSStringRelease(stringRep);
+  TR_LEAVE();
+  return jsStringRep;
+}
+
+/*
+ * NOTE: The object returned from this function is not protected.
+ */
+JSValueRef DispatchMethodGetToString(JSContextRef jsContext,
+    JSObjectRef jsObject, JSStringRef jsPropertyName, JSValueRef* jsException) {
+  TR_ENTER();
+  JSObjectRef toStringFn = JSObjectMakeFunctionWithCallback(jsContext,
+      jsPropertyName, DispatchMethodToString);
+  TR_LEAVE();
+  return toStringFn;
+}
+
+/*
+ *
+ */
+bool Initialize(JNIEnv* javaEnv, jclass javaDispatchObjectClass,
+    jclass javaDispatchMethodClass, jclass lowLevelSafClass) {
+  TR_ENTER();
+  if (!javaEnv || !javaDispatchObjectClass || !javaDispatchMethodClass
+      || !lowLevelSafClass) {
+    return false;
+  }
+
+  _javaVM = 0;
+  javaEnv->GetJavaVM(&_javaVM);
+
+  _javaEnv = javaEnv;
+  _javaDispatchObjectClass = static_cast<jclass>(
+      javaEnv->NewGlobalRef(javaDispatchObjectClass));
+  _javaDispatchMethodClass = static_cast<jclass>(
+      javaEnv->NewGlobalRef(javaDispatchMethodClass));
+  _lowLevelSafClass = static_cast<jclass>(
+      javaEnv->NewGlobalRef(lowLevelSafClass));
+  _javaDispatchObjectSetFieldMethod = javaEnv->GetMethodID(
+      javaDispatchObjectClass, "setField", "(ILjava/lang/String;I)V");
+  _javaDispatchObjectGetFieldMethod = javaEnv->GetMethodID(
+      javaDispatchObjectClass, "getField", "(ILjava/lang/String;)I");
+  _javaDispatchMethodInvokeMethod = javaEnv->GetMethodID(
+      javaDispatchMethodClass, "invoke", "(II[I[I)I");
+  _javaDispatchObjectToStringMethod = javaEnv->GetMethodID(
+      javaDispatchObjectClass, "toString", "()Ljava/lang/String;");
+  _lowLevelSafReleaseObject = javaEnv->GetStaticMethodID(
+      lowLevelSafClass, "releaseObject", "(Ljava/lang/Object;)V");
+
+  if (!_javaVM
+      || !_javaDispatchObjectSetFieldMethod || !_javaDispatchObjectGetFieldMethod
+      || !_javaDispatchMethodInvokeMethod || !_javaDispatchObjectToStringMethod
+      || !_lowLevelSafReleaseObject || javaEnv->ExceptionCheck()) {
+    return false;
+  }
+
+  TR_LEAVE();
+  return true;
+}
+
+void ReleaseJavaObject(jobject jObject) {
+  // Tricky: this call may be on a foreign thread.
+  JNIEnv* javaEnv = 0;
+  if ((_javaVM->AttachCurrentThreadAsDaemon(reinterpret_cast<void**>(&javaEnv),
+      NULL) < 0) || !javaEnv) {
+    TR_FAIL();
+    return;
+  }
+
+  // Tell the Java code we're done with this object.
+  javaEnv->CallStaticVoidMethod(_lowLevelSafClass, _lowLevelSafReleaseObject,
+      jObject);
+  if (javaEnv->ExceptionCheck()) {
+    TR_FAIL();
+    return;
+  }
+  javaEnv->DeleteGlobalRef(jObject);
+}
+
+} // namespace gwt
diff --git a/jni/mac/java-dispatch.h b/jni/mac/java-dispatch.h
new file mode 100644
index 0000000..f8fa80b
--- /dev/null
+++ b/jni/mac/java-dispatch.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2008 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#ifndef JAVA_DISPATCHER_H__
+#define JAVA_DISPATCHER_H__
+#include <iostream>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include <jni.h>
+
+namespace gwt {
+
+/*
+ * Initializes static members needed by DispatchObject, DispatchMethod,
+ * and LowLevelSaf.  This should be called before before calling anything
+ * else.
+ */
+bool Initialize(JNIEnv*, jclass, jclass, jclass);
+
+/*
+ * Returns a shared reference to the DispatchObject class
+ */
+JSClassRef GetDispatchObjectClass();
+
+/*
+ * Constructs a new DispatchObject.
+ *
+ * jContext - the JavaScript context
+ * jObject - the java instance of DispatchObject to which
+ *   this instance will dispatch calls
+ */
+JSObjectRef DispatchObjectCreate(JSContextRef jContext, jobject jObject);
+
+/*
+ * Returns a shared reference to the DispatchMethod class
+ */
+JSClassRef GetDispatchMethodClass();
+
+/*
+ * Constructs a new DispatchMethod object.
+ *
+ * jsContext - the JavaScript context
+ * name - the name of the method (used in toString)
+ * jObject - the java instance of DispatchMethod to which this object will
+ *   delegate calls.
+ */
+JSObjectRef DispatchMethodCreate(JSContextRef jsContext, std::string& name,
+                                 jobject jObject);
+
+
+} // namespace gwt
+
+#endif // JAVA_DISPATCHER_H__
diff --git a/jni/mac/org.eclipse.swt/webkit.c b/jni/mac/org.eclipse.swt/webkit.c
new file mode 100644
index 0000000..3b704ec
--- /dev/null
+++ b/jni/mac/org.eclipse.swt/webkit.c
@@ -0,0 +1,250 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+// Modified by Google
+#include <Carbon/Carbon.h>
+#include <WebKit/WebKit.h>
+#include <WebKit/HIWebView.h>
+
+#include "jni.h"
+
+JNIEXPORT void JNICALL Java_org_eclipse_swt_browser_WebKit_WebInitForCarbon(JNIEnv *env, jclass zz) {
+	WebInitForCarbon();
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_HIWebViewCreate(JNIEnv *env, jclass zz, jintArray outView) {
+	jint *a = (*env)->GetIntArrayElements(env, outView, NULL);
+	jint status = (jint) HIWebViewCreate((HIViewRef *)a);
+	(*env)->ReleaseIntArrayElements(env, outView, a, 0);
+	return status;
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_HIWebViewGetWebView(JNIEnv *env, jclass zz, jint viewRef) {
+	return (jint) HIWebViewGetWebView((HIViewRef)viewRef);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1msgSend__II(JNIEnv *env, jclass zz, jint obj, jint sel) {
+	return (jint) objc_msgSend((void *)obj, (void *)sel);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1msgSend__III(JNIEnv *env, jclass zz, jint obj, jint sel, jint arg0) {
+	return (jint) objc_msgSend((void *)obj, (void *)sel, (void *)arg0);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1msgSend__IIII(JNIEnv *env, jclass zz, jint obj, jint sel, jint arg0, jint arg1) {
+	return (jint) objc_msgSend((void *)obj, (void *)sel, (void *)arg0, (void *)arg1);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1msgSend__IIIII(JNIEnv *env, jclass zz, jint obj, jint sel, jint arg0, jint arg1, jint arg2) {
+	return (jint) objc_msgSend((void *)obj, (void *)sel, (void *)arg0, (void *)arg1, (void *)arg2);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1msgSend__IIIIII(JNIEnv *env, jclass zz, jint obj, jint sel, jint arg0, jint arg1, jint arg2, jint arg3) {
+	return (jint) objc_msgSend((void *)obj, (void *)sel, (void *)arg0, (void *)arg1, (void *)arg2, (void *)arg3);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1getClass(JNIEnv *env, jclass zz, jbyteArray name) {
+	jbyte *a = (*env)->GetByteArrayElements(env, name, NULL);
+	jint id = (jint) objc_getClass((const char *)a);
+	(*env)->ReleaseByteArrayElements(env, name, a, 0);
+	return id;
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_sel_1registerName(JNIEnv *env, jclass zz, jbyteArray name) {
+	jbyte *a= (*env)->GetByteArrayElements(env, name, NULL);
+	jint sel= (jint) sel_registerName((const char *)a);
+	(*env)->ReleaseByteArrayElements(env, name, a, 0);
+	return sel;
+}
+
+@interface WebKitDelegate : NSObject
+{
+	int user_data;
+	int (*proc) (int sender, int user_data, int selector, int arg0, int arg1, int arg2, int arg3);
+}
+@end
+
+@implementation WebKitDelegate
+
+- (id)initWithProc:(id)prc user_data:(int)data
+{
+    [super init];
+    proc= (void *) prc;
+    user_data = data;
+    return self;
+}
+
+/* WebFrameLoadDelegate */
+
+- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
+{
+	proc((int)sender, user_data, 1, (int)error, (int)frame, 0, 0);
+}
+
+- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
+{
+	proc((int)sender, user_data, 2, (int)frame, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame
+{
+	proc((int)sender, user_data, 3, (int)title, (int)frame, 0, 0);
+}
+
+- (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame
+{
+	proc((int)sender, user_data, 4, (int)frame, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame
+{
+	proc((int)sender, user_data, 10, (int)frame, 0, 0, 0);
+}
+
+/* WebResourceLoadDelegate */
+
+- (void)webView:(WebView *)sender resource:(id)identifier didFinishLoadingFromDataSource:(WebDataSource *)dataSource
+{
+	proc((int)sender, user_data, 5, (int)identifier, (int)dataSource, 0, 0);
+}
+
+- (void)webView:(WebView *)sender resource:(id)identifier didFailLoadingWithError:(NSError *)error fromDataSource:(WebDataSource *)dataSource
+{
+	proc((int)sender, user_data, 6, (int)identifier, (int)error, (int)dataSource, 0);
+}
+
+- (id)webView:(WebView *)sender identifierForInitialRequest:(NSURLRequest *)request fromDataSource:(WebDataSource *)dataSource
+{
+    return (id) proc((int)sender, user_data, 7, (int)request, (int)dataSource, 0, 0);    
+}
+
+- (NSURLRequest *)webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource
+{
+	return (NSURLRequest *) proc((int)sender, user_data, 8, (int)identifier, (int)request, (int)redirectResponse, (int)dataSource);
+}
+
+/* handleNotification */
+
+- (void)handleNotification:(NSNotification *)notification
+{
+	proc((int)[notification object], user_data, 9, (int)notification, 0, 0, 0);
+}
+
+/* UIDelegate */
+
+- (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request
+{
+	return (WebView *) proc((int)sender, user_data, 11, (int)request, 0, 0, 0);
+}
+
+- (void)webViewShow:(WebView *)sender
+{
+	proc((int)sender, user_data, 12, 0, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender setFrame:(NSRect)frame
+{
+	proc((int)sender, user_data, 13, (int)&frame, 0, 0, 0);
+}
+
+- (void)webViewClose:(WebView *)sender
+{
+	proc((int)sender, user_data, 14, 0, 0, 0, 0);
+}
+
+- (NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary *)element defaultMenuItems:(NSArray *)defaultMenuItems
+{
+	return (NSArray *)proc((int)sender, user_data, 15, (int)element, (int)defaultMenuItems, 0, 0);
+}
+
+- (void)webView:(WebView *)sender setStatusBarVisible:(BOOL)visible
+{
+	proc((int)sender, user_data, 16, (int)visible, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender setResizable:(BOOL)resizable
+{
+	proc((int)sender, user_data, 17, (int)resizable, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender setToolbarsVisible:(BOOL)visible
+{
+	proc((int)sender, user_data, 18, (int)visible, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender setStatusText:(NSString *)text
+{
+	proc((int)sender, user_data, 23, (int)text, 0, 0, 0);
+}
+
+- (void)webViewFocus:(WebView *)sender
+{
+	proc((int)sender, user_data, 24, 0, 0, 0, 0);
+}
+
+- (void)webViewUnfocus:(WebView *)sender
+{
+	proc((int)sender, user_data, 25, 0, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message
+{
+	proc((int)sender, user_data, 26, (int)message, 0, 0, 0);
+}
+
+- (BOOL)webView:(WebView *)sender runJavaScriptConfirmPanelWithMessage:(NSString *)message
+{
+	return (BOOL) proc((int)sender, user_data, 27, (int)message, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender runOpenPanelForFileButtonWithResultListener:(id<WebOpenPanelResultListener>)resultListener
+{
+	proc((int)sender, user_data, 28, (int)resultListener, 0, 0, 0);
+}
+
+/* WebPolicyDelegate */
+- (void)webView:(WebView *)sender decidePolicyForMIMEType:(NSString *)type request:(NSURLRequest *)request frame:(WebFrame*)frame decisionListener:(id<WebPolicyDecisionListener>)listener
+{
+	proc((int)sender, user_data, 19, (int)type, (int)request, (int)frame, (int)listener);
+}
+
+- (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener
+{
+	proc((int)sender, user_data, 20, (int)actionInformation, (int)request, (int)frame, (int)listener);
+}
+
+
+- (void)webView:(WebView *)sender decidePolicyForNewWindowAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request newFrameName:(NSString *)frameName decisionListener:(id<WebPolicyDecisionListener>)listener
+{
+	proc((int)sender, user_data, 21, (int)actionInformation, (int)request, (int)frameName, (int)listener);
+}
+
+
+- (void)webView:(WebView *)sender unableToImplementPolicyWithError:(NSError *)error frame:(WebFrame *)frame
+{
+	proc((int)sender, user_data, 22, (int)error, (int)frame, 0, 0);
+}
+
+/* WebDownload */
+
+- (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename
+{
+	proc((int)download, user_data, 29, (int)download, (int)filename, 0, 0);
+}
+
+// GOOGLE: we need a notification when the window object is available so we can
+// setup our own hooks before any JavaScript runs.
+- (void)webView:(WebView *)sender windowScriptObjectAvailable:(WebScriptObject *)windowScriptObject
+{
+	proc((int)sender, user_data, 99, (int)windowScriptObject, 0, 0, 0);
+}
+
+@end
+
diff --git a/jni/mac/prebuilt/libgwt-ll.jnilib b/jni/mac/prebuilt/libgwt-ll.jnilib
new file mode 100755
index 0000000..5a4030f
--- /dev/null
+++ b/jni/mac/prebuilt/libgwt-ll.jnilib
Binary files differ
diff --git a/jni/mac/trace.cpp b/jni/mac/trace.cpp
new file mode 100644
index 0000000..2127351
--- /dev/null
+++ b/jni/mac/trace.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2008 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <iostream>
+#include <map>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include "trace.h"
+
+#ifdef ENABLE_JSVALUE_PROTECTION_CHECKING
+static std::map<JSValueRef, int> _protectMap;
+#endif
+
+/*
+ *
+ */
+void JSValueProtectChecked(JSContextRef jsContext, JSValueRef jsValue) {
+  JSValueProtect(jsContext, jsValue);
+#ifdef ENABLE_JSVALUE_PROTECTION_CHECKING
+  _protectMap[jsValue]++;
+#endif
+}
+
+/*
+ *
+ */
+void JSValueUnprotectChecked(JSContextRef jsContext, JSValueRef jsValue) {
+#ifdef ENABLE_JSVALUE_PROTECTION_CHECKING
+  // Unrecord in a hash_map
+  unsigned count = _protectMap[jsValue];
+  if (count == 0) {
+    std::cerr << "[WARNING] JSValueUnprotect called on unprotected JSValueRef (0x"
+        << std::hex << ((unsigned)jsValue) << ")" << std::endl;
+    return;
+  }
+  _protectMap[jsValue] = count - 1;
+#else
+  JSValueUnprotect(jsContext, jsValue);
+#endif
+}
+
+bool JSValueIsProtected(JSValueRef jsValue) {
+#ifdef ENABLE_JSVALUE_PROTECTION_CHECKING
+  return _protectMap[jsValue] > 0;
+#else
+  return true;
+#endif
+}
+
+bool JSValueProtectCheckingIsEnabled() {
+#ifdef ENABLE_JSVALUE_PROTECTION_CHECKING
+  return true;
+#else
+  return false;
+#endif
+}
diff --git a/jni/mac/trace.h b/jni/mac/trace.h
new file mode 100644
index 0000000..e58ca96
--- /dev/null
+++ b/jni/mac/trace.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2008 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#ifndef TRACE_H__
+#define TRACE_H__
+#include <iostream>
+#include <map>
+
+// Uncomment to trace enter, exit and fail for all native calls.
+// #define ENABLE_CALL_TRACE
+
+// Uncomment to double check that JSValueRef's are protected and
+// unprotected properly.
+// #define ENABLE_JSVALUE_PROTECTION_CHECKING
+
+#ifdef ENABLE_CALL_TRACE
+#define TR_ENTER() std::cout << "ENTER " << __PRETTY_FUNCTION__ << std::endl
+#define TR_LEAVE() std::cout << "LEAVE " << __PRETTY_FUNCTION__ << std::endl
+#define TR_FAIL() std::cout << "FAIL " << __FILE__ << "@" << __LINE__ \
+    << std::endl;
+#else
+#define TR_ENTER()
+#define TR_LEAVE()
+#define TR_FAIL()
+#endif // ENABLE_CALL_TRACE
+
+void JSValueUnprotectChecked(JSContextRef, JSValueRef);
+void JSValueProtectChecked(JSContextRef, JSValueRef);
+bool JSValueIsProtected(JSValueRef jsValue);
+bool JSValueProtectCheckingIsEnabled();
+
+#endif // TRACE_H__