|  | /* | 
|  | * 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; | 
|  | } |