Add back IE proxy handling for CheckForUpdates.
Also remove branch-info.txt inadvertently committed to trunk.
Patch by: scottb
Review by: jat
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6390 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/jni/linux/ExternalWrapper.cpp b/jni/linux/ExternalWrapper.cpp
new file mode 100644
index 0000000..3b2854e
--- /dev/null
+++ b/jni/linux/ExternalWrapper.cpp
@@ -0,0 +1,412 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+/*
+ * Defines the JavaScript class gwt_external_class, which interface via JNI
+ * to Java objects.
+ */
+
+#include <jni.h>
+#include "JsRootedValue.h"
+#include "gwt-jni.h"
+#include "ExternalWrapper.h"
+#include "Tracer.h"
+#include "JsStringWrap.h"
+
+#ifdef ENABLE_TRACING
+extern void PrintJSValue(JSContext* cx, jsval val, char* prefix="");
+#else
+// Include a null version just to keep from cluttering up call sites.
+static inline void PrintJSValue(JSContext* cx, jsval val, char* prefix="") { }
+#endif
+
+// note that this does not use the NS_DEFINE_CID macro because it defines
+// the variable as const, which by default has internal linkage. I could
+// work around it by putting extern in front of the macro, but that seems
+// fragile if the macro changes.
+nsCID kGwtExternalCID = GWT_EXTERNAL_FACTORY_CID;
+
+/*
+ * definition of JavaScript gwtOnLoad method which maps to the Java
+ * gwtOnLoad method.
+ */
+static JSBool gwtOnLoad(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ Tracer tracer("gwtOnLoad");
+ tracer.log("context=%08x", unsigned(cx));
+ JsRootedValue::ContextManager context(cx);
+ JsRootedValue::ensureRuntime(cx);
+ if (argc < 3) {
+ tracer.setFail("less than 3 args");
+ return JS_FALSE;
+ }
+
+ JSObject* scriptWindow = 0;
+ if (argv[0] != JSVAL_NULL && argv[0] != JSVAL_VOID) {
+ if (!JS_ValueToObject(cx, argv[0], &scriptWindow)) {
+ tracer.setFail("can't get script window object");
+ return JS_FALSE;
+ }
+ }
+
+ JSString* moduleName = 0;
+ if (argv[1] != JSVAL_NULL && argv[1] != JSVAL_VOID) {
+ moduleName = JS_ValueToString(cx, argv[1]);
+ }
+
+ JSString* version = 0;
+ if (argv[2] != JSVAL_NULL && argv[2] != JSVAL_VOID) {
+ version = JS_ValueToString(cx, argv[2]);
+ }
+
+ nsCOMPtr<nsIScriptGlobalObject> scriptGlobal(0);
+ if (scriptWindow) {
+ nsCOMPtr<nsIXPConnect> xpConnect = do_GetService(nsIXPConnect::GetCID());
+ nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
+ xpConnect->GetWrappedNativeOfJSObject(cx, scriptWindow,
+ getter_AddRefs(wrappedNative));
+ if (wrappedNative) {
+ nsCOMPtr<nsISupports> native;
+ wrappedNative->GetNative(getter_AddRefs(native));
+ scriptGlobal = do_QueryInterface(native);
+ }
+ }
+ jstring jModuleName(0);
+ if (moduleName) {
+ jModuleName = savedJNIEnv->NewString(JS_GetStringChars(moduleName),
+ JS_GetStringLength(moduleName));
+ if (!jModuleName || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't get module name in Java string");
+ return JS_FALSE;
+ }
+ tracer.log("module name=%s", JS_GetStringBytes(moduleName));
+ } else {
+ tracer.log("null module name");
+ }
+
+ jstring jVersion(0);
+ if (version) {
+ jVersion = savedJNIEnv->NewString(JS_GetStringChars(version),
+ JS_GetStringLength(version));
+ if (!jVersion || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't get module name in Java string");
+ return JS_FALSE;
+ }
+ tracer.log("version=%s", JS_GetStringBytes(version));
+ } else {
+ tracer.log("null version");
+ }
+
+ jobject externalObject = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+ jclass objClass = savedJNIEnv->GetObjectClass(externalObject);
+ if (!objClass || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't get LowLevelMoz.ExternalObject class");
+ return JS_FALSE;
+ }
+
+ jmethodID methodID = savedJNIEnv->GetMethodID(objClass, "gwtOnLoad",
+ "(ILjava/lang/String;Ljava/lang/String;)Z");
+ if (!methodID || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't get gwtOnLoad method");
+ return JS_FALSE;
+ }
+
+ tracer.log("scriptGlobal=%08x", unsigned(scriptGlobal.get()));
+
+ jboolean result = savedJNIEnv->CallBooleanMethod(externalObject, methodID,
+ NS_REINTERPRET_CAST(jint, scriptGlobal.get()), jModuleName, jVersion);
+ if (savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("LowLevelMoz.ExternalObject.gwtOnLoad() threw an exception");
+ return JS_FALSE;
+ }
+ *rval = BOOLEAN_TO_JSVAL((result == JNI_FALSE) ? JS_FALSE : JS_TRUE);
+ return JS_TRUE;
+}
+
+/*
+ * definition of JavaScript initModule method which maps to the Java
+ * initModule method.
+ */
+static JSBool initModule(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ Tracer tracer("initModule");
+ tracer.log("context=%08x", unsigned(cx));
+ JsRootedValue::ContextManager context(cx);
+ JsRootedValue::ensureRuntime(cx);
+ if (argc < 1) {
+ tracer.setFail("less than 1 args");
+ return JS_FALSE;
+ }
+
+ JSString* moduleName = 0;
+ if (argv[0] != JSVAL_NULL && argv[0] != JSVAL_VOID) {
+ moduleName = JS_ValueToString(cx, argv[0]);
+ }
+
+ jstring jModuleName(0);
+ if (moduleName) {
+ jModuleName = savedJNIEnv->NewString(JS_GetStringChars(moduleName),
+ JS_GetStringLength(moduleName));
+ if (!jModuleName || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't get module name in Java string");
+ return JS_FALSE;
+ }
+ tracer.log("module name=%s", JS_GetStringBytes(moduleName));
+ } else {
+ tracer.log("null module name");
+ }
+
+ jobject externalObject = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+ jclass objClass = savedJNIEnv->GetObjectClass(externalObject);
+ if (!objClass || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't get LowLevelMoz.ExternalObject class");
+ return JS_FALSE;
+ }
+
+ jmethodID methodID = savedJNIEnv->GetMethodID(objClass, "initModule",
+ "(Ljava/lang/String;)Z");
+ if (!methodID || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't get initModule method");
+ return JS_FALSE;
+ }
+
+ jboolean result = savedJNIEnv->CallBooleanMethod(externalObject, methodID,
+ jModuleName);
+ if (savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("LowLevelMoz.ExternalObject.initModule() threw an exception");
+ return JS_FALSE;
+ }
+ *rval = BOOLEAN_TO_JSVAL((result == JNI_FALSE) ? JS_FALSE : JS_TRUE);
+ return JS_TRUE;
+}
+
+/*=======================================================================*/
+/* Implementation of the getProperty, setProperty, and finalize methods */
+/* for the JavaScript class gwt_external_class. */
+/*=======================================================================*/
+
+static JSBool JS_DLL_CALLBACK gwt_external_getProperty(JSContext *cx,
+ JSObject *obj, jsval id, jsval *vp)
+{
+ Tracer tracer("gwt_external_getProperty");
+ JsRootedValue::ContextManager context(cx);
+ if (*vp != JSVAL_VOID) {
+ // we setup the gwtOnLoad function as a property in GetScriptObject and
+ // do not maintain a copy of it anywhere. So, if there is a cached
+ // value for a property we must return it. As we never redefine any
+ // property values, this is safe. If we were going to keep this code
+ // around and add Toby's profiling code we would need to revisit this.
+ return JS_TRUE;
+ }
+
+ if (!JSVAL_IS_STRING(id)) {
+ tracer.setFail("not a string");
+ return JS_FALSE;
+ }
+ JsStringWrap jsStr(cx, id);
+ tracer.log("obj=%08x, property=%.*s", obj, jsStr.length(), jsStr.bytes());
+
+// All this is for calling resolveReference which only returns void. So,
+// just replace this code to return void for now. TODO(jat): revisit when
+// merging in Toby's code.
+#if 0
+ jstring jident = savedJNIEnv->NewString(jsStr.chars(), jsStr.length());
+ if (!jident || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't create Java string ");
+ return JS_FALSE;
+ }
+ jobject externalObject = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+ jclass objClass = savedJNIEnv->GetObjectClass(externalObject);
+ if (!objClass || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't find Java class for JS object");
+ return JS_FALSE;
+ }
+
+ jmethodID methodID = savedJNIEnv->GetMethodID(objClass, "resolveReference",
+ "(Ljava/lang/String;)I");
+ if (!methodID || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("exception getting method for int resolveReference(String)");
+ return JS_FALSE;
+ }
+ int retval = savedJNIEnv->CallIntMethod(externalObject, methodID, jident);
+ if (savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("exception calling int resolveReference(String)");
+ return JS_FALSE;
+ }
+ *vp = retval;
+#else
+ *vp = JSVAL_VOID;
+#endif
+ return JS_TRUE;
+}
+
+static void JS_DLL_CALLBACK gwt_external_finalize(JSContext *cx, JSObject *obj)
+{
+ // We don't need to push a context if all we do is DeleteGlobalRef
+ Tracer tracer("gwt_external_finalize", obj);
+ jobject externalObject = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+ if (externalObject) {
+ savedJNIEnv->DeleteGlobalRef(externalObject);
+ }
+ JS_FinalizeStub(cx, obj);
+}
+
+static JSBool JS_DLL_CALLBACK gwt_external_setProperty(JSContext *cx,
+ JSObject *obj, jsval id, jsval *vp)
+{
+ return JS_FALSE;
+}
+
+static JSClass gwt_external_class = {
+ "gwt_external_class", JSCLASS_HAS_PRIVATE,
+ JS_PropertyStub, JS_PropertyStub, gwt_external_getProperty,
+ gwt_external_setProperty, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
+ gwt_external_finalize,
+ JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+NS_IMPL_ISUPPORTS1(ExternalWrapper, nsIScriptObjectOwner)
+
+/*
+ * Create a new LowLevelMoz.ExternalObject instance and a JavaScript object
+ * that refers to it, mapping the gwtOnLoad member function mapping to
+ * a Javascript method.
+ */
+NS_IMETHODIMP ExternalWrapper::GetScriptObject(nsIScriptContext *aContext,
+ void** aScriptObject)
+{
+ Tracer tracer("ExternalWrapper::GetScriptObject");
+ if (!aScriptObject) {
+ tracer.setFail("null script object pointer");
+ return NS_ERROR_INVALID_POINTER;
+ }
+ if (!jsWindowExternalObject) {
+ JSContext* cx = NS_REINTERPRET_CAST(JSContext*,
+ aContext->GetNativeContext());
+ if (!cx) {
+ tracer.setFail("can't get JSContext");
+ return NS_ERROR_UNEXPECTED;
+ }
+ JsRootedValue::ContextManager context(cx);
+ *aScriptObject = 0;
+
+ nsIScriptGlobalObject* globalObject = aContext->GetGlobalObject();
+ nsCOMPtr<nsIDOMWindow> domWindow(do_QueryInterface(globalObject));
+ if (!domWindow) {
+ tracer.setFail("can't get DOM window");
+ return NS_ERROR_UNEXPECTED;
+ }
+ nsCOMPtr<nsIDOMWindow> topWindow;
+ domWindow->GetTop(getter_AddRefs(topWindow));
+ if (!topWindow) {
+ tracer.setFail("Can't get top window");
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ tracer.log("savedJNIEnv=%08x, llClass=%08x", unsigned(savedJNIEnv),
+ lowLevelMozClass);
+
+ jmethodID methodID = savedJNIEnv->GetStaticMethodID(lowLevelMozClass,
+ "createExternalObjectForDOMWindow",
+ "(I)Lcom/google/gwt/dev/shell/moz/LowLevelMoz$ExternalObject;");
+ if (!methodID || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("Can't get createExternalObjectForDOMWindow method");
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ jobject externalObject = savedJNIEnv->CallStaticObjectMethod(
+ lowLevelMozClass, methodID, NS_REINTERPRET_CAST(jint, topWindow.get()));
+ if (!externalObject || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("createExternalObjectForDOMWindow failed");
+ return NS_ERROR_UNEXPECTED;
+ }
+ externalObject = savedJNIEnv->NewGlobalRef(externalObject);
+ if (!externalObject || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't get GlobalRef for external object");
+ return NS_ERROR_UNEXPECTED;
+ }
+ JSObject* newObj = JS_NewObject(cx, &gwt_external_class, 0,
+ globalObject->GetGlobalJSObject());
+ if (!newObj) {
+ tracer.setFail("can't create new gwt_external_class object");
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ if (!JS_SetPrivate(cx, newObj, externalObject)) {
+ savedJNIEnv->DeleteGlobalRef(externalObject);
+ tracer.setFail("can't store external object private reference");
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ if (!JS_DefineFunction(cx, newObj, "gwtOnLoad", gwtOnLoad, 3,
+ JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
+ tracer.setFail("can't define gwtOnLoad function on JavaScript object");
+ return NS_ERROR_UNEXPECTED;
+ }
+ if (!JS_DefineFunction(cx, newObj, "initModule", initModule, 1,
+ JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
+ tracer.setFail("can't define initModule function on JavaScript object");
+ return NS_ERROR_UNEXPECTED;
+ }
+ jsWindowExternalObject = newObj;
+ }
+
+ *aScriptObject = jsWindowExternalObject;
+ return NS_OK;
+}
+
+NS_IMETHODIMP ExternalWrapper::SetScriptObject(void* aScriptObject)
+{
+ jsWindowExternalObject = aScriptObject;
+ return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS1(nsRpExternalFactory, nsIFactory)
+
+NS_IMETHODIMP nsRpExternalFactory::CreateInstance(nsISupports *aOuter,
+ const nsIID& aIID, void** aResult)
+{
+ Tracer tracer("nsRpExternalFactory::CreateInstance");
+ if (!aResult) {
+ tracer.setFail("null pointer for return value");
+ return NS_ERROR_INVALID_POINTER;
+ }
+ *aResult = NULL;
+
+ if (aOuter) {
+ tracer.setFail("aOuter is not null");
+ return NS_ERROR_NO_AGGREGATION;
+ }
+
+ nsISupports* object = new ExternalWrapper();
+ if (!object) {
+ tracer.setFail("can't create a new ExternalWrapper");
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ nsresult result = object->QueryInterface(aIID, aResult);
+ if (!*aResult || NS_FAILED(result)) {
+ tracer.setFail("ExternalWrapper::QueryInterface failed");
+ delete object;
+ }
+ return result;
+}
+
+NS_IMETHODIMP nsRpExternalFactory::LockFactory(PRBool lock)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
diff --git a/jni/linux/ExternalWrapper.h b/jni/linux/ExternalWrapper.h
new file mode 100644
index 0000000..0168083
--- /dev/null
+++ b/jni/linux/ExternalWrapper.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2006 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#ifndef EXTERNALWRAPPER_H_
+#define EXTERNALWRAPPER_H_
+
+class ExternalWrapper : public nsIScriptObjectOwner {
+public:
+ NS_DECL_ISUPPORTS
+ NS_IMETHOD GetScriptObject(nsIScriptContext *aContext, void** aScriptObject);
+ NS_IMETHOD SetScriptObject(void* aScriptObject);
+ ExternalWrapper(): jsWindowExternalObject(0) { }
+private:
+ ~ExternalWrapper() { }
+ void *jsWindowExternalObject;
+};
+
+class nsRpExternalFactory : public nsIFactory {
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIFACTORY
+ nsRpExternalFactory() { }
+private:
+ ~nsRpExternalFactory() { }
+};
+
+#define GWT_EXTERNAL_FACTORY_CID \
+{ 0xF56E23F8, 0x5D06, 0x47F9, \
+{ 0x88, 0x5A, 0xD9, 0xCA, 0xC3, 0x38, 0x41, 0x7F } }
+#define GWT_EXTERNAL_CONTRACTID "@com.google/GWT/external;1"
+
+#endif /*EXTERNALWRAPPER_H_*/
diff --git a/jni/linux/JStringWrap.h b/jni/linux/JStringWrap.h
new file mode 100644
index 0000000..9d2ebcc
--- /dev/null
+++ b/jni/linux/JStringWrap.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#ifndef JNI_LINUX_JSTRINGWRAP_H_
+#define JNI_LINUX_JSTRINGWRAP_H_
+
+/*
+ * Wrapper arouond Java Strings, keeps pointers to unpacked strings
+ * and makes sure they are cleaned up.
+ */
+class JStringWrap {
+ public:
+ JStringWrap(JNIEnv* env, jstring str): env(env), s(str), p(0), jp(0) { }
+ ~JStringWrap() {
+ if (p) env->ReleaseStringUTFChars(s, p);
+ if (jp) env->ReleaseStringChars(s, jp);
+ }
+ const char* str() {
+ if (!p) p = env->GetStringUTFChars(s, 0);
+ return p;
+ }
+ const jchar* jstr() {
+ if (!jp) jp = env->GetStringChars(s, 0);
+ return jp;
+ }
+ int length() {
+ return env->GetStringLength(s);
+ }
+ private:
+ JNIEnv* env;
+ jstring s;
+ const char* p;
+ const jchar* jp;
+};
+
+
+#endif // JNI_LINUX_JSTRINGWRAP_H_
diff --git a/jni/linux/JsRootedValue.cpp b/jni/linux/JsRootedValue.cpp
new file mode 100644
index 0000000..29b95ca
--- /dev/null
+++ b/jni/linux/JsRootedValue.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include "JsRootedValue.h"
+
+// Initialize static value used to hold the JavaScript String class.
+JSClass* JsRootedValue::stringClass = 0;
+
+// Initialize static reference to the sole JSRuntime value in Gecko.
+JSRuntime* JsRootedValue::runtime = 0;
+
+// Static stack of JavaScript execution contexts.
+std::stack<JSContext*> JsRootedValue::contextStack;
+
+/*
+ * Actually get the stringClass pointer from JavaScript.
+ */
+void JsRootedValue::fetchStringClass() const {
+ Tracer tracer("JsRootedValue::fetchStringClass");
+ JSContext* cx = currentContext();
+ jsval val = JS_GetEmptyStringValue(cx);
+ JSObject* obj;
+ // on error, leave stringClass null
+ if (!JS_ValueToObject(cx, val, &obj)) return;
+ if (!obj) {
+ tracer.log("ensureStringClass: null object");
+ return;
+ }
+ stringClass = JS_GET_CLASS(cx, obj);
+ tracer.log("stringClass=%08x", unsigned(stringClass));
+}
diff --git a/jni/linux/JsRootedValue.h b/jni/linux/JsRootedValue.h
new file mode 100644
index 0000000..65c25af
--- /dev/null
+++ b/jni/linux/JsRootedValue.h
@@ -0,0 +1,428 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+#ifndef JNI_LINUX_JSROOTEDVALUE_H_
+#define JNI_LINUX_JSROOTEDVALUE_H_
+
+// Mozilla header files
+#include "mozilla-headers.h"
+
+#include "Tracer.h"
+#include <stack>
+
+extern "C" JSClass gwt_nativewrapper_class;
+
+/*
+ * Holds a root for Javascript objects, so the JS interpreter knows not to
+ * garbage-collect the underlying object as long as this object exists.
+ * Java code will pass a pointer to this object around (as an int/long) for
+ * referring to the underlying Javascript object.
+ *
+ * There are also convenience routines for manipulating the underlying value.
+ * Note that all get* methods assume the type is correct, so the corresponding
+ * is* method should be called first if you aren't sure of the type.
+ *
+ * See http://developer.mozilla.org/en/docs/JS_AddRoot for details.
+ *
+ * TODO(jat): rewrite this to minimize the number of roots held and to
+ * improve 64-bit compatibility.
+ */
+class JsRootedValue
+{
+private:
+ // the JavaScript String class
+ static JSClass* stringClass;
+
+ // Javascript runtime
+ static JSRuntime* runtime;
+
+ // stack of Javascript contexts
+ static std::stack<JSContext*> contextStack;
+
+ // underlying Javascript value
+ jsval value_;
+
+protected:
+ /*
+ * Fetch the JavaScript String class.
+ * Not inlined to minimize code bloat since it should only be called once.
+ */
+ void fetchStringClass() const;
+
+ /*
+ * Make sure we have the JS code to identify String objects installed.
+ */
+ void ensureStringClass() const {
+ if(stringClass) return;
+ fetchStringClass();
+ }
+
+ /*
+ * Helper for the various constructors
+ */
+ void constructorHelper(const char* ctorDesc) {
+ Tracer tracer(ctorDesc, this);
+ if (!JS_AddNamedRootRT(runtime, &value_, ctorDesc)) {
+ tracer.log("JS_AddNamedRootRT failed");
+ // TODO(jat): handle errors
+ }
+ }
+
+ /*
+ * Push a new JavaScript execution context.
+ */
+ static void pushContext(JSContext* context) {
+ Tracer tracer("JsRootedValue::pushContext");
+ tracer.log("pushed context=%08x", unsigned(context));
+ contextStack.push(context);
+ }
+
+ /*
+ * Pop a JavaScript execution context from the context stack.
+ */
+ static void popContext() {
+ Tracer tracer("JsRootedValue::popContext");
+ JSContext* context = currentContext();
+ contextStack.pop();
+ tracer.log("popped context=%08x", unsigned(context));
+ }
+
+public:
+ /*
+ * This is a helper class used to push/pop JSContext values automatically,
+ * using RAII. Simply create a ContextManager object on the stack and it
+ * will push the context at creation time and pop it at destruction time,
+ * so you don't have to worry about covering all the exit paths from a
+ * function.
+ */
+ class ContextManager {
+ public:
+ explicit ContextManager(JSContext* context) {
+ JsRootedValue::pushContext(context);
+ }
+ ~ContextManager() {
+ JsRootedValue::popContext();
+ }
+ };
+
+ /*
+ * This is a helper class to manage short-lived roots on the stack, using
+ * RAII to free the roots when no longer needed.
+ */
+ class Temp {
+ private:
+ void* ptr_;
+ public:
+ explicit Temp(void* ptr) : ptr_(ptr) {
+ JS_AddNamedRootRT(runtime, ptr_, "temporary root");
+ }
+ ~Temp() {
+ JS_RemoveRootRT(runtime, ptr_);
+ }
+ };
+
+ /*
+ * Copy constructor - make another rooted value that refers to the same
+ * JavaScript object (or has the same value if a primitive)
+ */
+ JsRootedValue(const JsRootedValue& rooted_value) : value_(rooted_value.value_)
+ {
+ constructorHelper("JsRootedValue copy ctor");
+ }
+
+ /*
+ * Create a value with a given jsval value
+ */
+ JsRootedValue(jsval value) : value_(value)
+ {
+ constructorHelper("JsRootedValue jsval ctor");
+ }
+
+ /*
+ * Create a void value
+ */
+ JsRootedValue() : value_(JSVAL_VOID) {
+ constructorHelper("JsRootedValue void ctor");
+ }
+
+ /*
+ * Destroy this object.
+ */
+ ~JsRootedValue() {
+ Tracer tracer("~JsRootedValue", this);
+ // ignore error since currently it is not possible to fail
+ JS_RemoveRootRT(runtime, &value_);
+ }
+
+ /*
+ * Save a pointer to the JSRuntime if we don't have it yet
+ */
+ static void ensureRuntime(JSContext* context) {
+ if(!runtime) runtime = JS_GetRuntime(context);
+ }
+
+ /*
+ * Return the current JavaScript execution context.
+ */
+ static JSContext* currentContext() {
+ Tracer tracer("JsRootedValue::currentContext");
+ if (contextStack.empty()) {
+ // TODO(jat): better error handling?
+ fprintf(stderr, "JsRootedValue::currentContext - context stack empty\n");
+ ::abort();
+ }
+ JSContext* context = contextStack.top();
+ tracer.log("context=%08x", unsigned(context));
+ return context;
+ }
+
+ /*
+ * Return the underlying JS object
+ */
+ jsval getValue() const { return value_; }
+
+ /*
+ * Sets the value of the underlying JS object.
+ *
+ * Returns false if an error occurred.
+ */
+ bool setValue(jsval new_value) {
+ value_ = new_value;
+ return true;
+ }
+
+ /*
+ * Returns true if the underlying value is of some number type.
+ */
+ bool isNumber() const {
+ return JSVAL_IS_NUMBER(value_);
+ }
+ /*
+ * Returns the underlying value as a double.
+ * Result is 0.0 if the underlying value is not a number
+ * type.
+ */
+ double getDouble() const {
+ jsdouble return_value=0.0;
+ // ignore return value -- if it fails, value will remain 0.0
+ JS_ValueToNumber(currentContext(), value_, &return_value);
+ return double(return_value);
+ }
+ /*
+ * Set the underlying value to a double value.
+ *
+ * Returns false on failure.
+ */
+ bool setDouble(double val) {
+ jsval js_double;
+ if(!JS_NewDoubleValue(currentContext(), jsdouble(val), &js_double)) {
+ return false;
+ }
+ return setValue(js_double);
+ }
+
+ /*
+ * Returns the underlying value as an integer value. Note that the result
+ * is undefined if isInt() does not return true.
+ */
+ int getInt() {
+ return JSVAL_TO_INT(value_);
+ }
+
+ /*
+ * Set the underlying value to an integer value.
+ *
+ * Returns false on failure.
+ */
+ bool setInt(int val) {
+ // check if it fits in 31 bits (ie, top two bits are equal).
+ // if not, store it as a double
+ if ((val & 0x80000000) != ((val << 1) & 0x80000000)) {
+ return setDouble(val);
+ } else {
+ return setValue(INT_TO_JSVAL(val));
+ }
+ }
+
+ /*
+ * Returns true if the underlying value is a boolean.
+ */
+ bool isBoolean() const {
+ return JSVAL_IS_BOOLEAN(value_);
+ }
+ /*
+ * Returns the underlying value as a boolean.
+ * Result is undefined if the value is not actually
+ * a boolean.
+ */
+ bool getBoolean() const {
+ return value_ != JSVAL_FALSE;
+ }
+ /*
+ * Set the underlying value to a boolean value.
+ *
+ * Returns false on failure (impossible?).
+ */
+ bool setBoolean(bool val) {
+ return setValue(val ? JSVAL_TRUE : JSVAL_FALSE);
+ }
+
+ /*
+ * Returns true if the underlying value is a string.
+ */
+ bool isInt() const {
+ return JSVAL_IS_INT(value_);
+ }
+
+ /*
+ * Returns true if the underlying value is a string.
+ */
+ bool isString() const {
+ return JSVAL_IS_STRING(value_);
+ }
+
+ /*
+ * Check if the value is a JavaScript String object.
+ */
+ bool isJavaScriptStringObject() const {
+ if (!isObject()) return false;
+ ensureStringClass();
+ return getObjectClass() == stringClass;
+ }
+
+ /*
+ * Return this value as a string, converting as necessary.
+ */
+ JSString* asString() const {
+ return JS_ValueToString(currentContext(), value_);
+ }
+
+ /* Returns the string as a JSString pointer.
+ * Result is undefined if the value is not actually a string or String object.
+ */
+ const JSString* getString() const {
+ if (JSVAL_IS_STRING(value_)) {
+ return JSVAL_TO_STRING(value_);
+ }
+ return asString();
+ }
+ /*
+ * Returns the string as a zero-terminated array of UTF16 characters.
+ * Note that this pointer may become invalid when JS performs GC, so it
+ * may only be used without calling other JS functions. Result is
+ * undefined if the value is not actually a string.
+ */
+ const wchar_t* getStringChars() const {
+ return reinterpret_cast<const wchar_t*>(JS_GetStringChars(
+ const_cast<JSString*>(getString())));
+ }
+
+ /*
+ * Returns the length of the underlying string. Result is undefined
+ * if the value is not actually a string.
+ */
+ int getStringLength() const {
+ return JS_GetStringLength(const_cast<JSString*>(getString()));
+ }
+
+ /*
+ * Sets the underlying value, defined by a null-terminated array of UTF16
+ * chars.
+ *
+ * Returns false on failure.
+ */
+ bool setString(const wchar_t* utf16) {
+ JSString* str = JS_NewUCStringCopyZ(currentContext(),
+ reinterpret_cast<const jschar*>(utf16));
+ return setValue(STRING_TO_JSVAL(str));
+ }
+
+ /*
+ * Sets the underlying value, defined by a counted array of UTF16 chars.
+ *
+ * Returns false on failure.
+ */
+ bool setString(const wchar_t* utf16, size_t len) {
+ JSString* str = JS_NewUCStringCopyN(currentContext(),
+ reinterpret_cast<const jschar*>(utf16), len);
+ return setValue(STRING_TO_JSVAL(str));
+ }
+
+ /*
+ * Returns true if the underlying value is an object.
+ */
+ bool isObject() const {
+ return JSVAL_IS_OBJECT(value_);
+ }
+
+ /*
+ * Returns the underlying value as an object.
+ * Result is undefined if it is not actually an object.
+ */
+ JSObject* getObject() const {
+ return isObject() ? JSVAL_TO_OBJECT(value_) : 0;
+ }
+
+ /*
+ * Returns the class name of the underlying value.
+ *
+ * Result is undefined if it is not actually an object.
+ */
+ const JSClass* getObjectClass() const {
+ return isObject() ? JS_GET_CLASS(currentContext(), getObject()) : 0;
+ }
+
+ /*
+ * Sets the underlying value to be an object.
+ *
+ * Returns false on failure.
+ */
+ bool setObject(JSObject* obj) {
+ return setValue(OBJECT_TO_JSVAL(obj));
+ }
+
+ /*
+ * Returns true if the underlying value is undefined (void).
+ */
+ bool isUndefined() const {
+ return JSVAL_IS_VOID(value_);
+ }
+
+ /*
+ * Sets the underlying value to be undefined (void).
+ *
+ * Returns false on failure (impossible?)
+ */
+ bool setUndefined() {
+ return setValue(JSVAL_VOID);
+ }
+
+ /*
+ * Returns true if the underlying value is null.
+ */
+ bool isNull() const {
+ return JSVAL_IS_NULL(value_);
+ }
+ /*
+ * Sets the underlying value to be null.
+ *
+ * Returns false on failure (impossible?)
+ */
+ bool setNull() {
+ return setValue(JSVAL_NULL);
+ }
+};
+
+#endif /*JNI_LINUX_JSROOTEDVALUE_H_*/
diff --git a/jni/linux/JsStringWrap.h b/jni/linux/JsStringWrap.h
new file mode 100644
index 0000000..7ab0ce6
--- /dev/null
+++ b/jni/linux/JsStringWrap.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#ifndef JNI_LINUX_JSSTRINGWRAP_H_
+#define JNI_LINUX_JSSTRINGWRAP_H_
+
+/*
+ * Wrapper arouond JavaScript Strings, keeps pointers to unpacked strings
+ * and makes sure they are not cleaned up early.
+ */
+class JsStringWrap {
+ private:
+ JSContext* context_;
+ JSString* string_;
+ const char* bytes_;
+ const wchar_t* chars_;
+
+ public:
+ JsStringWrap(JSContext* context, JSString* str)
+ : context_(context), string_(str), bytes_(0), chars_(0) {
+ JS_AddRoot(context_, &string_);
+ JS_AddRoot(context_, &bytes_);
+ JS_AddRoot(context_, &chars_);
+ }
+ JsStringWrap(JSContext* context, jsval str)
+ : context_(context), string_(JSVAL_TO_STRING(str)), bytes_(0), chars_(0) {
+ JS_AddRoot(context_, &string_);
+ JS_AddRoot(context_, &bytes_);
+ JS_AddRoot(context_, &chars_);
+ }
+ ~JsStringWrap() {
+ JS_RemoveRoot(context_, &string_);
+ JS_RemoveRoot(context_, &bytes_);
+ JS_RemoveRoot(context_, &chars_);
+ }
+ const char* bytes() {
+ if (!bytes_) bytes_ = JS_GetStringBytes(string_);
+ return bytes_;
+ }
+ const wchar_t* chars() {
+ if (!chars_) {
+ chars_ = reinterpret_cast<wchar_t*>(JS_GetStringChars(string_));
+ }
+ return chars_;
+ }
+ int length() {
+ return JS_GetStringLength(string_);
+ }
+};
+
+#endif // JNI_LINUX_JSSTRINGWRAP_H_
diff --git a/jni/linux/JsValueMoz.cpp b/jni/linux/JsValueMoz.cpp
new file mode 100644
index 0000000..195306c
--- /dev/null
+++ b/jni/linux/JsValueMoz.cpp
@@ -0,0 +1,993 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <jni.h>
+#include "JsRootedValue.h"
+#include "gwt-jni.h"
+#include "ExternalWrapper.h"
+#include "Tracer.h"
+
+// include javah-generated header to make sure things match
+#include "JsValueMoz.h"
+
+/*
+ * Returns the value of a field on a Java object.
+ *
+ * context - JavaScript context
+ * clazz - class of obj
+ * obj - Java object to retreive field from
+ * fieldName - name of field on Java object to retrieve
+ *
+ * Returns null on failure. Caller is responsible for deleting
+ * returned JsRootedValue when done with it.
+ */
+static JsRootedValue* GetFieldAsRootedValue(JSContext* cx, jclass clazz,
+ jobject obj, jstring fieldName)
+{
+ Tracer tracer("GetFieldAsRootedValue");
+ JsRootedValue::ContextManager context(cx);
+ jmethodID getFieldMeth = savedJNIEnv->GetMethodID(clazz, "getField",
+ "(Ljava/lang/String;I)V");
+ if (!getFieldMeth || savedJNIEnv->ExceptionCheck()) {
+ return 0;
+ }
+
+ JsRootedValue* jsRootedValue = new JsRootedValue();
+ savedJNIEnv->CallVoidMethod(obj, getFieldMeth, fieldName,
+ reinterpret_cast<jint>(jsRootedValue));
+ if (savedJNIEnv->ExceptionCheck()) {
+ delete jsRootedValue;
+ return 0;
+ }
+ return jsRootedValue;
+}
+
+/*
+ * Sets the value of a field on a Java object.
+ *
+ * context - JavaScript context
+ * clazz - class of obj
+ * obj - Java object to store into field
+ * fieldName - name of field on Java object to store into
+ * jsRootedValue - the value to store in the field
+ *
+ * returns true on success, false on failure
+ */
+static bool SetFieldFromRootedValue(JSContext* cx, jclass clazz,
+ jobject obj, jstring fieldName, JsRootedValue* jsRootedValue)
+{
+ Tracer tracer("SetFieldAsRootedValue");
+ JsRootedValue::ContextManager context(cx);
+ jmethodID getFieldMeth = savedJNIEnv->GetMethodID(clazz, "setField",
+ "(Ljava/lang/String;I)V");
+ if (!getFieldMeth || savedJNIEnv->ExceptionCheck()) {
+ return false;
+ }
+
+ savedJNIEnv->CallVoidMethod(obj, getFieldMeth, fieldName,
+ reinterpret_cast<jint>(jsRootedValue));
+ if (savedJNIEnv->ExceptionCheck()) {
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Throws a HostedModeException with the specified message.
+ */
+static void ThrowHostedModeException(JNIEnv* jniEnv, const char* msg) {
+ jclass exceptionClass
+ = jniEnv->FindClass("com/google/gwt/dev/shell/HostedModeException");
+ jniEnv->ThrowNew(exceptionClass, msg);
+}
+
+/*
+ * Types of jsvals.
+ */
+enum JsValueType {
+ JSVAL_TYPE_VOID=0,
+ JSVAL_TYPE_NULL,
+ JSVAL_TYPE_BOOLEAN,
+ JSVAL_TYPE_NUMBER,
+ JSVAL_TYPE_STRING,
+ JSVAL_TYPE_OBJECT,
+ JSVAL_TYPE_UNKNOWN,
+};
+
+/*
+ * Names of jsval types -- must match the order of the enum above.
+ */
+static const char* JsValueTypeStrings[]={
+ "undefined",
+ "null",
+ "boolean",
+ "number",
+ "string",
+ "object",
+ "unknown",
+};
+
+/*
+ * Return the type of a jsval.
+ */
+static JsValueType GetValueType(jsval val) {
+ if(JSVAL_IS_VOID(val)) {
+ return JSVAL_TYPE_VOID;
+ } else if(JSVAL_IS_NULL(val)) {
+ return JSVAL_TYPE_NULL;
+ } else if(JSVAL_IS_BOOLEAN(val)) {
+ return JSVAL_TYPE_BOOLEAN;
+ } else if(JSVAL_IS_NUMBER(val)) {
+ return JSVAL_TYPE_NUMBER;
+ } else if(JSVAL_IS_STRING(val)) {
+ return JSVAL_TYPE_STRING;
+ } else if(JSVAL_IS_OBJECT(val)) {
+ return JSVAL_TYPE_OBJECT;
+ } else {
+ return JSVAL_TYPE_UNKNOWN;
+ }
+}
+
+/*
+ * Called from JavaScript to call a Java method that has previously been
+ * wrapped. See _setWrappedFunction for use.
+ */
+static JSBool invokeJavaMethod(JSContext *cx, JSObject *obj, uintN argc,
+ jsval *argv, jsval *rval)
+{
+ Tracer tracer("invokeJavaMethod");
+ JsRootedValue::ContextManager context(cx);
+
+ // I kid you not; this is how XPConnect gets their function object so they can
+ // multiplex dispatch the call from a common site. See XPCDispObject.cpp(466)
+ //
+ // I now have a secondary confirmation that this trick is legit.
+ // brandon@mozilla.org writes:
+ //
+ // argv[-2] is part of the JS API, unabstracted. Just as argv[0] is the
+ // first argument (if argc != 0), argv[-1] is the |this| parameter (equal
+ // to OBJECT_TO_JSVAL(obj) in a native method with the standard |obj|
+ // second formal parameter name), and argv[-2] is the callee object, tagged
+ // as a jsval.
+ if (JS_TypeOfValue(cx, argv[-2]) != JSTYPE_FUNCTION) {
+ tracer.setFail("not a function type");
+ return JS_FALSE;
+ }
+ JSObject* funObj = JSVAL_TO_OBJECT(argv[-2]);
+
+ // Pull the wrapper object out of the funObj's reserved slot
+ jsval jsCleanupObj;
+ if (!JS_GetReservedSlot(cx, funObj, 0, &jsCleanupObj)) {
+ tracer.setFail("JS_GetReservedSlot failed");
+ return JS_FALSE;
+ }
+ JSObject* cleanupObj = JSVAL_TO_OBJECT(jsCleanupObj);
+ if (!cleanupObj) {
+ tracer.setFail("cleanupObj is null");
+ return JS_FALSE;
+ }
+
+ // Get DispatchMethod instance out of the wrapper object
+ jobject dispMeth =
+ NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, cleanupObj));
+ if (!dispMeth) {
+ tracer.setFail("dispMeth is null");
+ return JS_FALSE;
+ }
+ jclass dispClass = savedJNIEnv->GetObjectClass(dispMeth);
+ if (!dispClass || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("GetObjectClass returns null");
+ return JS_FALSE;
+ }
+
+ // lookup the invoke method on the dispatch object
+ jmethodID invokeID =
+ savedJNIEnv->GetMethodID(dispClass, "invoke", "(I[II)V");
+ if (!invokeID || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("GetMethodID failed");
+ return JS_FALSE;
+ }
+
+ // create an array of integers to hold the JsRootedValue pointers passed
+ // to the invoke method
+ jintArray args = savedJNIEnv->NewIntArray(argc);
+ if (!args || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("NewIntArray failed");
+ return JS_FALSE;
+ }
+
+ // these arguments are already rooted by the JS interpreter, but we
+ // can't easily take advantage of that without complicating the JsRootedValue
+ // interface.
+
+ // argv[-1] is OBJECT_TO_JSVAL(this)
+ JsRootedValue* jsThis = new JsRootedValue(argv[-1]);
+ tracer.log("jsthis=%08x, RV=%08x", unsigned(argv[-1]), unsigned(jsThis));
+
+ // create JsRootedValues for arguments
+ JsRootedValue *jsArgs[argc];
+ for (uintN i = 0; i < argc; ++i) {
+ jsArgs[i] = new JsRootedValue(argv[i]);
+ }
+ savedJNIEnv->SetIntArrayRegion(args, 0, argc,
+ reinterpret_cast<jint*>(jsArgs));
+ if (savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("SetIntArrayRegion failed");
+ return JS_FALSE;
+ }
+
+ // slot for return value
+ JsRootedValue* jsReturnVal = new JsRootedValue();
+
+ // TODO(jat): small window here where invocation may fail before Java
+ // takes ownership of the JsRootedValue objects. One solution would be
+ // to reference-count them between Java and C++ (so the reference count
+ // would always be 0, 1, or 2). Also setField has a similar problem.
+ // I plan to fix this when switching away from Java holding pointers to
+ // C++ objects as part of the fix for 64-bit support (which we could
+ // accomplish inefficiently by changing int to long everywhere, but there
+ // are other 64-bit issues to resolve and we need to reduce the number of
+ // roots the JS interpreter has to search.
+
+ // call Java method
+ savedJNIEnv->CallVoidMethod(dispMeth, invokeID, reinterpret_cast<int>(jsThis),
+ args, reinterpret_cast<int>(jsReturnVal));
+
+ JSBool returnValue = JS_TRUE;
+
+ if (savedJNIEnv->ExceptionCheck()) {
+ tracer.log("dispMeth=%08x", unsigned(dispMeth));
+ tracer.setFail("java exception is active:");
+ jobject exception = savedJNIEnv->ExceptionOccurred();
+ if (exception) {
+ fprintf(stderr, "Exception occurred in MethodDispatch.invoke:\n");
+ savedJNIEnv->ExceptionDescribe();
+ savedJNIEnv->DeleteLocalRef(exception);
+ }
+ returnValue = JS_FALSE;
+ } else if (JS_IsExceptionPending(cx)) {
+ tracer.setFail("js exception is active");
+ returnValue = JS_FALSE;
+ }
+
+ // extract return value
+ *rval = jsReturnVal->getValue();
+
+#if 0
+ // NOTE: C++ objects are not cleaned up here because Java now owns them.
+ // TODO(jat): if reference-counted, they *do* need to be Released here.
+
+ // free JsRootedValues
+ for (uintN i = 0; i < argc; ++i) {
+ delete jsArgs[i];
+ }
+ delete jsThis;
+ delete jsReturnVal;
+#endif
+
+ return returnValue;
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _createJsRootedValue()
+ * Signature: (I)I
+ */
+extern "C" JNIEXPORT jint JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1createJsRootedValue
+ (JNIEnv* jniEnv, jclass, jint jsval)
+{
+ Tracer tracer("JsValueMoz._createJsRootedValue");
+ JsRootedValue* jsRootedValue = new JsRootedValue(jsval);
+ return NS_REINTERPRET_CAST(jint, jsRootedValue);
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _copyJsRootedValue()
+ * Signature: (I)I
+ */
+extern "C" JNIEXPORT jint JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1copyJsRootedValue
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ const JsRootedValue* jsRootedValue = reinterpret_cast<const JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._copyJsRootedValue", jsRootedValue);
+ JsRootedValue* newRootedValue = new JsRootedValue(*jsRootedValue);
+ return NS_REINTERPRET_CAST(jint, newRootedValue);
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _destroyJsRootedValue()
+ * Signature: (I)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1destroyJsRootedValue
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._destroyJsRootedValue", jsRootedValue);
+ delete jsRootedValue;
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _getBoolean()
+ * Signature: (I)Z
+ *
+ * TODO(jat): unboxing Javascript Boolean type?
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getBoolean
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._getBoolean", jsRootedValue);
+ return jsRootedValue->getBoolean();
+}
+
+/**
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _getInt()
+ * Signature: (I)I
+ *
+ * @see com.google.gwt.dev.shell.moz.JsValueMoz#getInt()
+ */
+extern "C" JNIEXPORT jint JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getInt
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._getInt", jsRootedValue);
+ int val = jsRootedValue->getInt();
+ tracer.log("value=%d", val);
+ return val;
+}
+
+/**
+ * Return a Javascript number as a Java double.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _getNumber()
+ * Signature: (I)D
+ */
+extern "C" JNIEXPORT jdouble JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getNumber
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._getNumber", jsRootedValue);
+ return jsRootedValue->getDouble();
+}
+
+/**
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _getJsval()
+ * Signature: (I)I
+ */
+extern "C" JNIEXPORT jint JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getJsval
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._getObjectPointer", jsRootedValue);
+ int val = jsRootedValue->getValue();
+ tracer.log("value=%d", val);
+ return val;
+}
+
+/**
+ * Return a Javascript string as a Java string.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _getString()
+ * Signature: (I)Ljava/lang/String;
+ *
+ * Note that this relies on jschar being assignment compatible with jchar
+ */
+extern "C" JNIEXPORT jstring JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getString
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._getString", jsRootedValue);
+ const JSString* str = jsRootedValue->getString();
+ int len = JS_GetStringLength(const_cast<JSString*>(str));
+ jstring javaStr =jniEnv->NewString(reinterpret_cast<const jchar*>(
+ JS_GetStringChars(const_cast<JSString*>(str))), len);
+ return javaStr;
+}
+
+/*
+ * Returns a human-readable Java string describing the type of a
+ * JavaScript object.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _getTypeString
+ * Signature: (I)Ljava/lang/String;
+ */
+extern "C" JNIEXPORT jstring JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getTypeString
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._getTypeString", jsRootedValue);
+ jsval val = jsRootedValue->getValue();
+ JSContext* cx = JsRootedValue::currentContext();
+ JsValueType valueType = GetValueType(val);
+ const char* typeString = 0;
+ char buf[256];
+ if(valueType == JSVAL_TYPE_OBJECT) {
+ JSObject* jsObject = JSVAL_TO_OBJECT(val);
+ JSClass* objClass = JS_GET_CLASS(cx, jsObject);
+ if (JS_InstanceOf(cx, jsObject,
+ &gwt_nativewrapper_class, 0)) {
+ typeString = "Java object";
+ } else {
+ snprintf(buf, sizeof(buf), "class %s", objClass->name);
+ typeString = buf;
+ }
+ } else {
+ typeString = JsValueTypeStrings[valueType];
+ }
+ jstring returnValue = jniEnv->NewStringUTF(typeString);
+ return returnValue;
+}
+
+/*
+ * Unwraps a wrapped Java object from a JS object.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _getWrappedJavaObject
+ * Signature: (I)Ljava/lang/Object;
+ */
+extern "C" JNIEXPORT jobject JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1getWrappedJavaObject
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._getWrappedJavaObject", jsRootedValue);
+ JSObject* jsObject = jsRootedValue->getObject();
+ if(!jsObject) {
+ tracer.throwHostedModeException(jniEnv, "Javascript value not an object");
+ return 0;
+ }
+ JSContext* cx = JsRootedValue::currentContext();
+ if(!JS_InstanceOf(cx, jsObject, &gwt_nativewrapper_class, 0)) {
+ tracer.throwHostedModeException(jniEnv,
+ "Javascript object not a Java object");
+ return 0;
+ }
+ jobject javaObject
+ = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, jsObject));
+ return javaObject;
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _isBoolean()
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isBoolean
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._isBoolean", jsRootedValue);
+ return jsRootedValue->isBoolean();
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _isInt()
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isInt
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._isBoolean", jsRootedValue);
+ return jsRootedValue->isInt();
+}
+
+/*
+ * Checks if a JS object is a JavaScript object.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _isJavaScriptObject
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isJavaScriptObject
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._isJavaScriptObject", jsRootedValue);
+ jsval val = jsRootedValue->getValue();
+ bool returnValue = false;
+ if(JSVAL_IS_OBJECT(val)) {
+ JSObject* jsObject = JSVAL_TO_OBJECT(val);
+ returnValue = !JS_InstanceOf(JsRootedValue::currentContext(), jsObject,
+ &gwt_nativewrapper_class, 0);
+ tracer.log("jsobject=%08x, isJSObject=%s", unsigned(jsObject),
+ returnValue ? "true" : "false");
+ } else {
+ tracer.log("not an object");
+ }
+ return returnValue;
+}
+
+/*
+ * Checks if a JS object is a JavaScript String object.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _isJavaScriptString
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isJavaScriptString
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._isJavaScriptString", jsRootedValue);
+ bool returnValue = jsRootedValue->isJavaScriptStringObject();
+ tracer.log("value=%s", returnValue ? "true" : "false");
+ return returnValue;
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _isNull()
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isNull
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._isNull", jsRootedValue);
+ return jsRootedValue->isNull();
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _isNumber()
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isNumber
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._isNumber", jsRootedValue);
+ return jsRootedValue->isNumber();
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _isString()
+ * Signature: (I)Z
+ *
+ * Handles the case of JavaScript String objects as well
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isString
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._isString", jsRootedValue);
+ return jsRootedValue->isString();
+}
+
+/*
+ * Checks if a JS object is undefined (void)
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _isUndefined
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isUndefined
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._isUndefined", jsRootedValue);
+ return jsRootedValue->isUndefined();
+}
+
+/*
+ * Checks if a JS object is a wrapped Java object.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _isWrappedJavaObject
+ * Signature: (I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1isWrappedJavaObject
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._isWrappedJavaObject", jsRootedValue);
+ jsval val = jsRootedValue->getValue();
+ bool returnValue = false;
+ if(JSVAL_IS_OBJECT(val)) {
+ JSObject* jsObject = JSVAL_TO_OBJECT(val);
+ returnValue = JS_InstanceOf(JsRootedValue::currentContext(), jsObject,
+ &gwt_nativewrapper_class, 0);
+ tracer.log("jsobject=%08x, wrappedJava=%s", unsigned(jsObject),
+ returnValue ? "true" : "false");
+ } else {
+ tracer.log("not an object");
+ }
+ return returnValue;
+}
+
+/*
+ * Set the JavaScript value to be a boolean of the supplied value.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setBoolean()
+ * Signature: (IZ)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setBoolean
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jboolean val)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._setBoolean", jsRootedValue);
+ jsRootedValue->setBoolean(val == JNI_TRUE);
+ return;
+}
+
+/*
+ * Set the JavaScript value to be a double of the supplied value.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setDouble()
+ * Signature: (ID)V
+ */
+extern "C" JNIEXPORT void
+JNICALL Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setDouble
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jdouble val)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._setDouble", jsRootedValue);
+ if(!jsRootedValue->setDouble(val)) {
+ tracer.throwHostedModeException(jniEnv, "Unable to allocate JS double");
+ return;
+ }
+}
+
+/*
+ * Set the Javascript value to be an integer.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setInt()
+ * Signature: (II)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setInt
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jint val)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._setInt", jsRootedValue);
+ tracer.log("val=%d", val);
+ jsRootedValue->setInt(val);
+}
+
+/*
+ * Set the Javascript value to be another JsRootedValue's value.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setJsRootedValue()
+ * Signature: (II)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setJsRootedValue
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jint jsOtherRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ JsRootedValue* jsOtherRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsOtherRootedValueInt);
+ Tracer tracer("JsValueMoz._setJsRootedValue", jsRootedValue);
+ jsRootedValue->setValue(jsOtherRootedValue->getValue());
+}
+
+/*
+ * Set the Javascript value to a specific jsval.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setJsval()
+ * Signature: (II)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setJsval
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jint jsval)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._setJsval", jsRootedValue);
+ jsRootedValue->setValue(jsval);
+}
+
+/*
+ * Set the JavaScript value to be null.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setNull()
+ * Signature: (I)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setNull
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._setNull", jsRootedValue);
+ jsRootedValue->setNull();
+}
+
+/*
+ * Set the JavaScript value to be a string of the supplied value.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setString()
+ * Signature: (ILjava/lang/String;)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setString
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jstring val)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._setString", jsRootedValue);
+ JStringWrap strVal(jniEnv, val);
+ const jchar* stringUTF16 = strVal.jstr();
+ if(!stringUTF16) {
+ tracer.throwHostedModeException(jniEnv, "Unable to retrieve Java string");
+ return;
+ }
+ tracer.log("string=%s", strVal.str());
+ if(!jsRootedValue->setString(reinterpret_cast<const wchar_t*>(stringUTF16),
+ strVal.length())) {
+ tracer.throwHostedModeException(jniEnv, "Unable to allocate JS string");
+ return;
+ }
+}
+
+/*
+ * Set the JavaScript value to be undefined (void).
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setUndefined()
+ * Signature: (I)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setUndefined
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._setUndefined", jsRootedValue);
+ jsRootedValue->setUndefined();
+}
+
+/*
+ * Wraps a Java object in a JS object.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setWrappedJavaObject
+ * Signature: (ILjava/lang/Object)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setWrappedJavaObject
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jobject obj)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._setWrappedJavaObject", jsRootedValue);
+ JSContext* cx = JsRootedValue::currentContext();
+ JSObject* scriptWindow = JS_GetGlobalObject(cx);
+ JSObject* newObj = JS_NewObject(cx, &gwt_nativewrapper_class, 0,
+ scriptWindow);
+ if (!newObj) {
+ tracer.throwHostedModeException(jniEnv,
+ "Unable to allocate JS object to wrap Java object");
+ return;
+ }
+ // Save in output value so it won't get GCed.
+ jsRootedValue->setObject(newObj);
+ tracer.log("jsobject=%08x", unsigned(newObj));
+
+ // This is collected when the gwt_nativewrapper_class destructor runs.
+ jobject dispObjRef = jniEnv->NewGlobalRef(obj);
+ if (!dispObjRef || jniEnv->ExceptionCheck()) {
+ tracer.throwHostedModeException(jniEnv,
+ "Unable to allocate global reference for JS wrapper");
+ return;
+ }
+ if (!JS_SetPrivate(cx, newObj, dispObjRef)) {
+ jniEnv->DeleteGlobalRef(dispObjRef);
+ tracer.throwHostedModeException(jniEnv,
+ "Unable to allocate global reference for JS wrapper");
+ return;
+ }
+ // forcibly setup a "toString" method to override the default
+ jclass dispClass = jniEnv->GetObjectClass(obj);
+ if (jniEnv->ExceptionCheck()) {
+ tracer.throwHostedModeException(jniEnv, "Can't get object class");
+ return;
+ }
+ jmethodID getFieldMeth = jniEnv->GetMethodID(dispClass, "getField",
+ "(Ljava/lang/String;I)V");
+ if (!getFieldMeth || jniEnv->ExceptionCheck()) {
+ tracer.throwHostedModeException(jniEnv, "Can't get getField method");
+ return;
+ }
+ jstring ident = jniEnv->NewStringUTF("@java.lang.Object::toString()");
+ if (!ident || jniEnv->ExceptionCheck()) {
+ tracer.throwHostedModeException(jniEnv,
+ "Can't create Java string for toString method name");
+ return;
+ }
+ // allocate a new root to hold the result of the getField call
+ JsRootedValue* toStringFunc = new JsRootedValue();
+ jniEnv->CallVoidMethod(obj, getFieldMeth, ident,
+ NS_REINTERPRET_CAST(jint, toStringFunc));
+ if (toStringFunc->isUndefined() || jniEnv->ExceptionCheck()) {
+ tracer.throwHostedModeException(jniEnv, "getField(toString) failed");
+ return;
+ }
+ if (!JS_DefineProperty(cx, newObj, "toString", toStringFunc->getValue(),
+ JS_PropertyStub, JS_PropertyStub, JSPROP_READONLY | JSPROP_PERMANENT)) {
+ tracer.throwHostedModeException(jniEnv, "Can't define JS toString method");
+ return;
+ }
+}
+
+/*
+ * Wraps a Java function in a JS object.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _setWrappedFunction
+ * Signature: (ILjava/lang/String;Lcom/google/gwt/dev/shell/moz/DispatchMethod;)V
+ */
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1setWrappedFunction
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt, jstring methodName,
+ jobject dispatchMethod)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._setWrappedFunction", jsRootedValue);
+ JSContext* cx = JsRootedValue::currentContext();
+ JSObject* scriptWindow = JS_GetGlobalObject(cx);
+ JStringWrap nameStr(jniEnv, methodName);
+ if (!nameStr.str()) {
+ tracer.throwHostedModeException(jniEnv,
+ "null method name passed to setWrappedFunction");
+ return;
+ }
+ tracer.log("JsRootedValue=%08x, method=%s, obj=%08x", jsRootedValueInt,
+ nameStr.str(), unsigned(dispatchMethod));
+ JSFunction* function = JS_NewFunction(cx, invokeJavaMethod, 0,
+ JSFUN_LAMBDA, 0, nameStr.str());
+ if (!function) {
+ tracer.throwHostedModeException(jniEnv, "JS_NewFunction failed");
+ return;
+ }
+ JSObject* funObj = JS_GetFunctionObject(function);
+ if (!funObj) {
+ tracer.throwHostedModeException(jniEnv, "JS_GetFunctionObject failed");
+ return;
+ }
+ // Save in output value so it won't get GCed.
+ jsRootedValue->setObject(funObj);
+
+ // Create a cleanup object to hold and clean up dispMeth
+ JSObject* cleanupObj = JS_NewObject(cx, &gwt_functionwrapper_class, 0,
+ scriptWindow);
+ if (!cleanupObj) {
+ tracer.throwHostedModeException(jniEnv, "JS_NewObject failed");
+ return;
+ }
+ tracer.log("funObj=%08x, cleanupObj=%08x", unsigned(funObj),
+ unsigned(cleanupObj));
+ // Store the cleanup object in funObj's reserved slot; now GC protected.
+ if(!JS_SetReservedSlot(cx, funObj, 0, OBJECT_TO_JSVAL(cleanupObj))) {
+ tracer.throwHostedModeException(jniEnv, "JS_SetReservedSlot failed");
+ return;
+ }
+ jobject dispMethRef = jniEnv->NewGlobalRef(dispatchMethod);
+ if (!dispMethRef || jniEnv->ExceptionCheck()) {
+ tracer.throwHostedModeException(jniEnv,
+ "NewGlobalRef(dispatchMethod) failed");
+ return;
+ }
+ // Store our global ref in the wrapper object
+ if (!JS_SetPrivate(cx, cleanupObj, dispMethRef)) {
+ jniEnv->DeleteGlobalRef(dispMethRef);
+ tracer.throwHostedModeException(jniEnv, "JS_SetPrivate(cleanupObj) failed");
+ return;
+ }
+}
+
+/*
+ * Returns a JavaScript value as a string.
+ *
+ * Class: com_google_gwt_dev_shell_moz_JsValueMoz
+ * Method: _toString
+ * Signature: (I)Ljava/lang/String;
+ */
+extern "C" JNIEXPORT jstring JNICALL
+Java_com_google_gwt_dev_shell_moz_JsValueMoz__1toString
+ (JNIEnv* jniEnv, jclass, jint jsRootedValueInt)
+{
+ JsRootedValue* jsRootedValue = reinterpret_cast<JsRootedValue*>
+ (jsRootedValueInt);
+ Tracer tracer("JsValueMoz._toString", jsRootedValue);
+ jsval val = jsRootedValue->getValue();
+ JSContext* cx = JsRootedValue::currentContext();
+
+ // if it is a JavaScript object that has a toString member function
+ // call that, otherwise call JS_ValueToString
+ if(JSVAL_IS_OBJECT(val)) {
+ JSObject* jsObject = JSVAL_TO_OBJECT(val);
+ jsval fval;
+ jsval rval;
+ if (!JS_InstanceOf(cx, jsObject, &gwt_nativewrapper_class, 0)
+ && JS_GetProperty(cx, jsObject, "toString", &fval)
+ && JS_ValueToFunction(cx, fval)
+ && JS_CallFunctionValue(cx, jsObject, fval, 0, 0, &rval)) {
+ // all the steps succeeded, so use the result of toString() instead
+ // of the value for JS_ValueToString below
+ val = rval;
+ }
+ }
+ JSString* str = JS_ValueToString(cx, val);
+ if (!str) {
+ return 0;
+ }
+ int len = JS_GetStringLength(str);
+ jstring javaStr =jniEnv->NewString(reinterpret_cast<const jchar*>(
+ JS_GetStringChars(str)), len);
+ return javaStr;
+}
diff --git a/jni/linux/LowLevelMoz.cpp b/jni/linux/LowLevelMoz.cpp
new file mode 100644
index 0000000..9c3aba2
--- /dev/null
+++ b/jni/linux/LowLevelMoz.cpp
@@ -0,0 +1,380 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+// Mozilla-specific hosted-mode methods
+
+// Define to log debug-level output rather than just warnings.
+#define DEBUG
+
+#include <cstdio>
+#include <cstdarg>
+#include <cwchar>
+
+// Mozilla header files
+#include "mozilla-headers.h"
+
+#include <jni.h>
+#include "gwt-jni.h"
+#include "JsRootedValue.h"
+#include "ExternalWrapper.h"
+#include "Tracer.h"
+#include "JsStringWrap.h"
+
+/*
+ * Debug definitions -- define FILETRACE to have debug output written to
+ * a file named gwt-ll.log, or JAVATRACE to have debug output passed to the
+ * Java LowLevelMoz.trace method.
+ */
+#ifdef ENABLE_TRACING
+#define FILETRACE
+//#define JAVATRACE
+#endif
+
+// include javah-generated header to make sure we match
+#include "LowLevelMoz.h"
+
+JNIEnv* savedJNIEnv = 0;
+jclass lowLevelMozClass;
+
+// Only include debugging code if we are tracing somewhere.
+#ifdef ENABLE_TRACING
+
+/*
+ * Template so vsnprintf/vswprintf can be used interchangeably in the
+ * append_sprintf template below.
+ * buf - pointer to the start of the output buffer
+ * len - maximum number of characters to write into the buffer
+ * (including the null terminator)
+ * fmt - printf-style format string
+ * args - stdarg-style variable arguments list
+ * Returns the number of characters written (excluding the null terminator)
+ * or -1 if an error occurred.
+ *
+ * Note that %lc and %ls are only legal in the wchar_t implementation.
+ */
+template<class charT>
+int safe_vsprintf(charT* buf, size_t len, const charT* fmt, va_list args);
+
+// specialization for char that maps to vsnprintf
+template<>
+inline int safe_vsprintf<char>(char* buf, size_t len, const char* fmt,
+ va_list args) {
+ return ::vsnprintf(buf, len, fmt, args);
+}
+
+// specialization for wchar_t that maps to vswprintf
+template<>
+inline int safe_vsprintf<wchar_t>(wchar_t* buf, size_t len, const wchar_t* fmt,
+ va_list args) {
+ return ::vswprintf(buf, len, fmt, args);
+}
+
+/*
+ * Safely append to a string buffer, updating the output pointer and always
+ * reserving the last character of the buffer for a null terminator.
+ * bufStart - pointer to the start of the output buffer
+ * bufEnd - pointer just past the end of the output buffer
+ * fmt - format string
+ * additional arguments as passed to *printf
+ * Returns the number of characters actually written, not including the null
+ * terminator. Nothing is written, including the null terminator, if the
+ * buffer start points beyond the output buffer.
+ *
+ * Templated to work with any character type that has a safe_vsprintf
+ * implementation.
+ */
+template<class charT>
+static int append_sprintf(charT* bufStart, const charT* bufEnd,
+ const charT* fmt, ...) {
+ va_list args;
+ va_start(args, fmt); // initialize variable arguments list
+ // compute space left in buffer: -1 for null terminator
+ int maxlen = bufEnd - bufStart - 1;
+ if (maxlen <= 0) return 0;
+ int n = safe_vsprintf(bufStart, maxlen, fmt, args);
+ va_end(args);
+ if (n > maxlen) {
+ n = maxlen;
+ }
+ bufStart[n] = 0;
+ return n;
+}
+
+/*
+ * Log a given jsval with a prefix.
+ * cx - JSContext for the JS execution context to use
+ * val - jsval to print
+ * prefix - string to print before the value, defaults to empty string
+ *
+ * TODO(jat): this whole printf-style logging needs to be replaced, but we
+ * run into library version issues if we use C++ iostreams so we would need
+ * to implement our own equivalent. Given that this code is all likely to
+ * be rewritten for out-of-process hosted mode, it seems unlikely to be worth
+ * the effort until that is completed.
+ */
+void PrintJSValue(JSContext* cx, jsval val, char* prefix="") {
+ JSType type = JS_TypeOfValue(cx, val);
+ const char* typeString=JS_GetTypeName(cx, type);
+ static const int BUF_SIZE = 256;
+ char buf[BUF_SIZE];
+ const char *bufEnd = buf + BUF_SIZE;
+ char* p = buf;
+ p += append_sprintf(p, bufEnd, "%s%s", prefix, typeString);
+ switch(type) {
+ case JSTYPE_VOID:
+ break;
+ case JSTYPE_BOOLEAN:
+ p += append_sprintf(p, bufEnd, ": %s",
+ JSVAL_TO_BOOLEAN(val) ? "true" : "false");
+ break;
+ case JSTYPE_NUMBER:
+ if (JSVAL_IS_INT(val)) {
+ p += append_sprintf(p, bufEnd, ": %d", JSVAL_TO_INT(val));
+ } else {
+ p += append_sprintf(p, bufEnd, ": %lf", (double)*JSVAL_TO_DOUBLE(val));
+ }
+ break;
+ case JSTYPE_OBJECT: {
+ JSObject* obj = JSVAL_TO_OBJECT(val);
+ if (!JSVAL_IS_OBJECT(val)) break;
+ JSClass* clazz = obj ? JS_GET_CLASS(cx, obj) : 0;
+ p += append_sprintf(p, bufEnd, " @ %08x, class %s",
+ (unsigned)obj, clazz ? clazz->name : "<null>");
+ break;
+ }
+ case JSTYPE_FUNCTION:
+ case JSTYPE_LIMIT:
+ break;
+ case JSTYPE_STRING: {
+ /*
+ * TODO(jat): support JS strings with international characters
+ */
+ JsStringWrap str(cx, JSVAL_TO_STRING(val));
+ p += append_sprintf(p, bufEnd, ": %.*s", str.length(), str.bytes());
+ break;
+ }
+ }
+ Tracer::log("%s", buf);
+}
+#else
+// Include a null version just to keep from cluttering up call sites.
+static inline void PrintJSValue(JSContext* cx, jsval val, char* prefix="") { }
+#endif
+
+
+static bool InitGlobals(JNIEnv* env, jclass llClass) {
+ if (savedJNIEnv)
+ return false;
+
+#ifdef FILETRACE
+ Tracer::setFile("gwt-ll.log");
+#endif // FILETRACE
+
+#ifdef JAVATRACE
+ Tracer::setJava(env, llClass);
+#endif // JAVATRACE
+
+#ifdef DEBUG
+ Tracer::setLevel(Tracer::LEVEL_DEBUG);
+#endif
+
+ savedJNIEnv = env;
+ lowLevelMozClass = static_cast<jclass>(env->NewGlobalRef(llClass));
+ return true;
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method: _executeScriptWithInfo
+ * Signature: (ILjava/lang/String;Ljava/lang/String;I)Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1executeScriptWithInfo
+ (JNIEnv* env, jclass llClass, jint scriptObjectInt, jstring code,
+ jstring file, jint line)
+{
+ Tracer tracer("LowLevelMoz._executeScriptWithInfo");
+ JStringWrap jcode(env, code);
+ if (!jcode.jstr()) {
+ tracer.setFail("null code string");
+ return JNI_FALSE;
+ }
+ JStringWrap jfile(env, file);
+ if (!jfile.str()) {
+ tracer.setFail("null file name");
+ return JNI_FALSE;
+ }
+ tracer.log("code=%s, file=%s, line=%d", jcode.str(), jfile.str(), line);
+ JSContext* cx = JsRootedValue::currentContext();
+ nsCOMPtr<nsIScriptContext> scriptContext(GetScriptContextFromJSContext(cx));
+
+ nsIScriptGlobalObject* scriptObject =
+ NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjectInt);
+ JSObject* scriptWindow =
+ reinterpret_cast<JSObject*>(scriptObject->GetGlobalJSObject());
+ nsXPIDLString scriptString;
+ scriptString = jcode.jstr();
+
+ nsXPIDLString aRetValue;
+ PRBool aIsUndefined;
+ if (NS_FAILED(scriptContext->EvaluateString(scriptString, scriptWindow, 0,
+ jfile.str(), line, 0, aRetValue, &aIsUndefined))) {
+ tracer.setFail("EvaluateString failed");
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method: _invoke
+ * Signature: (ILjava/lang/String;I[I)I
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1invoke
+ (JNIEnv* env, jclass, jint scriptObjInt, jstring methodName, jint jsThisInt,
+ jintArray jsArgsInt, jint jsRetValInt)
+{
+ Tracer tracer("LowLevelMoz._invoke");
+
+ JStringWrap methodStr(env, methodName);
+ if (!methodStr.str()) {
+ tracer.setFail("null method name");
+ return JNI_FALSE;
+ }
+ JsRootedValue* jsThisRV = reinterpret_cast<JsRootedValue*>(jsThisInt);
+ jint jsArgc = env->GetArrayLength(jsArgsInt);
+ tracer.log("method=%s, jsthis=%08x, #args=%d", methodStr.str(), jsThisInt,
+ jsArgc);
+ JSContext* cx = JsRootedValue::currentContext();
+ nsIScriptGlobalObject* scriptObject =
+ NS_REINTERPRET_CAST(nsIScriptGlobalObject*, scriptObjInt);
+ JSObject* scriptWindow
+ = reinterpret_cast<JSObject*>(scriptObject->GetGlobalJSObject());
+
+ jsval fval;
+ if (!JS_GetProperty(cx, scriptWindow, methodStr.str(), &fval)) {
+ tracer.setFail("JS_GetProperty(method) failed");
+ return JNI_FALSE;
+ }
+ JSFunction* jsFunction = JS_ValueToFunction(cx, fval);
+ if (!jsFunction) {
+ tracer.setFail("JS_ValueToFunction failed");
+ return JNI_FALSE;
+ }
+
+ // extract arguments in jsval form
+ nsAutoArrayPtr<jint> jsargvals(new jint[jsArgc]);
+ if (!jsargvals) {
+ tracer.setFail("failed to allocate arg array");
+ return JNI_FALSE;
+ }
+ env->GetIntArrayRegion(jsArgsInt, 0, jsArgc, jsargvals);
+ if (env->ExceptionCheck()) {
+ tracer.setFail("copy from Java array failed");
+ return JNI_FALSE;
+ }
+ nsAutoArrayPtr<jsval> jsargs(new jsval[jsArgc]);
+ for (int i = 0; i < jsArgc; ++i) {
+ JsRootedValue* arg = reinterpret_cast<JsRootedValue*>(jsargvals[i]);
+ jsargs[i] = arg->getValue();
+ }
+
+ jsval jsrval;
+ JSObject* jsThis;
+ if (jsThisRV->isNull()) {
+ jsThis = scriptWindow;
+ } else {
+ jsThis = jsThisRV->getObject();
+ }
+
+ PrintJSValue(cx, OBJECT_TO_JSVAL(jsThis), "jsThis=");
+ for (int i = 0; i < jsArgc; ++i) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "arg[%d]=", i);
+ PrintJSValue(cx, jsargs[i], buf);
+ }
+ //tracer.log("fval = %08x, args=%08x", fval, jsargs.get());
+ if (!JS_CallFunctionValue(cx, jsThis, fval, jsArgc, jsargs.get(), &jsrval)) {
+ tracer.setFail("JS_CallFunctionValue failed");
+ return JNI_FALSE;
+ }
+
+ PrintJSValue(cx, jsrval, "return value=");
+ JsRootedValue* returnVal = reinterpret_cast<JsRootedValue*>(jsRetValInt);
+ returnVal->setValue(jsrval);
+ return JNI_TRUE;
+}
+
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method: _raiseJavaScriptException
+ * Signature: ()Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1raiseJavaScriptException
+ (JNIEnv* env, jclass)
+{
+ Tracer tracer("LowLevelMoz._raiseJavaScriptException");
+ JS_SetPendingException(JsRootedValue::currentContext(), JSVAL_NULL);
+ return JNI_TRUE;
+}
+
+/*
+ * Class: com_google_gwt_dev_shell_moz_LowLevelMoz
+ * Method: _registerExternalFactoryHandler
+ * Signature: ()Z
+ */
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_gwt_dev_shell_moz_LowLevelMoz__1registerExternalFactoryHandler
+ (JNIEnv* env, jclass llClass)
+{
+ if (!InitGlobals(env, llClass))
+ return JNI_FALSE;
+
+ // tracing isn't setup until after InitGlobals is called
+ Tracer tracer("LowLevelMoz._registerExternalFactoryHandler");
+
+ char buf[256];
+ sprintf(buf, " jniEnv=%08x, llClass=%08x", (unsigned)env, (unsigned)llClass);
+ tracer.log(buf);
+
+ // Register "window.external" as our own class
+ if (NS_FAILED(nsComponentManager::RegisterFactory(
+ kGwtExternalCID, "externalFactory", GWT_EXTERNAL_CONTRACTID,
+ new nsRpExternalFactory(), PR_TRUE))) {
+ tracer.setFail("RegisterFactory failed");
+ return JNI_FALSE;
+ }
+
+ nsCOMPtr<nsICategoryManager> categoryManager =
+ do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
+ if (!categoryManager) {
+ tracer.setFail("unable to get category manager");
+ return JNI_FALSE;
+ }
+
+ nsXPIDLCString previous;
+ if (NS_FAILED(categoryManager->AddCategoryEntry(
+ JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY, "external", GWT_EXTERNAL_CONTRACTID,
+ PR_TRUE, PR_TRUE, getter_Copies(previous)))) {
+ tracer.setFail("AddCategoryEntry failed");
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
diff --git a/jni/linux/Makefile b/jni/linux/Makefile
new file mode 100644
index 0000000..8b3a8cf
--- /dev/null
+++ b/jni/linux/Makefile
@@ -0,0 +1,153 @@
+# Copyright 2007 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+##
+# Target settings
+##
+#JAVA_HOME
+#JAVA_HOME=/usr/lib/j2sdk1.5-sun
+
+# set GWT_TOOLS only if it is not already defined
+GWT_TOOLS ?= ../../../tools
+
+GWT_ROOT = ../../
+OBJDIR := $(GWT_ROOT)build/out/jni/linux/
+OUTDIR := $(GWT_ROOT)build/jni/linux/
+OUT := $(OUTDIR)libgwt-ll.so
+STAGING := $(GWT_ROOT)build/staging/gwt-linux-0.0.0/
+
+##
+# The location to get .class files from for javah
+##
+CLASSDIR := $(GWT_ROOT)build/out/dev/linux/bin
+
+# use this instead if you want to use eclipse to build the class files during
+# development
+#CLASSDIR := $(GWT_ROOT)eclipse/dev/linux/bin
+
+##
+# Tools
+##
+CXX := g++
+AR := ar
+STRIP := strip
+LD := $(CXX)
+JAVAH := $(JAVA_HOME)/bin/javah
+
+##
+# List of source, object, and dependency paths plus the path to them
+##
+SRCDIRS := ./:../core/
+VPATH := .:../core
+SRCS := gwt-ll.cpp LowLevelMoz.cpp JsValueMoz.cpp Tracer.cpp \
+ ExternalWrapper.cpp NativeWrapper.cpp JsRootedValue.cpp
+OBJS := $(addprefix $(OBJDIR),$(SRCS:.cpp=.o))
+DEPS := $(addprefix $(OBJDIR),$(SRCS:.cpp=.d))
+
+MOZDIR = $(GWT_TOOLS)/sdk/mozilla-1.7.12
+MOZINC = $(MOZDIR)/include
+MOZLIB = $(MOZDIR)/lib
+
+##
+# Include path configuration
+##
+SYSINCS := \
+ $(JAVA_HOME)/include \
+ $(JAVA_HOME)/include/linux \
+ $(MOZINC) $(MOZINC)/extra
+
+INCS := $(OBJDIR)
+INCS := $(addprefix -I ,$(INCS)) $(addprefix -isystem ,$(SYSINCS))
+
+##
+# Libraries and library path
+##
+LIBS = xpcomglue_s
+LIBPATH = -L$(MOZLIB)
+LIBS := $(addprefix -l,$(LIBS))
+
+# for notes on auto-dependency generation, see
+# http://make.paulandlesley.org/autodep.html
+# -MP obviates the need for sed hackery
+CFLAGS := -ggdb -m32 -Os -fPIC -fno-omit-frame-pointer -fno-strict-aliasing -D_REENTRANT -MMD -MP -Wno-system-headers $(CFLAGS)
+LDFLAGS := -ggdb -m32 -s -fPIC -fno-omit-frame-pointer -fno-strict-aliasing -D_REENTRANT -Wl,-shared-gcc $(LDFLAGS)
+
+#-------------------------------------------------------------------------------
+# Rules
+#-------------------------------------------------------------------------------
+
+##
+# default rule
+##
+all: $(OUT)
+
+# install into prebuilt directory
+install: $(OUT)
+ cp $(OUT) prebuilt/
+
+##
+# Include the dependency rules
+##
+-include $(DEPS)
+
+##
+# javah-generated headers for native methods
+##
+$(OBJDIR)LowLevelMoz.h : $(CLASSDIR)/com/google/gwt/dev/shell/moz/LowLevelMoz.class
+ $(JAVAH) -classpath $(CLASSDIR) -o $(OBJDIR)LowLevelMoz.h com.google.gwt.dev.shell.moz.LowLevelMoz
+
+$(OBJDIR)JsValueMoz.h : $(CLASSDIR)/com/google/gwt/dev/shell/moz/JsValueMoz.class
+ $(JAVAH) -classpath $(CLASSDIR) -o $(OBJDIR)JsValueMoz.h com.google.gwt.dev.shell.moz.JsValueMoz
+
+##
+# Dependency rules for generated headers
+# TODO(jat): autogenerate these and others
+##
+$(OBJDIR)LowLevelMoz.o: $(OBJDIR)LowLevelMoz.h $(JAVA_HOME)/include/jni.h
+$(OBJDIR)JsValueMoz.o: $(OBJDIR)JsValueMoz.h $(JAVA_HOME)/include/jni.h
+
+##
+# Compilation rule for cpp files
+##
+$(OBJDIR)%.o : $(SRCDIR)%.cpp
+ @[ -d $(OBJDIR) ] || mkdir -p $(OBJDIR)
+ $(CXX) -c $(CFLAGS) $(INCS) -o $@ $<
+
+# generate preprocessed output files upon request for debugging
+%.i : $(SRCDIR)%.cpp
+ $(CXX) -E $(CFLAGS) $(INCS) -o $@ $<
+
+%.I : $(SRCDIR)%.cpp
+ $(CXX) -E -dDI $(CFLAGS) $(INCS) -o $@ $<
+
+##
+# Actual output file
+##
+$(OUT): $(OBJS) $(MOZLIB)/libxpcomglue_s.a
+ @[ -d $(OUTDIR) ] || mkdir -p $(OUTDIR)
+ $(LD) -shared $(LDFLAGS) $(LIBPATH) -o $@ $^ $(LIBS)
+ $(STRIP) --strip-unneeded $@
+
+##
+# copy to staging area for hosted-mode development
+##
+staging: $(OUT)
+ @[ -d $(STAGING) ] || mkdir -p $(STAGING)
+ cp $(OUT) $(STAGING)
+
+##
+# Clean rule
+##
+clean:
+ @-rm -rf $(OBJDIR) $(OUT)
diff --git a/jni/linux/NativeWrapper.cpp b/jni/linux/NativeWrapper.cpp
new file mode 100644
index 0000000..38958d0
--- /dev/null
+++ b/jni/linux/NativeWrapper.cpp
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+/*
+ * Defines the JavaScript classes gwt_nativewrapper_class and
+ * gwt_functionwrapper_class, which interface via JNI to Java objects.
+ */
+
+#include <jni.h>
+#include "JsRootedValue.h"
+#include "gwt-jni.h"
+#include "Tracer.h"
+
+/*
+ * Helper function to get reference Java attributes from Javascript.
+ *
+ * cx - JSContext pointer
+ * obj - JavaScript object which is a wrapped Java object
+ * id - property name, as a jsval string
+ * dispClass - output parameter of DispatchMethod subclass
+ * dispObj - output parameter of Java object
+ * jident - output parameter of property name as a Java string
+ */
+static JSBool getJavaPropertyStats(JSContext *cx, JSObject *obj, jsval id,
+ jclass& dispClass, jobject& dispObj, jstring& jident)
+{
+ Tracer tracer("getJavaPropertyStats");
+ if (!JSVAL_IS_STRING(id)) {
+ tracer.setFail("id is not a string");
+ return JS_FALSE;
+ }
+
+ jident = savedJNIEnv->NewString(JS_GetStringChars(JSVAL_TO_STRING(id)),
+ JS_GetStringLength(JSVAL_TO_STRING(id)));
+ if (!jident || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("unable to create Java string");
+ return JS_FALSE;
+ }
+
+ dispObj = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+ if (!dispObj) {
+ tracer.setFail("can't get dispatch object");
+ return JS_FALSE;
+ }
+
+ dispClass = savedJNIEnv->GetObjectClass(dispObj);
+ if (savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("can't get class of dispatch object");
+ return JS_FALSE;
+ }
+
+ return JS_TRUE;
+}
+
+/*
+ * Returns the value of a field on a Java object.
+ *
+ * context - JavaScript context
+ * clazz - class of obj
+ * obj - Java object to retreive field from
+ * fieldName - name of field on Java object to retrieve
+ *
+ * Returns null on failure. Caller is responsible for deleting
+ * returned JsRootedValue when done with it.
+ */
+static JsRootedValue* GetFieldAsRootedValue(JSContext* cx, jclass clazz,
+ jobject obj, jstring fieldName)
+{
+ Tracer tracer("GetFieldAsRootedValue");
+ JsRootedValue::ContextManager context(cx);
+ jmethodID getFieldMeth = savedJNIEnv->GetMethodID(clazz, "getField",
+ "(Ljava/lang/String;I)V");
+ if (!getFieldMeth || savedJNIEnv->ExceptionCheck()) {
+ return 0;
+ }
+
+ JsRootedValue* jsRootedValue = new JsRootedValue();
+ savedJNIEnv->CallVoidMethod(obj, getFieldMeth, fieldName,
+ reinterpret_cast<jint>(jsRootedValue));
+ if (savedJNIEnv->ExceptionCheck()) {
+ delete jsRootedValue;
+ return 0;
+ }
+ return jsRootedValue;
+}
+
+/*
+ * Sets the value of a field on a Java object.
+ *
+ * context - JavaScript context
+ * clazz - class of obj
+ * obj - Java object to store into field
+ * fieldName - name of field on Java object to store into
+ * jsRootedValue - the value to store in the field
+ *
+ * returns true on success, false on failure
+ */
+static bool SetFieldFromRootedValue(JSContext* cx, jclass clazz,
+ jobject obj, jstring fieldName, JsRootedValue* jsRootedValue)
+{
+ Tracer tracer("SetFieldAsRootedValue");
+ JsRootedValue::ContextManager context(cx);
+ jmethodID getFieldMeth = savedJNIEnv->GetMethodID(clazz, "setField",
+ "(Ljava/lang/String;I)V");
+ if (!getFieldMeth || savedJNIEnv->ExceptionCheck()) {
+ return false;
+ }
+
+ savedJNIEnv->CallVoidMethod(obj, getFieldMeth, fieldName,
+ reinterpret_cast<jint>(jsRootedValue));
+ if (savedJNIEnv->ExceptionCheck()) {
+ return false;
+ }
+
+ return true;
+}
+
+static JSBool JS_DLL_CALLBACK gwt_nativewrapper_getProperty(JSContext *cx,
+ JSObject *obj, jsval id, jsval *vp)
+{
+ Tracer tracer("gwt_nativewrapper_getProperty");
+ tracer.log("context=%08x, obj=%08x", unsigned(cx), unsigned(obj));
+ JsRootedValue::ContextManager context(cx);
+
+ jclass dispClass;
+ jobject dispObj;
+ jstring ident;
+ if (!getJavaPropertyStats(cx, obj, id, dispClass, dispObj, ident)) {
+ tracer.setFail("getJavaPropertyStats failed");
+ return JS_FALSE;
+ }
+ JsRootedValue* js_rooted_value = GetFieldAsRootedValue(cx, dispClass,
+ dispObj, ident);
+ if (!js_rooted_value) {
+ tracer.setFail("can't get field");
+ return JS_FALSE;
+ }
+ *vp = js_rooted_value->getValue();
+ return JS_TRUE;
+}
+
+static void JS_DLL_CALLBACK gwt_nativewrapper_finalize(JSContext *cx,
+ JSObject *obj)
+{
+ Tracer tracer("gwt_nativewrapper_finalize");
+ jobject dispObj = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
+ if (dispObj) {
+ // Remove this pairing from the global map.
+ jmethodID removeMethod = savedJNIEnv->GetStaticMethodID(lowLevelMozClass, "removeJsvalForObject",
+ "(Ljava/lang/Object;)V");
+ if (!removeMethod || savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("Cannot GetMethodID for removeJsvalForObject");
+ return;
+ }
+ savedJNIEnv->CallStaticVoidMethod(lowLevelMozClass, removeMethod, dispObj);
+ if (savedJNIEnv->ExceptionCheck()) {
+ tracer.setFail("Exception calling removeJsvalForObject");
+ return;
+ }
+ savedJNIEnv->DeleteGlobalRef(dispObj);
+ }
+}
+
+static JSBool JS_DLL_CALLBACK gwt_nativewrapper_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+ Tracer tracer("gwt_nativewrapper_setProperty");
+ tracer.log("context=%08x", unsigned(cx));
+ JsRootedValue::ContextManager context(cx);
+ jclass dispClass;
+ jobject dispObj;
+ jstring ident;
+ if (!getJavaPropertyStats(cx, obj, id, dispClass, dispObj, ident)) {
+ tracer.setFail("getJavaPropertyStats failed");
+ return JS_FALSE;
+ }
+ JsRootedValue* js_rooted_value = new JsRootedValue(*vp);
+ if (!SetFieldFromRootedValue(cx, dispClass, dispObj, ident,
+ js_rooted_value)) {
+ tracer.setFail("can't set field");
+ return JS_FALSE;
+ }
+ return JS_TRUE;
+}
+
+JSClass gwt_nativewrapper_class = {
+ "gwt_nativewrapper_class", JSCLASS_HAS_PRIVATE,
+ JS_PropertyStub, JS_PropertyStub, gwt_nativewrapper_getProperty,
+ gwt_nativewrapper_setProperty, JS_EnumerateStub, JS_ResolveStub,
+ JS_ConvertStub, gwt_nativewrapper_finalize,
+ JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+JSClass gwt_functionwrapper_class = {
+ "gwt_functionwrapper_class", JSCLASS_HAS_PRIVATE,
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, gwt_nativewrapper_finalize,
+ JSCLASS_NO_OPTIONAL_MEMBERS
+};
diff --git a/jni/linux/Tracer.cpp b/jni/linux/Tracer.cpp
new file mode 100644
index 0000000..e5f3189
--- /dev/null
+++ b/jni/linux/Tracer.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include "Tracer.h"
+
+#ifdef ENABLE_TRACING
+
+// initialize static fields
+FILE* Tracer::outfp = 0;
+JNIEnv* Tracer::jniEnv = 0;
+jclass Tracer::traceClass;
+jmethodID Tracer::traceMethod;
+int Tracer::indentation = 0;
+Tracer::LogLevel Tracer::logLevel = Tracer::LEVEL_WARNING;
+
+/*
+ * Sets a JNI environment and Java class to pass trace messages to.
+ *
+ * env - JNI environment to use for trace calls
+ * clazz - Java class, which must provide static void trace(String)
+ */
+bool Tracer::setJava(JNIEnv* env, jclass clazz) {
+ jniEnv = env;
+ if (!env) {
+ return true;
+ }
+ traceClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+ if (!traceClass || env->ExceptionCheck()) {
+ return false;
+ }
+ traceMethod = env->GetStaticMethodID(traceClass, "trace",
+ "(Ljava/lang/String;)V");
+ if (!traceMethod || env->ExceptionCheck()) {
+ return false;
+ }
+
+ jstring msg = jniEnv->NewStringUTF("== Java trace started ==");
+ jniEnv->CallStaticVoidMethod(traceClass, traceMethod, msg);
+ return true;
+}
+
+#endif // ENABLE_TRACING
+
+/*
+ * Throw a HostedModeException and log a failure message.
+ *
+ * Creates a new HostedModeException with the failure message,
+ * and also logs the failure message
+ *
+ * env - JNI environment to throw the exception in
+ * msg - failure message
+ */
+void Tracer::throwHostedModeException(JNIEnv* env, const char* msg) {
+#ifdef ENABLE_TRACING
+ setFail(msg);
+#endif // ENABLE_TRACING
+ jclass exceptionClass
+ = env->FindClass("com/google/gwt/dev/shell/HostedModeException");
+ env->ThrowNew(exceptionClass, msg);
+}
diff --git a/jni/linux/Tracer.h b/jni/linux/Tracer.h
new file mode 100644
index 0000000..ef9fd7d
--- /dev/null
+++ b/jni/linux/Tracer.h
@@ -0,0 +1,297 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+#ifndef JNI_LINUX_TRACER_H_
+#define JNI_LINUX_TRACER_H_
+
+#include <cstdio>
+#include <cstdarg>
+#include <cstring>
+#include <jni.h>
+
+// comment this out to remove almost all runtime overhead (with usual compiler
+// support) from tracing.
+//#define ENABLE_TRACING
+
+/*
+ * Utility class for tracing. This class is intended to be used as follows:
+ *
+ * {
+ * Tracer tracer("method name");
+ * ... do work
+ * if (fail) {
+ * tracer.setFail("failure explanation");
+ * return;
+ * }
+ * if (fail2) {
+ * tracer.throwHostedModeException("failure explanation");
+ * return;
+ * }
+ * return;
+ * }
+ *
+ * The class automatically logs an enter message when it is created, as well
+ * as leave/fail messages when it is destroyed. Logging is performed to a
+ * file or to a Java static member function on a class (or both) -- these
+ * are configured by using static member functions setFile() and setJava().
+ *
+ * This class knows about the Java class
+ * com.google.gwt.dev.shell.HostedModeException
+ * and throws a new instance of that exception if requested.
+ */
+class Tracer {
+public:
+ enum LogLevel {
+ LEVEL_ERROR = 0,
+ LEVEL_WARNING,
+ LEVEL_NOTICE,
+ LEVEL_INFO,
+ LEVEL_DEBUG,
+ LEVEL_DEBUG_V1,
+ LEVEL_DEBUG_V2,
+ };
+protected:
+#ifdef ENABLE_TRACING
+ // static variables that specify where logging is performed. This are
+ // set by calling setFile() and setJava().
+ static FILE* outfp;
+ static JNIEnv* jniEnv;
+ static jclass traceClass;
+ static jmethodID traceMethod;
+ static int indentation;
+ static LogLevel logLevel;
+
+ // method is set when the instance is created.
+ const char* method_;
+ // fail_msg is set to indicate a failure has occurred.
+ const char* fail_msg_;
+ // level of this trace object
+ LogLevel log_level_;
+#endif
+
+public:
+ /*
+ * Set the logging level.
+ */
+ static void setLevel(LogLevel level) {
+#ifdef ENABLE_TRACING
+ logLevel = level;
+#endif
+ }
+
+protected:
+ /*
+ * Log a message (with supplied prefix) to the configured file.
+ * Only called if a file was specified and successfully opened for writing.
+ */
+ static void logFile(const char* msg) {
+#ifdef ENABLE_TRACING
+ for (int i = 0; i < indentation; ++i) {
+ putc(' ', outfp);
+ }
+ fputs(msg, outfp);
+ putc('\n', outfp);
+ fflush(outfp);
+#else
+ (void)msg; // avoid unused warning
+#endif
+ }
+
+ /*
+ * Log a message (with supplied prefix) to the configured Java class.
+ * Only called if a file was specified and successfully accessed.
+ *
+ * Call static void trace(String msg) on the configured class.
+ */
+ static void logJava(const char* msg) {
+#ifdef ENABLE_TRACING
+ // TODO(jat): fixed buffer size
+ char buf[512];
+ for (int i = 0; (i < indentation) && (i < int(sizeof(buf))); ++i) {
+ buf[i] = ' ';
+ }
+ strncpy(buf + indentation, msg, sizeof(buf) - indentation);
+ buf[sizeof(buf) - 1] = 0; // ensure null termination
+ jstring str = jniEnv->NewStringUTF(buf);
+ jniEnv->CallStaticVoidMethod(traceClass, traceMethod, str);
+#else
+ (void)msg; // avoid unused warning
+#endif
+ }
+
+ /*
+ * Log a message to a file and/or class with the default logging level.
+ *
+ * If the preprocessor symbol DISABLE_TRACING has been defined, this is
+ * completely removed from the code path.
+ */
+ void logPrefix(const char* prefix) {
+#ifdef ENABLE_TRACING
+ logPrefix(prefix, log_level_);
+#else
+ (void)prefix; // avoid unused warning
+#endif
+ }
+
+ /*
+ * Log a message to a file and/or class.
+ *
+ * If the preprocessor symbol DISABLE_TRACING has been defined, this is
+ * completely removed from the code path.
+ */
+ void logPrefix(const char* prefix, LogLevel level) {
+#ifdef ENABLE_TRACING
+ if (level>logLevel) return;
+ log("%-5.5s %s%s%s", prefix, method_, fail_msg_ ? ": " : "",
+ fail_msg_ ? fail_msg_ : "");
+#endif
+ }
+
+public:
+ /*
+ * Create an instance with the specified method name and no failure
+ * message. Log an ENTER message.
+ */
+ Tracer(const char* method, LogLevel log_level = LEVEL_ERROR)
+#ifdef ENABLE_TRACING
+ : method_(method), fail_msg_(0), log_level_(log_level) {
+ log("ENTER %s", method);
+ indentation++;
+#else
+ { (void)method; (void)log_level; // avoid unused warnings
+#endif
+ }
+
+ /*
+ * Create an instance with the specified method name and no failure
+ * message. Log an ENTER message and the this pointer.
+ */
+ Tracer(const char* method, const void* objThis,
+ LogLevel log_level = LEVEL_ERROR)
+#ifdef ENABLE_TRACING
+ : method_(method), fail_msg_(0), log_level_(log_level) {
+ log("ENTER %s(this=%08x)", method, unsigned(objThis));
+ indentation++;
+#else
+ { (void)method; (void)objThis; (void)log_level; // avoid unused warnings
+#endif
+ }
+
+ /*
+ * Destroy the instance and log a fail or leave message.
+ */
+ ~Tracer() {
+#ifdef ENABLE_TRACING
+ --indentation;
+ if(fail_msg_) {
+ logPrefix("*FAIL", LEVEL_ERROR);
+ } else {
+ logPrefix("LEAVE");
+ }
+#endif
+ }
+
+ /*
+ * Specify a filename to receive logging output. Close any previously
+ * opened file. If a null filename is passed, disable logging to a
+ * file.
+ *
+ * filename - the file path to receive logging output. This file is
+ * truncated if it already exists.
+ *
+ * Returns false on failure.
+ */
+ static bool setFile(const char* filename) {
+#ifdef ENABLE_TRACING
+ if (outfp) {
+ fclose(outfp);
+ outfp = 0;
+ }
+ if (!filename) {
+ return true;
+ }
+ outfp = fopen(filename, "w");
+ if (!outfp) {
+ return false;
+ }
+ fprintf(outfp, "== started logging ==\n");
+ fflush(outfp);
+#else
+ (void)filename; // avoid unused warning
+#endif
+ return true;
+ }
+
+ /*
+ * Specify a Java class to receive logging output. The supplied class
+ * must have a static void trace(String) member function which is called
+ * for output. Logging to a Java class is disabled if the supplied JNI
+ * environment is null.
+ *
+ * env - JNI environment
+ * clazz - the Java class to receive logging output
+ *
+ * Returns false on failure.
+ */
+ static bool setJava(JNIEnv* env, jclass clazz)
+#ifdef ENABLE_TRACING
+ ;
+#else
+ // inline a null body if we aren't debugging; avoid unused warnings
+ { (void)env; (void)clazz; return true; }
+#endif
+
+ /*
+ * Set a failure message, overwriting any previously specified failure
+ * message. Passing a null string will remove any previous failure
+ * notification.
+ */
+ void setFail(const char* fail_msg) {
+#ifdef ENABLE_TRACING
+ fail_msg_ = fail_msg;
+#else
+ (void)fail_msg; // avoid unused warning
+#endif
+ }
+
+ /*
+ * Throw a Java HostedModeException as well as set a failure message to
+ * be logged.
+ *
+ * env - JNI environment to throw exception into
+ * fail_msg - failure message
+ */
+ void throwHostedModeException(JNIEnv* env, const char* fail_msg);
+
+ /*
+ * Log an arbitrary message.
+ */
+ static void log(const char* format, ...) {
+#ifdef ENABLE_TRACING
+ va_list args;
+ va_start(args, format);
+ char msg[512]; // TODO(jat): fixed size buffer
+ vsnprintf(msg, sizeof(msg), format, args);
+ msg[sizeof(msg) - 1] = 0; // ensure null termination
+ if(outfp) logFile(msg);
+ if(jniEnv) logJava(msg);
+ va_end(args);
+#else
+ (void)format; // avoid unused warning
+#endif
+ }
+};
+
+#endif /* JNI_LINUX_TRACER_H_ */
diff --git a/jni/linux/build.xml b/jni/linux/build.xml
new file mode 100755
index 0000000..5f0db6b
--- /dev/null
+++ b/jni/linux/build.xml
@@ -0,0 +1,18 @@
+<project name="jni-linux" default="build" basedir=".">
+ <property name="gwt.root" location="../.." />
+ <property name="project.tail" value="jni/linux" />
+ <import file="${gwt.root}/common.ant.xml" />
+
+ <target name="build" description="Builds a JNI lib">
+ <mkdir dir="${project.jni}" />
+ <!-- TODO: Actually build this from source! -->
+ <copy todir="${project.jni}">
+ <fileset dir="prebuilt" />
+ </copy>
+ </target>
+
+ <target name="clean" description="Cleans this project's intermediate and output files">
+ <delete dir="${project.build}" failonerror="false" />
+ <delete dir="${project.jni}" failonerror="false" />
+ </target>
+</project>
diff --git a/jni/linux/gwt-jni.h b/jni/linux/gwt-jni.h
new file mode 100644
index 0000000..c477f1c
--- /dev/null
+++ b/jni/linux/gwt-jni.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+#ifndef JNI_LINUX_GWT_JNI_H_
+#define JNI_LINUX_GWT_JNI_H_
+
+#include <jni.h>
+#include "JsRootedValue.h"
+#include "JStringWrap.h"
+
+extern JNIEnv* savedJNIEnv;
+extern jclass lowLevelMozClass;
+
+extern nsCID kGwtExternalCID;
+
+// JavaScript class objects
+extern JSClass gwt_nativewrapper_class;
+extern JSClass gwt_functionwrapper_class;
+
+#endif /*JNI_LINUX_GWT_JNI_H_*/
diff --git a/jni/linux/mozilla-headers.h b/jni/linux/mozilla-headers.h
new file mode 100644
index 0000000..6259b41
--- /dev/null
+++ b/jni/linux/mozilla-headers.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+// include all of the necessary Mozilla headers.
+#include "mozilla-config.h"
+#include "nsIServiceManagerUtils.h"
+#include "nsComponentManagerUtils.h"
+#include "nsICategoryManager.h"
+#include "nsIScriptNameSpaceManager.h"
+#include "nsIScriptObjectOwner.h"
+#include "nsIScriptGlobalObject.h"
+#include "nsIScriptContext.h"
+#include "nsIDOMWindow.h"
+#include "nsIXPConnect.h"
+#include "nsIFactory.h"
+#include "nsCOMPtr.h"
+#include "nsAutoPtr.h"
diff --git a/jni/linux/prebuilt/libgwt-ll.so b/jni/linux/prebuilt/libgwt-ll.so
new file mode 100755
index 0000000..97ead651
--- /dev/null
+++ b/jni/linux/prebuilt/libgwt-ll.so
Binary files differ