Rewrite of the low level libs for OSX hosted mode. We now use all public
APIs and the standard install of WebKit. Because of this change there is
no longer any need to produce two different mac targets, so this also
reverses the changes to the build in r2000.

Review by: scottb (desk), jat (desk)



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2168 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/jni/mac/gwt-webkit.cpp b/jni/mac/gwt-webkit.cpp
new file mode 100644
index 0000000..293a2bc
--- /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) {
+  TR_ENTER();
+  TR_LEAVE();
+  return static_cast<jboolean>(gwt::Initialize(env, dispatchObjectClass, dispatchMethodClass));
+}
+
+/*
+ *
+ */
+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());
+}