Propagating fixes from SpiderMonkey140_BRANCH

This commit is contained in:
fur%netscape.com 1999-08-29 16:54:24 +00:00
Родитель 10855247b5
Коммит 7f0a6e786b
13 изменённых файлов: 526 добавлений и 281 удалений

Просмотреть файл

@ -466,7 +466,7 @@ JSJ_ConnectToJavaVM(SystemJavaVM *java_vm_arg, void* initargs)
thread_list_monitor =
(struct PRMonitor *) PR_NewMonitor();
}
#endif JSJ_THREADSAFE
#endif /* JSJ_THREADSAFE */
/* Put this VM on the list of all created VMs */
jsjava_vm->next = jsjava_vm_list;
@ -580,7 +580,7 @@ JSJ_DisconnectFromJavaVM(JSJavaVM *jsjava_vm)
PR_DestroyMonitor(thread_list_monitor);
thread_list_monitor = NULL;
}
#endif JSJ_THREADSAFE
#endif /* JSJ_THREADSAFE */
free(jsjava_vm);
}
@ -600,14 +600,14 @@ new_jsjava_thread_state(JSJavaVM *jsjava_vm, const char *thread_name, JNIEnv *jE
if (thread_name)
jsj_env->name = strdup(thread_name);
#ifdef JSJ_THREAD_SAFE
#ifdef JSJ_THREADSAFE
PR_EnterMonitor(thread_list_monitor);
#endif
jsj_env->next = thread_list;
thread_list = jsj_env;
#ifdef JSJ_THREAD_SAFE
#ifdef JSJ_THREADSAFE
PR_ExitMonitor(thread_list_monitor);
#endif
@ -620,6 +620,10 @@ find_jsjava_thread(JNIEnv *jEnv)
JSJavaThreadState *e, **p, *jsj_env;
jsj_env = NULL;
#ifdef JSJ_THREADSAFE
PR_EnterMonitor(thread_list_monitor);
#endif
/* Search for the thread state among the list of all created
LiveConnect threads */
for (p = &thread_list; (e = *p) != NULL; p = &(e->next)) {
@ -631,19 +635,15 @@ find_jsjava_thread(JNIEnv *jEnv)
/* Move a found thread to head of list for faster search next time. */
if (jsj_env && p != &thread_list) {
#ifdef JSJ_THREAD_SAFE
PR_EnterMonitor(thread_list_monitor);
#endif
/* First, check to make sure list hasn't mutated since we searched */
if (*p == jsj_env) {
*p = jsj_env->next;
thread_list = jsj_env;
}
#ifdef JSJ_THREAD_SAFE
PR_ExitMonitor(thread_list_monitor);
#endif
*p = jsj_env->next;
jsj_env->next = thread_list;
thread_list = jsj_env;
}
#ifdef JSJ_THREADSAFE
PR_ExitMonitor(thread_list_monitor);
#endif
return jsj_env;
}
@ -744,6 +744,9 @@ JSJ_SetDefaultJSContextForJavaThread(JSContext *cx, JSJavaThreadState *jsj_env)
JSContext *old_context;
old_context = jsj_env->cx;
jsj_env->cx = cx;
/* The following line prevents clearing of jsj_env->cx by jsj_ExitJava() */
jsj_env->recursion_depth++;
return old_context;
}
@ -757,15 +760,22 @@ JSJ_DetachCurrentThreadFromJava(JSJavaThreadState *jsj_env)
/* Disassociate the current native thread from its corresponding Java thread */
java_vm = jsj_env->jsjava_vm->java_vm;
jEnv = jsj_env->jEnv;
if (!JSJ_callbacks->detach_current_thread(java_vm, jEnv))
return JS_FALSE;
/* Destroy the LiveConnect execution environment passed in */
jsj_ClearPendingJSErrors(jsj_env);
#ifdef JSJ_THREADSAFE
PR_EnterMonitor(thread_list_monitor);
#endif JSJ_THREADSAFE
#endif /* JSJ_THREADSAFE */
if (!JSJ_callbacks->detach_current_thread(java_vm, jEnv)) {
#ifdef JSJ_THREADSAFE
PR_ExitMonitor(thread_list_monitor);
#endif /* JSJ_THREADSAFE */
return JS_FALSE;
}
/* Destroy the LiveConnect execution environment passed in */
jsj_ClearPendingJSErrors(jsj_env);
for (p = &thread_list; (e = *p) != NULL; p = &(e->next)) {
if (e == jsj_env) {
@ -774,9 +784,11 @@ JSJ_DetachCurrentThreadFromJava(JSJavaThreadState *jsj_env)
}
}
JS_ASSERT(e);
#ifdef JSJ_THREADSAFE
PR_ExitMonitor(thread_list_monitor);
#endif JSJ_THREADSAFE
#endif /* JSJ_THREADSAFE */
free(jsj_env);
return JS_TRUE;
@ -788,13 +800,17 @@ JSBool
JSJ_ConvertJavaObjectToJSValue(JSContext *cx, jobject java_obj, jsval *vp)
{
JNIEnv *jEnv;
JSBool result;
JSJavaThreadState *jsj_env;
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
return jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_obj, vp);
result = jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_obj, vp);
jsj_ExitJava(jsj_env);
return result;
}

Просмотреть файл

@ -244,7 +244,7 @@ jsj_WrapJSObject(JSContext *cx, JNIEnv *jEnv, JSObject *js_obj)
if (!handle)
return NULL;
handle->js_obj = js_obj;
handle->cx = cx;
handle->rt = JS_GetRuntime(cx);
/* Create a new Java object that wraps the JavaScript object by storing its
address in a private integer field. */
@ -366,7 +366,7 @@ capture_js_error_reports_for_java(JSContext *cx, const char *message,
}
/* Get the head of the list of pending JS errors */
jsj_env = jsj_MapJSContextToJSJThread(cx, &jEnv);
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jsj_env)
goto abort;
@ -383,6 +383,7 @@ capture_js_error_reports_for_java(JSContext *cx, const char *message,
/* Push this error onto the list of pending JS errors */
new_error->next = jsj_env->pending_js_errors;
jsj_env->pending_js_errors = new_error;
jsj_ExitJava(jsj_env);
return;
abort:
@ -682,10 +683,6 @@ jsj_enter_js(JNIEnv *jEnv, void* applet_obj, jobject java_wrapper_obj,
if (!jsj_env)
goto error;
/* If a JSContext was passed by caller, use it. */
if (jsj_env->cx == NULL)
jsj_env->cx = *cxp;
/* Get the JSContext that we're supposed to use for this Java thread */
cx = jsj_env->cx;
if (!cx) {
@ -693,7 +690,14 @@ jsj_enter_js(JNIEnv *jEnv, void* applet_obj, jobject java_wrapper_obj,
Java and back into JS. Invoke a callback to obtain/create a
JSContext for us to use. */
if (JSJ_callbacks->map_jsj_thread_to_js_context) {
cx = JSJ_callbacks->map_jsj_thread_to_js_context(jsj_env, applet_obj, jEnv, &err_msg);
#ifdef OJI
cx = JSJ_callbacks->map_jsj_thread_to_js_context(jsj_env,
applet_obj,
jEnv, &err_msg);
#else
cx = JSJ_callbacks->map_jsj_thread_to_js_context(jsj_env,
jEnv, &err_msg);
#endif
if (!cx)
goto error;
} else {
@ -704,7 +708,6 @@ jsj_enter_js(JNIEnv *jEnv, void* applet_obj, jobject java_wrapper_obj,
jsj_env->cx = cx;
}
*cxp = cx;
jsj_env->recursion_depth++;
/*
* Capture all JS error reports so that they can be thrown into the Java
@ -713,6 +716,10 @@ jsj_enter_js(JNIEnv *jEnv, void* applet_obj, jobject java_wrapper_obj,
*old_error_reporterp =
JS_SetErrorReporter(cx, capture_js_error_reports_for_java);
#ifdef JSJ_THREADSAFE
JS_BeginRequest(cx);
#endif
return jsj_env;
error:
@ -740,6 +747,10 @@ jsj_exit_js(JSContext *cx, JSJavaThreadState *jsj_env, JSErrorReporter original_
{
JNIEnv *jEnv;
#ifdef JSJ_THREADSAFE
JS_EndRequest(cx);
#endif
/* Restore the JS error reporter */
JS_SetErrorReporter(cx, original_reporter);
@ -765,9 +776,6 @@ jsj_exit_js(JSContext *cx, JSJavaThreadState *jsj_env, JSErrorReporter original_
if (JSJ_callbacks->exit_js)
JSJ_callbacks->exit_js(jEnv);
jsj_env->recursion_depth--;
if (!jsj_env->recursion_depth)
jsj_env->cx = NULL;
return JS_TRUE;
}
@ -811,7 +819,7 @@ Java_netscape_javascript_JSObject_getMember(JNIEnv *jEnv,
jobject java_wrapper_obj,
jstring property_name_jstr)
{
JSContext *cx;
JSContext *cx = NULL;
JSObject *js_obj;
jsval js_val;
int dummy_cost;
@ -869,7 +877,7 @@ Java_netscape_javascript_JSObject_getSlot(JNIEnv *jEnv,
jobject java_wrapper_obj,
jint slot)
{
JSContext *cx;
JSContext *cx = NULL;
JSObject *js_obj;
jsval js_val;
int dummy_cost;
@ -907,7 +915,7 @@ Java_netscape_javascript_JSObject_setMember(JNIEnv *jEnv,
jstring property_name_jstr,
jobject java_obj)
{
JSContext *cx;
JSContext *cx = NULL;
JSObject *js_obj;
jsval js_val;
const jchar *property_name_ucs2;
@ -957,7 +965,7 @@ Java_netscape_javascript_JSObject_setSlot(JNIEnv *jEnv,
jint slot,
jobject java_obj)
{
JSContext *cx;
JSContext *cx = NULL;
JSObject *js_obj;
jsval js_val;
JSErrorReporter saved_reporter;
@ -985,7 +993,7 @@ Java_netscape_javascript_JSObject_removeMember(JNIEnv *jEnv,
jobject java_wrapper_obj,
jstring property_name_jstr)
{
JSContext *cx;
JSContext *cx = NULL;
JSObject *js_obj;
jsval js_val;
const jchar *property_name_ucs2;
@ -1031,7 +1039,7 @@ Java_netscape_javascript_JSObject_call(JNIEnv *jEnv, jobject java_wrapper_obj,
{
int i, argc, arg_num;
jsval *argv;
JSContext *cx;
JSContext *cx = NULL;
JSObject *js_obj;
jsval js_val, function_val;
int dummy_cost;
@ -1119,7 +1127,7 @@ Java_netscape_javascript_JSObject_eval(JNIEnv *jEnv,
{
const char *codebase;
JSPrincipals *principals;
JSContext *cx;
JSContext *cx = NULL;
JSBool eval_succeeded;
JSObject *js_obj;
jsval js_val;
@ -1188,7 +1196,7 @@ Java_netscape_javascript_JSObject_toString(JNIEnv *jEnv,
jobject java_wrapper_obj)
{
jstring result;
JSContext *cx;
JSContext *cx = NULL;
JSObject *js_obj;
JSString *jsstr;
JSErrorReporter saved_reporter;
@ -1222,7 +1230,7 @@ Java_netscape_javascript_JSObject_getWindow(JNIEnv *jEnv,
jobject java_applet_obj)
{
char *err_msg;
JSContext *cx;
JSContext *cx = NULL;
JSObject *js_obj;
jsval js_val;
int dummy_cost;
@ -1264,19 +1272,17 @@ JNIEXPORT void JNICALL
Java_netscape_javascript_JSObject_finalize(JNIEnv *jEnv, jobject java_wrapper_obj)
{
JSBool success;
JSContext *cx;
JSObjectHandle *handle;
success = JS_FALSE;
handle = (JSObjectHandle *)((*jEnv)->GetIntField(jEnv, java_wrapper_obj, njJSObject_internal));
JS_ASSERT(handle);
if (!handle)
return;
cx = handle->cx;
success = JS_RemoveRoot(cx, &handle->js_obj);
JS_free(cx, handle);
success = JS_RemoveRootRT(handle->rt, &handle->js_obj);
free(handle);
JS_ASSERT(success);
}

Просмотреть файл

@ -94,7 +94,8 @@ access_java_array_element(JSContext *cx,
if (JS_IdToValue(cx, id, &idval) && JSVAL_IS_STRING(idval) &&
(property_name = JS_GetStringBytes(JSVAL_TO_STRING(idval))) != NULL) {
if (!strcmp(property_name, "constructor")) {
*vp = JSVAL_VOID;
if (vp)
*vp = JSVAL_VOID;
return JS_TRUE;
}
}
@ -132,7 +133,8 @@ access_java_array_element(JSContext *cx,
JSJMSG_CANT_WRITE_JARRAY, member_name);
return JS_FALSE;
} else {
*vp = JSVAL_VOID;
if (vp)
*vp = JSVAL_VOID;
return JS_TRUE;
}
} else {
@ -190,20 +192,30 @@ JS_STATIC_DLL_CALLBACK(JSBool)
JavaArray_getPropertyById(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
JNIEnv *jEnv;
jsj_MapJSContextToJSJThread(cx, &jEnv);
JSJavaThreadState *jsj_env;
JSBool result;
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
return access_java_array_element(cx, jEnv, obj, id, vp, JS_FALSE);
result = access_java_array_element(cx, jEnv, obj, id, vp, JS_FALSE);
jsj_ExitJava(jsj_env);
return result;
}
JS_STATIC_DLL_CALLBACK(JSBool)
JavaArray_setPropertyById(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
JNIEnv *jEnv;
jsj_MapJSContextToJSJThread(cx, &jEnv);
JSJavaThreadState *jsj_env;
JSBool result;
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
return access_java_array_element(cx, jEnv, obj, id, vp, JS_TRUE);
result = access_java_array_element(cx, jEnv, obj, id, vp, JS_TRUE);
jsj_ExitJava(jsj_env);
return result;
}
static JSBool
@ -217,13 +229,16 @@ JavaArray_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
JNIEnv *jEnv;
JSBool result;
JSErrorReporter old_reporter;
jsj_MapJSContextToJSJThread(cx, &jEnv);
JSJavaThreadState *jsj_env;
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
old_reporter = JS_SetErrorReporter(cx, NULL);
result = access_java_array_element(cx, jEnv, obj, id, NULL, JS_FALSE);
JS_SetErrorReporter(cx, old_reporter);
jsj_ExitJava(jsj_env);
return result;
}
@ -232,9 +247,13 @@ JavaArray_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
JSPropertyOp getter, JSPropertyOp setter,
uintN attrs, JSProperty **propp)
{
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
JSJMSG_JARRAY_PROP_DEFINE);
return JS_FALSE;
jsval *vp = &value;
if (propp)
return JS_FALSE;
if (attrs & ~(JSPROP_PERMANENT|JSPROP_ENUMERATE))
return JS_FALSE;
return JavaArray_setPropertyById(cx, obj, id, vp);
}
static JSBool
@ -290,6 +309,7 @@ JavaArray_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
jsval *statep, jsid *idp)
{
JavaObjectWrapper *java_wrapper;
JSJavaThreadState *jsj_env;
JNIEnv *jEnv;
jsize array_length, index;
@ -303,13 +323,15 @@ JavaArray_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
}
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
array_length = jsj_GetJavaArrayLength(cx, jEnv, java_wrapper->java_obj);
if (array_length < 0)
if (array_length < 0) {
jsj_ExitJava(jsj_env);
return JS_FALSE;
}
switch(enum_op) {
case JSENUMERATE_INIT:
@ -317,6 +339,7 @@ JavaArray_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
if (idp)
*idp = INT_TO_JSVAL(array_length);
jsj_ExitJava(jsj_env);
return JS_TRUE;
case JSENUMERATE_NEXT:
@ -332,10 +355,12 @@ JavaArray_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
case JSENUMERATE_DESTROY:
*statep = JSVAL_NULL;
jsj_ExitJava(jsj_env);
return JS_TRUE;
default:
JS_ASSERT(0);
jsj_ExitJava(jsj_env);
return JS_FALSE;
}
}

Просмотреть файл

@ -148,18 +148,23 @@ JavaClass_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
JavaClassDescriptor *class_descriptor;
JavaMemberDescriptor *member_descriptor;
JNIEnv *jEnv;
JSJavaThreadState *jsj_env;
JSBool result;
/* printf("In JavaClass_getProperty\n"); */
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
if (!lookup_static_member_by_id(cx, jEnv, obj, &class_descriptor, id, &member_descriptor))
if (!lookup_static_member_by_id(cx, jEnv, obj, &class_descriptor, id, &member_descriptor)) {
jsj_ExitJava(jsj_env);
return JS_FALSE;
}
if (!member_descriptor) {
*vp = JSVAL_VOID;
jsj_ExitJava(jsj_env);
return JS_TRUE;
}
@ -167,7 +172,9 @@ JavaClass_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
if (member_descriptor->field) {
if (!member_descriptor->methods) {
return jsj_GetJavaFieldValue(cx, jEnv, member_descriptor->field, java_class, vp);
result = jsj_GetJavaFieldValue(cx, jEnv, member_descriptor->field, java_class, vp);
jsj_ExitJava(jsj_env);
return result;
} else {
JS_ASSERT(0);
}
@ -189,11 +196,15 @@ JavaClass_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
}
function = JS_NewFunction(cx, jsj_JavaStaticMethodWrapper, 0,
JSFUN_BOUND_METHOD, obj, member_name);
if (!function)
if (!function) {
jsj_ExitJava(jsj_env);
return JS_FALSE;
}
*vp = OBJECT_TO_JSVAL(JS_GetFunctionObject(function));
}
jsj_ExitJava(jsj_env);
return JS_TRUE;
}
@ -206,16 +217,20 @@ JavaClass_setPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
JavaMemberDescriptor *member_descriptor;
jsval idval;
JNIEnv *jEnv;
JSJavaThreadState *jsj_env;
JSBool result;
/* printf("In JavaClass_setProperty\n"); */
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
if (!lookup_static_member_by_id(cx, jEnv, obj, &class_descriptor, id, &member_descriptor))
if (!lookup_static_member_by_id(cx, jEnv, obj, &class_descriptor, id, &member_descriptor)) {
jsj_ExitJava(jsj_env);
return JS_FALSE;
}
/* Check for the case where there is a method with the given name, but no field
with that name */
@ -223,11 +238,15 @@ JavaClass_setPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
goto no_such_field;
/* Silently fail if field value is final (immutable), as required by ECMA spec */
if (member_descriptor->field->modifiers & ACC_FINAL)
if (member_descriptor->field->modifiers & ACC_FINAL) {
jsj_ExitJava(jsj_env);
return JS_TRUE;
}
java_class = class_descriptor->java_class;
return jsj_SetJavaFieldValue(cx, jEnv, member_descriptor->field, java_class, *vp);
result = jsj_SetJavaFieldValue(cx, jEnv, member_descriptor->field, java_class, *vp);
jsj_ExitJava(jsj_env);
return result;
no_such_field:
JS_IdToValue(cx, id, &idval);
@ -235,6 +254,7 @@ no_such_field:
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
JSJMSG_MISSING_STATIC,
member_name, class_descriptor->name);
jsj_ExitJava(jsj_env);
return JS_FALSE;
}
@ -245,18 +265,20 @@ JS_STATIC_DLL_CALLBACK(void)
JavaClass_finalize(JSContext *cx, JSObject *obj)
{
JNIEnv *jEnv;
JSJavaThreadState *jsj_env;
JavaClassDescriptor *class_descriptor = JS_GetPrivate(cx, obj);
if (!class_descriptor)
return;
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return;
/* printf("Finalizing %s\n", class_descriptor->name); */
jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor);
jsj_ExitJava(jsj_env);
}
@ -270,11 +292,12 @@ JavaClass_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
{
JNIEnv *jEnv;
JSErrorReporter old_reporter;
JSJavaThreadState *jsj_env;
/* printf("In JavaClass_lookupProperty()\n"); */
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
@ -288,6 +311,7 @@ JavaClass_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
}
JS_SetErrorReporter(cx, old_reporter);
jsj_ExitJava(jsj_env);
return JS_TRUE;
}
@ -364,6 +388,7 @@ JavaClass_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
JavaMemberDescriptor *member_descriptor;
JavaClassDescriptor *class_descriptor;
JNIEnv *jEnv;
JSJavaThreadState *jsj_env;
class_descriptor = JS_GetPrivate(cx, obj);
@ -378,13 +403,14 @@ JavaClass_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
switch(enum_op) {
case JSENUMERATE_INIT:
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
member_descriptor = jsj_GetClassStaticMembers(cx, jEnv, class_descriptor);
*statep = PRIVATE_TO_JSVAL(member_descriptor);
if (idp)
*idp = INT_TO_JSVAL(class_descriptor->num_instance_members);
jsj_ExitJava(jsj_env);
return JS_TRUE;
case JSENUMERATE_NEXT:
@ -453,6 +479,7 @@ JavaClass_hasInstance(JSContext *cx, JSObject *obj, jsval candidate_jsval,
jclass java_class;
jobject java_obj;
JNIEnv *jEnv;
JSJavaThreadState *jsj_env;
has_instance = JS_FALSE;
class_descriptor = JS_GetPrivate(cx, obj);
@ -486,8 +513,9 @@ JavaClass_hasInstance(JSContext *cx, JSObject *obj, jsval candidate_jsval,
}
java_obj = java_wrapper->java_obj;
/* Get JNI pointer */
jsj_MapJSContextToJSJThread(cx, &jEnv);
jsj_env = jsj_EnterJava(cx, &jEnv);
has_instance = (*jEnv)->IsInstanceOf(jEnv, java_obj, java_class);
jsj_ExitJava(jsj_env);
done:
*has_instancep = has_instance;
@ -589,10 +617,7 @@ getClass(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
JavaObjectWrapper *java_wrapper;
JavaClassDescriptor *class_descriptor;
JNIEnv *jEnv;
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
JSJavaThreadState *jsj_env;
if (argc != 1 ||
!JSVAL_IS_OBJECT(argv[0]) ||
@ -611,12 +636,20 @@ getClass(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
return JS_FALSE;
}
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
class_descriptor = java_wrapper->class_descriptor;
JavaClass_obj = jsj_new_JavaClass(cx, jEnv, NULL, class_descriptor);
if (!JavaClass_obj)
if (!JavaClass_obj) {
jsj_ExitJava(jsj_env);
return JS_FALSE;
}
*rval = OBJECT_TO_JSVAL(JavaClass_obj);
jsj_ExitJava(jsj_env);
return JS_TRUE;
}
@ -627,10 +660,7 @@ JavaClass_construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval
JavaObjectWrapper *java_wrapper;
JavaClassDescriptor *class_descriptor;
JNIEnv *jEnv;
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
JSJavaThreadState *jsj_env;
if (argc != 1 ||
!JSVAL_IS_OBJECT(argv[0]) ||
@ -642,18 +672,27 @@ JavaClass_construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval
return JS_FALSE;
}
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
class_descriptor = java_wrapper->class_descriptor;
if (!(*jEnv)->IsSameObject(jEnv, class_descriptor->java_class, jlClass)) {
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
JSJMSG_NEED_JCLASS_ARG);
jsj_ExitJava(jsj_env);
return JS_FALSE;
}
class_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, java_wrapper->java_obj);
JavaClass_obj = jsj_new_JavaClass(cx, jEnv, NULL, class_descriptor);
if (!JavaClass_obj)
if (!JavaClass_obj) {
jsj_ExitJava(jsj_env);
return JS_FALSE;
}
*rval = OBJECT_TO_JSVAL(JavaClass_obj);
jsj_ExitJava(jsj_env);
return JS_TRUE;
}

Просмотреть файл

@ -62,16 +62,11 @@ static void
JavaMember_finalize(JSContext *cx, JSObject *obj)
{
JavaMethodOrFieldValue *member_val;
JNIEnv *jEnv;
member_val = JS_GetPrivate(cx, obj);
if (!member_val)
return;
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return;
JS_RemoveRoot(cx, &member_val->method_val);
if (JSVAL_IS_GCTHING(member_val->method_val))
JS_RemoveRoot(cx, &member_val->method_val);

Просмотреть файл

@ -54,6 +54,7 @@ static JSJHashTable *java_obj_reflections = NULL;
#ifdef JSJ_THREADSAFE
static PRMonitor *java_obj_reflections_monitor = NULL;
static int java_obj_reflections_mutation_count = 0;
#endif
JSBool
@ -63,7 +64,7 @@ jsj_InitJavaObjReflectionsTable(void)
java_obj_reflections =
JSJ_NewHashTable(512, jsj_HashJavaObject, jsj_JavaObjectComparator,
jsj_JavaObjectComparator, NULL, NULL);
NULL, NULL, NULL);
if (!java_obj_reflections)
return JS_FALSE;
@ -92,6 +93,10 @@ jsj_WrapJavaObject(JSContext *cx,
JavaClassDescriptor *class_descriptor;
JSJHashEntry *he, **hep;
#ifdef JSJ_THREADSAFE
int mutation_count;
#endif
js_wrapper_obj = NULL;
hash_code = jsj_HashJavaObject((void*)java_obj, (void*)jEnv);
@ -103,16 +108,26 @@ jsj_WrapJavaObject(JSContext *cx,
hep = JSJ_HashTableRawLookup(java_obj_reflections,
hash_code, java_obj, (void*)jEnv);
he = *hep;
#ifdef JSJ_THREADSAFE
/* Track mutations to hash table */
mutation_count = java_obj_reflections_mutation_count;
/* We must temporarily release this monitor so as to avoid
deadlocks with the JS GC. See Bugsplat #354852 */
PR_ExitMonitor(java_obj_reflections_monitor);
#endif
if (he) {
js_wrapper_obj = (JSObject *)he->value;
if (js_wrapper_obj)
goto done;
return js_wrapper_obj;
}
/* No existing reflection found. Construct a new one */
class_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, java_class);
if (!class_descriptor)
goto done;
return NULL;
if (class_descriptor->type == JAVA_SIGNATURE_ARRAY) {
js_class = &JavaArray_class;
} else {
@ -123,17 +138,40 @@ jsj_WrapJavaObject(JSContext *cx,
/* Create new JS object to reflect Java object */
js_wrapper_obj = JS_NewObject(cx, js_class, NULL, NULL);
if (!js_wrapper_obj)
goto done;
return NULL;
/* Create private, native portion of JavaObject */
java_wrapper =
(JavaObjectWrapper *)JS_malloc(cx, sizeof(JavaObjectWrapper));
if (!java_wrapper) {
jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor);
goto done;
return NULL;
}
JS_SetPrivate(cx, js_wrapper_obj, java_wrapper);
java_wrapper->class_descriptor = class_descriptor;
java_wrapper->java_obj = NULL;
#ifdef JSJ_THREADSAFE
PR_EnterMonitor(java_obj_reflections_monitor);
/* We may need to do the hash table lookup again, since some other
thread may have updated it while the lock wasn't being held. */
if (mutation_count != java_obj_reflections_mutation_count) {
hep = JSJ_HashTableRawLookup(java_obj_reflections,
hash_code, java_obj, (void*)jEnv);
he = *hep;
if (he) {
js_wrapper_obj = (JSObject *)he->value;
if (js_wrapper_obj) {
PR_ExitMonitor(java_obj_reflections_monitor);
return js_wrapper_obj;
}
}
}
java_obj_reflections_mutation_count++;
#endif
java_obj = (*jEnv)->NewGlobalRef(jEnv, java_obj);
java_wrapper->java_obj = java_obj;
@ -143,23 +181,21 @@ jsj_WrapJavaObject(JSContext *cx,
/* Add the JavaObject to the hash table */
he = JSJ_HashTableRawAdd(java_obj_reflections, hep, hash_code,
java_obj, js_wrapper_obj, (void*)jEnv);
#ifdef JSJ_THREADSAFE
PR_ExitMonitor(java_obj_reflections_monitor);
#endif
if (!he) {
(*jEnv)->DeleteGlobalRef(jEnv, java_obj);
goto out_of_memory;
}
done:
#ifdef JSJ_THREADSAFE
PR_ExitMonitor(java_obj_reflections_monitor);
#endif
return js_wrapper_obj;
out_of_memory:
/* No need to free js_wrapper_obj, as it will be finalized by GC. */
JS_ReportOutOfMemory(cx);
js_wrapper_obj = NULL;
goto done;
return NULL;
}
static void
@ -183,6 +219,8 @@ remove_java_obj_reflection_from_hashtable(jobject java_obj, JNIEnv *jEnv)
JSJ_HashTableRawRemove(java_obj_reflections, hep, he, (void*)jEnv);
#ifdef JSJ_THREADSAFE
java_obj_reflections_mutation_count++;
PR_ExitMonitor(java_obj_reflections_monitor);
#endif
}
@ -193,13 +231,14 @@ JavaObject_finalize(JSContext *cx, JSObject *obj)
JavaObjectWrapper *java_wrapper;
jobject java_obj;
JNIEnv *jEnv;
JSJavaThreadState *jsj_env;
java_wrapper = JS_GetPrivate(cx, obj);
if (!java_wrapper)
return;
java_obj = java_wrapper->java_obj;
jsj_MapJSContextToJSJThread(cx, &jEnv);
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return;
@ -209,6 +248,7 @@ JavaObject_finalize(JSContext *cx, JSObject *obj)
}
jsj_ReleaseJavaClassDescriptor(cx, jEnv, java_wrapper->class_descriptor);
JS_free(cx, java_wrapper);
jsj_ExitJava(jsj_env);
}
/* Trivial helper for jsj_DiscardJavaObjReflections(), below */
@ -255,11 +295,8 @@ JavaObject_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
JavaClassDescriptor *class_descriptor;
jobject java_obj;
JNIEnv *jEnv;
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
JSJavaThreadState *jsj_env;
JSBool result;
java_wrapper = JS_GetPrivate(cx, obj);
if (!java_wrapper) {
@ -269,10 +306,10 @@ JavaObject_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
}
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
JSJMSG_BAD_OP_JOBJECT);
JSJMSG_BAD_OP_JOBJECT);
return JS_FALSE;
}
java_obj = java_wrapper->java_obj;
class_descriptor = java_wrapper->class_descriptor;
@ -283,22 +320,43 @@ JavaObject_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
case JSTYPE_FUNCTION:
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
JSJMSG_CONVERT_TO_FUNC);
JSJMSG_CONVERT_TO_FUNC);
return JS_FALSE;
case JSTYPE_VOID:
case JSTYPE_STRING:
/* Get the Java per-thread environment pointer for this JSContext */
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
/* Either extract a C-string from the java.lang.String object
or call the Java toString() method */
return jsj_ConvertJavaObjectToJSString(cx, jEnv, class_descriptor, java_obj, vp);
result = jsj_ConvertJavaObjectToJSString(cx, jEnv, class_descriptor, java_obj, vp);
jsj_ExitJava(jsj_env);
return result;
case JSTYPE_NUMBER:
/* Call Java doubleValue() method, if applicable */
return jsj_ConvertJavaObjectToJSNumber(cx, jEnv, class_descriptor, java_obj, vp);
/* Get the Java per-thread environment pointer for this JSContext */
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
/* Call Java doubleValue() method, if applicable */
result = jsj_ConvertJavaObjectToJSNumber(cx, jEnv, class_descriptor, java_obj, vp);
jsj_ExitJava(jsj_env);
return result;
case JSTYPE_BOOLEAN:
/* Get the Java per-thread environment pointer for this JSContext */
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
/* Call booleanValue() method, if applicable */
return jsj_ConvertJavaObjectToJSBoolean(cx, jEnv, class_descriptor, java_obj, vp);
result = jsj_ConvertJavaObjectToJSBoolean(cx, jEnv, class_descriptor, java_obj, vp);
jsj_ExitJava(jsj_env);
return result;
default:
JS_ASSERT(0);
@ -460,23 +518,28 @@ JavaObject_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
JSObject *funobj;
jsval field_val, method_val;
JSBool success;
JSJavaThreadState *jsj_env;
/* printf("In JavaObject_getProperty\n"); */
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
if (vp)
*vp = JSVAL_VOID;
if (!lookup_member_by_id(cx, jEnv, obj, &java_wrapper, id, &member_descriptor, vp))
if (!lookup_member_by_id(cx, jEnv, obj, &java_wrapper, id, &member_descriptor, vp)) {
jsj_ExitJava(jsj_env);
return JS_FALSE;
}
/* Handle access to special, non-Java properties of JavaObjects, e.g. the
"constructor" property of the prototype object */
if (!member_descriptor)
if (!member_descriptor) {
jsj_ExitJava(jsj_env);
return JS_TRUE;
}
java_obj = java_wrapper->java_obj;
field_val = method_val = JSVAL_VOID;
@ -484,8 +547,10 @@ JavaObject_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
/* If a field member, get the value of the field */
if (member_descriptor->field) {
success = jsj_GetJavaFieldValue(cx, jEnv, member_descriptor->field, java_obj, &field_val);
if (!success)
if (!success) {
jsj_ExitJava(jsj_env);
return JS_FALSE;
}
}
/* If a method member, build a wrapper around the Java method */
@ -493,16 +558,20 @@ JavaObject_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
/* Create a function object with this JavaObject as its parent, so that
JSFUN_BOUND_METHOD binds it as the default 'this' for the function. */
funobj = JS_CloneFunctionObject(cx, member_descriptor->invoke_func_obj, obj);
if (!funobj)
if (!funobj) {
jsj_ExitJava(jsj_env);
return JS_FALSE;
}
method_val = OBJECT_TO_JSVAL(funobj);
}
#if TEST_JAVAMEMBER
/* Always create a JavaMember object, even though it's inefficient */
obj = jsj_CreateJavaMember(cx, method_val, field_val);
if (!obj)
if (!obj) {
jsj_ExitJava(jsj_env);
return JS_FALSE;
}
*vp = OBJECT_TO_JSVAL(obj);
#else /* !TEST_JAVAMEMBER */
@ -516,8 +585,10 @@ JavaObject_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
In Java, such ambiguity is not possible because the compiler
can statically determine which is being accessed. */
obj = jsj_CreateJavaMember(cx, method_val, field_val);
if (!obj)
if (!obj) {
jsj_ExitJava(jsj_env);
return JS_FALSE;
}
*vp = OBJECT_TO_JSVAL(obj);
}
@ -527,7 +598,8 @@ JavaObject_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
}
#endif /* !TEST_JAVAMEMBER */
jsj_ExitJava(jsj_env);
return JS_TRUE;
}
@ -541,16 +613,20 @@ JavaObject_setPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
JavaMemberDescriptor *member_descriptor;
jsval idval;
JNIEnv *jEnv;
JSJavaThreadState *jsj_env;
JSBool result;
/* printf("In JavaObject_setProperty\n"); */
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
if (!lookup_member_by_id(cx, jEnv, obj, &java_wrapper, id, &member_descriptor, NULL))
if (!lookup_member_by_id(cx, jEnv, obj, &java_wrapper, id, &member_descriptor, NULL)) {
jsj_ExitJava(jsj_env);
return JS_FALSE;
}
/* Could be assignment to magic JS __proto__ property rather than a Java field */
if (!member_descriptor) {
@ -563,9 +639,11 @@ JavaObject_setPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
if (!JSVAL_IS_OBJECT(*vp)) {
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
JSJMSG_BAD_PROTO_ASSIGNMENT);
jsj_ExitJava(jsj_env);
return JS_FALSE;
}
JS_SetPrototype(cx, obj, JSVAL_TO_OBJECT(*vp));
jsj_ExitJava(jsj_env);
return JS_TRUE;
}
@ -575,11 +653,15 @@ JavaObject_setPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
goto no_such_field;
/* Silently fail if field value is final (immutable), as required by ECMA spec */
if (member_descriptor->field->modifiers & ACC_FINAL)
if (member_descriptor->field->modifiers & ACC_FINAL) {
jsj_ExitJava(jsj_env);
return JS_TRUE;
}
java_obj = java_wrapper->java_obj;
return jsj_SetJavaFieldValue(cx, jEnv, member_descriptor->field, java_obj, *vp);
result = jsj_SetJavaFieldValue(cx, jEnv, member_descriptor->field, java_obj, *vp);
jsj_ExitJava(jsj_env);
return result;
no_such_field:
JS_IdToValue(cx, id, &idval);
@ -588,6 +670,7 @@ no_such_field:
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
JSJMSG_NO_NAME_IN_CLASS,
member_name, class_descriptor->name);
jsj_ExitJava(jsj_env);
return JS_FALSE;
}
@ -602,11 +685,12 @@ JavaObject_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
JNIEnv *jEnv;
JSErrorReporter old_reporter;
jsval dummy_val;
JSJavaThreadState *jsj_env;
/* printf("In JavaObject_lookupProperty()\n"); */
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
@ -624,6 +708,7 @@ JavaObject_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
}
JS_SetErrorReporter(cx, old_reporter);
jsj_ExitJava(jsj_env);
return JS_TRUE;
}
@ -693,6 +778,7 @@ JavaObject_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
JavaMemberDescriptor *member_descriptor;
JavaClassDescriptor *class_descriptor;
JNIEnv *jEnv;
JSJavaThreadState *jsj_env;
java_wrapper = JS_GetPrivate(cx, obj);
/* Check for prototype object */
@ -709,7 +795,7 @@ JavaObject_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
case JSENUMERATE_INIT:
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
@ -717,6 +803,7 @@ JavaObject_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
*statep = PRIVATE_TO_JSVAL(member_descriptor);
if (idp)
*idp = INT_TO_JSVAL(class_descriptor->num_instance_members);
jsj_ExitJava(jsj_env);
return JS_TRUE;
case JSENUMERATE_NEXT:

Просмотреть файл

@ -118,6 +118,7 @@ JavaPackage_resolve(JSContext *cx, JSObject *obj, jsval id)
char *subPath, *newPath;
const char *path;
JNIEnv *jEnv;
JSJavaThreadState *jsj_env;
/* Painful hack for pre_define_java_packages() */
if (quiet_resolve_failure)
@ -148,7 +149,7 @@ JavaPackage_resolve(JSContext *cx, JSObject *obj, jsval id)
return JS_FALSE;
}
jsj_MapJSContextToJSJThread(cx, &jEnv);
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
@ -235,6 +236,7 @@ JavaPackage_resolve(JSContext *cx, JSObject *obj, jsval id)
out:
free(newPath);
jsj_ExitJava(jsj_env);
return ok;
}

Просмотреть файл

@ -396,10 +396,41 @@ jsj_DiscardJavaClassReflections(JNIEnv *jEnv)
{
JSJavaThreadState *jsj_env;
char *err_msg;
JSContext *cx;
/* Get the per-thread state corresponding to the current Java thread */
jsj_env = jsj_MapJavaThreadToJSJavaThreadState(jEnv, &err_msg);
JS_ASSERT(jsj_env);
if (!jsj_env)
return;
/* Get the JSContext that we're supposed to use for this Java thread */
cx = jsj_env->cx;
if (!cx) {
/* We called spontaneously into JS from Java, rather than from JS into
Java and back into JS. Invoke a callback to obtain/create a
JSContext for us to use. */
if (JSJ_callbacks->map_jsj_thread_to_js_context) {
#ifdef OJI
cx = JSJ_callbacks->map_jsj_thread_to_js_context(jsj_env,
NULL, /* FIXME: What should this argument be ? */
jEnv, &err_msg);
#else
cx = JSJ_callbacks->map_jsj_thread_to_js_context(jsj_env,
jEnv, &err_msg);
#endif
JS_ASSERT(cx);
if (!cx)
return;
} else {
err_msg = JS_smprintf("Unable to find/create JavaScript execution "
"context for JNI thread 0x%08x", jEnv);
jsj_LogError(err_msg);
free(err_msg);
return;
}
jsj_env->cx = cx;
}
if (java_class_reflections) {
JSJ_HashTableEnumerateEntries(java_class_reflections,
@ -470,19 +501,22 @@ reflect_java_methods_and_fields(JSContext *cx,
success = JS_TRUE; /* optimism */
#ifdef JSJ_THREAD_SAFE
#ifdef JSJ_THREADSAFE
PR_EnterMonitor(java_reflect_monitor);
#endif
/* See if we raced with another thread to reflect members of this class */
/* See if we raced with another thread to reflect members of this class.
If the status is REFLECT_COMPLETE, another thread beat us to it. If
the status is REFLECT_IN_PROGRESS, we've recursively called this
function within a single thread. Either way, we're done. */
if (reflect_statics_only) {
if (class_descriptor->static_members_reflected)
if (class_descriptor->static_members_reflected != REFLECT_NO)
goto done;
class_descriptor->static_members_reflected = JS_TRUE;
class_descriptor->static_members_reflected = REFLECT_IN_PROGRESS;
} else {
if (class_descriptor->instance_members_reflected)
if (class_descriptor->instance_members_reflected != REFLECT_NO)
goto done;
class_descriptor->instance_members_reflected = JS_TRUE;
class_descriptor->instance_members_reflected = REFLECT_IN_PROGRESS;
}
if (!jsj_ReflectJavaMethods(cx, jEnv, class_descriptor, reflect_statics_only))
@ -496,16 +530,18 @@ reflect_java_methods_and_fields(JSContext *cx,
class_descriptor->num_static_members++;
member_descriptor = member_descriptor->next;
}
class_descriptor->static_members_reflected = REFLECT_COMPLETE;
} else {
member_descriptor = class_descriptor->instance_members;
while (member_descriptor) {
class_descriptor->num_instance_members++;
member_descriptor = member_descriptor->next;
}
class_descriptor->instance_members_reflected = REFLECT_COMPLETE;
}
done:
#ifdef JSJ_THREAD_SAFE
#ifdef JSJ_THREADSAFE
PR_ExitMonitor(java_reflect_monitor);
#endif
return success;
@ -520,7 +556,7 @@ jsj_GetClassStaticMembers(JSContext *cx,
JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor)
{
if (!class_descriptor->static_members_reflected)
if (class_descriptor->static_members_reflected != REFLECT_COMPLETE)
reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_TRUE);
return class_descriptor->static_members;
}
@ -530,7 +566,7 @@ jsj_GetClassInstanceMembers(JSContext *cx,
JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor)
{
if (!class_descriptor->instance_members_reflected)
if (class_descriptor->instance_members_reflected != REFLECT_COMPLETE)
reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_FALSE);
return class_descriptor->instance_members;
}
@ -615,7 +651,7 @@ JavaMemberDescriptor *
jsj_LookupJavaClassConstructors(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor)
{
if (!class_descriptor->static_members_reflected)
if (class_descriptor->static_members_reflected != REFLECT_COMPLETE)
reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_TRUE);
return class_descriptor->constructors;
}
@ -675,7 +711,7 @@ jsj_InitJavaClassReflectionsTable()
{
java_class_reflections =
JSJ_NewHashTable(64, jsj_HashJavaObject, jsj_JavaObjectComparator,
jsj_JavaObjectComparator, NULL, NULL);
NULL, NULL, NULL);
if (!java_class_reflections)
return JS_FALSE;

Просмотреть файл

@ -1088,13 +1088,16 @@ preferred_conversion(JSContext *cx, JNIEnv *jEnv, jsval js_val,
js_type = compute_jsj_type(cx, js_val);
rank1 = rank_table[js_type][(int)descriptor1->type - 2];
rank2 = rank_table[js_type][(int)descriptor2->type - 2];
/* Fast path for conversion from most JS types */
if (rank1 < rank2)
return JSJPREF_FIRST_ARG;
/*
* Special logic is required for matching the classes of wrapped
* Java objects.
*/
if (((js_type == JSJTYPE_JAVAOBJECT) || (js_type == JSJTYPE_JAVAARRAY)) &&
IS_REFERENCE_TYPE(descriptor2->type)) {
if (rank2 == 0) {
java_class1 = descriptor1->java_class;
java_class2 = descriptor2->java_class;
@ -1110,7 +1113,7 @@ preferred_conversion(JSContext *cx, JNIEnv *jEnv, jsval js_val,
* For JavaObject arguments, any compatible reference type is preferable
* to any primitive Java type or to java.lang.String.
*/
if (rank2 < rank1)
if (rank1 != 0)
return JSJPREF_SECOND_ARG;
/*
@ -1127,10 +1130,6 @@ preferred_conversion(JSContext *cx, JNIEnv *jEnv, jsval js_val,
return JSJPREF_AMBIGUOUS;
}
/* Fast path for conversion from most JS types */
if (rank1 < rank2)
return JSJPREF_FIRST_ARG;
if (rank1 > rank2)
return JSJPREF_SECOND_ARG;
@ -1354,7 +1353,6 @@ invoke_java_method(JSContext *cx, JSJavaThreadState *jsj_env,
jmethodID methodID;
JavaMethodSignature *signature;
JavaSignature *return_val_signature;
JSContext *old_cx;
JNIEnv *jEnv;
JSBool *localv, error_occurred, success;
@ -1375,15 +1373,6 @@ invoke_java_method(JSContext *cx, JSJavaThreadState *jsj_env,
java_class = NULL;
}
old_cx = JSJ_SetDefaultJSContextForJavaThread(cx, jsj_env);
#ifdef DEBUG
if (old_cx && (old_cx != cx)) {
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
JSJMSG_MULTIPLE_JTHREADS);
}
#endif
jargv = NULL;
localv = NULL;
if (argc) {
@ -1394,6 +1383,12 @@ invoke_java_method(JSContext *cx, JSJavaThreadState *jsj_env,
}
}
/* Prevent deadlocking if we re-enter JS on another thread as a result of a Java
method call and that new thread wants to perform a GC. */
#ifdef JSJ_THREADSAFE
JS_EndRequest(cx);
#endif
#define CALL_JAVA_METHOD(type, member) \
JS_BEGIN_MACRO \
if (is_static_method) { \
@ -1458,7 +1453,8 @@ invoke_java_method(JSContext *cx, JSJavaThreadState *jsj_env,
case JAVA_SIGNATURE_UNKNOWN:
JS_ASSERT(0);
return JS_FALSE;
error_occurred = JS_TRUE;
goto out;
/* Non-primitive (reference) type */
default:
@ -1468,7 +1464,6 @@ invoke_java_method(JSContext *cx, JSJavaThreadState *jsj_env,
}
out:
JSJ_SetDefaultJSContextForJavaThread(old_cx, jsj_env);
if (localv) {
for (i = 0; i < argc; i++) {
@ -1480,6 +1475,10 @@ out:
if (jargv)
JS_free(cx, jargv);
#ifdef JSJ_THREADSAFE
JS_BeginRequest(cx);
#endif
if (!error_occurred) {
success = jsj_ConvertJavaValueToJSValue(cx, jEnv, return_val_signature, &java_value, vp);
if (IS_REFERENCE_TYPE(return_val_signature->type))
@ -1523,7 +1522,6 @@ invoke_java_constructor(JSContext *cx,
jobject java_object;
jmethodID methodID;
JavaMethodSignature *signature;
JSContext *old_cx;
JNIEnv *jEnv;
JSBool *localv;
JSBool success, error_occurred;
@ -1547,19 +1545,18 @@ invoke_java_constructor(JSContext *cx,
}
}
old_cx = JSJ_SetDefaultJSContextForJavaThread(cx, jsj_env);
#ifdef DEBUG
if (old_cx && (old_cx != cx)) {
JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
JSJMSG_MULTIPLE_JTHREADS);
}
/* Prevent deadlocking if we re-enter JS on another thread as a result of a Java
method call and that new thread wants to perform a GC. */
#ifdef JSJ_THREADSAFE
JS_EndRequest(cx);
#endif
/* Call the constructor */
java_object = (*jEnv)->NewObjectA(jEnv, java_class, methodID, jargv);
JSJ_SetDefaultJSContextForJavaThread(old_cx, jsj_env);
#ifdef JSJ_THREADSAFE
JS_BeginRequest(cx);
#endif
if (!java_object) {
jsj_ReportJavaError(cx, jEnv, "Error while constructing instance of %s",
@ -1655,19 +1652,23 @@ jsj_JavaConstructorWrapper(JSContext *cx, JSObject *obj,
JavaMemberDescriptor *member_descriptor;
JSJavaThreadState *jsj_env;
JNIEnv *jEnv;
JSBool result;
/* Get the Java per-thread environment pointer for this JSContext */
jsj_env = jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
obj = JSVAL_TO_OBJECT(argv[-2]);
class_descriptor = JS_GetPrivate(cx, obj);
JS_ASSERT(class_descriptor);
if (!class_descriptor)
return JS_FALSE;
/* Get the Java per-thread environment pointer for this JSContext */
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
member_descriptor = jsj_LookupJavaClassConstructors(cx, jEnv, class_descriptor);
return java_constructor_wrapper(cx, jsj_env, member_descriptor,
class_descriptor, argc, argv, vp);
result = java_constructor_wrapper(cx, jsj_env, member_descriptor,
class_descriptor, argc, argv, vp);
jsj_ExitJava(jsj_env);
return result;
}
@ -1709,22 +1710,25 @@ jsj_JavaStaticMethodWrapper(JSContext *cx, JSObject *obj,
jsval idval;
JNIEnv *jEnv;
JSJavaThreadState *jsj_env;
/* Get the Java per-thread environment pointer for this JSContext */
jsj_env = jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
JSBool result;
class_descriptor = JS_GetPrivate(cx, obj);
if (!class_descriptor)
return JS_FALSE;
/* Get the Java per-thread environment pointer for this JSContext */
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
JS_ASSERT(JS_TypeOfValue(cx, argv[-2]) == JSTYPE_FUNCTION);
function = JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[-2]));
idval = STRING_TO_JSVAL(JS_InternString(cx, JS_GetFunctionName(function)));
JS_ValueToId(cx, idval, &id);
return static_method_wrapper(cx, jsj_env, class_descriptor, id, argc, argv, vp);
result = static_method_wrapper(cx, jsj_env, class_descriptor, id, argc, argv, vp);
jsj_ExitJava(jsj_env);
return result;
}
JS_DLL_CALLBACK JSBool
@ -1740,11 +1744,7 @@ jsj_JavaInstanceMethodWrapper(JSContext *cx, JSObject *obj,
JSJavaThreadState *jsj_env;
JNIEnv *jEnv;
jobject java_obj;
/* Get the Java per-thread environment pointer for this JSContext */
jsj_env = jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
JSBool result;
java_wrapper = JS_GetPrivate(cx, obj);
if (!java_wrapper)
@ -1757,14 +1757,22 @@ jsj_JavaInstanceMethodWrapper(JSContext *cx, JSObject *obj,
JS_ValueToId(cx, idval, &id);
class_descriptor = java_wrapper->class_descriptor;
/* Get the Java per-thread environment pointer for this JSContext */
jsj_env = jsj_EnterJava(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
/* Try to find an instance method with the given name first */
member_descriptor = jsj_LookupJavaMemberDescriptorById(cx, jEnv, class_descriptor, id);
if (member_descriptor)
return invoke_overloaded_java_method(cx, jsj_env, member_descriptor,
JS_FALSE, java_obj,
class_descriptor, argc, argv, vp);
result = invoke_overloaded_java_method(cx, jsj_env, member_descriptor,
JS_FALSE, java_obj,
class_descriptor, argc, argv, vp);
/* If no instance method was found, try for a static method or constructor */
return static_method_wrapper(cx, jsj_env, class_descriptor, id, argc, argv, vp);
else
result = static_method_wrapper(cx, jsj_env, class_descriptor, id, argc, argv, vp);
jsj_ExitJava(jsj_env);
return result;
}

Просмотреть файл

@ -151,6 +151,13 @@ struct JavaMemberDescriptor {
JSObject * invoke_func_obj; /* If non-null, JSFunction obj to invoke method */
};
/* Status of Class member reflection. See JavaClassDescriptor. */
typedef enum {
REFLECT_NO,
REFLECT_IN_PROGRESS,
REFLECT_COMPLETE
} ReflectStatus;
/* This is the native portion of a reflected Java class */
struct JavaClassDescriptor {
const char * name; /* Name of class, e.g. "java.lang.Byte" */
@ -158,9 +165,9 @@ struct JavaClassDescriptor {
jclass java_class; /* Opaque JVM handle to corresponding java.lang.Class */
int num_instance_members;
int num_static_members;
JSBool instance_members_reflected;
volatile ReflectStatus instance_members_reflected;
JavaMemberDescriptor * instance_members;
JSBool static_members_reflected;
volatile ReflectStatus static_members_reflected;
JavaMemberDescriptor * static_members;
JavaMemberDescriptor * constructors;
int modifiers; /* Class declaration qualifiers,
@ -204,7 +211,7 @@ struct JSJavaThreadState {
JNIEnv * jEnv; /* Per-thread opaque handle to Java VM */
CapturedJSError * pending_js_errors; /* JS errors to be thrown as Java exceptions */
JSContext * cx; /* current JS context for thread */
int recursion_depth;/* # transitions into JS from Java */
int recursion_depth;/* # transitions into Java from JS */
JSJavaThreadState * next; /* next thread state among all created threads */
};
@ -219,7 +226,7 @@ typedef struct JavaToJSSavedState JavaToJSSavedState;
objects hold a reference to native JSObjects. */
struct JSObjectHandle {
JSObject *js_obj;
JSContext *cx; /* Creating context, needed for finalization */
JSRuntime *rt;
};
typedef struct JSObjectHandle JSObjectHandle;
@ -578,8 +585,11 @@ JavaStringToId(JSContext *cx, JNIEnv *jEnv, jstring jstr, jsid *idp);
extern const char *
jsj_DupJavaStringUTF(JSContext *cx, JNIEnv *jEnv, jstring jstr);
JSJavaThreadState *
jsj_MapJSContextToJSJThread(JSContext *cx, JNIEnv **envp);
extern JSJavaThreadState *
jsj_EnterJava(JSContext *cx, JNIEnv **envp);
extern void
jsj_ExitJava(JSJavaThreadState *jsj_env);
#ifdef DEBUG
#define DEBUG_LOG(args) printf args

Просмотреть файл

@ -221,88 +221,97 @@ vreport_java_error(JSContext *cx, JNIEnv *jEnv, const char *format, va_list ap)
/* Get the exception out of the java environment. */
java_exception = (*jEnv)->ExceptionOccurred(jEnv);
if (!java_exception) {
JSString *err_jsstr;
char *err = JS_vsmprintf(format, ap);
if (!err)
return;
err_jsstr = JS_NewString(cx, err, strlen(err));
if (!err_jsstr)
return;
JS_SetPendingException(cx, STRING_TO_JSVAL(err_jsstr));
return;
}
if (java_exception) {
(*jEnv)->ExceptionClear(jEnv);
(*jEnv)->ExceptionClear(jEnv);
/* Check for JSException */
if (njJSException &&
(*jEnv)->IsInstanceOf(jEnv, java_exception, njJSException)) {
/* Check for JSException */
if (njJSException &&
(*jEnv)->IsInstanceOf(jEnv, java_exception, njJSException)) {
wrapped_exception_type =
(*jEnv)->GetIntField(jEnv, java_exception,
njJSException_wrappedExceptionType);
wrapped_exception_type =
(*jEnv)->GetIntField(jEnv, java_exception,
njJSException_wrappedExceptionType);
if (wrapped_exception_type != JSTYPE_EMPTY) {
java_obj =
(*jEnv)->GetObjectField(jEnv, java_exception,
njJSException_wrappedException);
if ((java_obj == NULL) &&
(wrapped_exception_type == JSTYPE_OBJECT)) {
js_exception = JSVAL_NULL;
} else {
java_class = (*jEnv)->GetObjectClass(jEnv, java_obj);
class_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, java_class);
/* OK to delete ref, since above call adds global ref */
(*jEnv)->DeleteLocalRef(jEnv, java_class);
if (wrapped_exception_type != JSTYPE_EMPTY) {
java_obj =
(*jEnv)->GetObjectField(jEnv, java_exception,
njJSException_wrappedException);
if ((java_obj == NULL) &&
(wrapped_exception_type == JSTYPE_OBJECT)) {
js_exception = JSVAL_NULL;
} else {
java_class = (*jEnv)->GetObjectClass(jEnv, java_obj);
class_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, java_class);
/* OK to delete ref, since above call adds global ref */
(*jEnv)->DeleteLocalRef(jEnv, java_class);
/* Convert native JS values back to native types. */
switch(wrapped_exception_type) {
case JSTYPE_NUMBER:
if (!jsj_ConvertJavaObjectToJSNumber(cx, jEnv,
class_descriptor,
java_obj,
&js_exception))
goto do_report;
break;
case JSTYPE_BOOLEAN:
if (!jsj_ConvertJavaObjectToJSBoolean(cx, jEnv,
class_descriptor,
java_obj,
&js_exception))
goto do_report;
break;
case JSTYPE_STRING:
if (!jsj_ConvertJavaObjectToJSString(cx, jEnv,
class_descriptor,
java_obj,
&js_exception))
goto do_report;
break;
case JSTYPE_VOID:
js_exception = JSVAL_VOID;
break;
case JSTYPE_OBJECT:
case JSTYPE_FUNCTION:
default:
if ((*jEnv)->IsInstanceOf(jEnv, java_obj, njJSObject)) {
js_exception = OBJECT_TO_JSVAL(jsj_UnwrapJSObjectWrapper(jEnv, java_obj));
if (!js_exception)
goto do_report;
} else {
if (!jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_obj,
&js_exception))
goto do_report;
}
/* Convert native JS values back to native types. */
switch(wrapped_exception_type) {
case JSTYPE_NUMBER:
if (!jsj_ConvertJavaObjectToJSNumber(cx, jEnv,
class_descriptor,
java_obj,
&js_exception))
goto error;
break;
case JSTYPE_BOOLEAN:
if (!jsj_ConvertJavaObjectToJSBoolean(cx, jEnv,
class_descriptor,
java_obj,
&js_exception))
goto error;
break;
case JSTYPE_STRING:
if (!jsj_ConvertJavaObjectToJSString(cx, jEnv,
class_descriptor,
java_obj,
&js_exception))
goto error;
break;
case JSTYPE_VOID:
js_exception = JSVAL_VOID;
break;
case JSTYPE_OBJECT:
case JSTYPE_FUNCTION:
default:
if ((*jEnv)->IsInstanceOf(jEnv, java_obj, njJSObject)) {
js_exception = OBJECT_TO_JSVAL(jsj_UnwrapJSObjectWrapper(jEnv, java_obj));
if (!js_exception)
goto error;
} else {
if (!jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_obj,
&js_exception))
goto error;
}
}
}
/* Check for internal exception */
} else {
if (!JSJ_ConvertJavaObjectToJSValue(cx, java_exception,
&js_exception)) {
goto do_report;
}
}
/* Set pending JS exception and clear the java exception. */
JS_SetPendingException(cx, js_exception);
goto done;
/* Check for internal exception */
} else {
if (!JSJ_ConvertJavaObjectToJSValue(cx, java_exception,
&js_exception)) {
goto error;
}
}
/* Set pending JS exception and clear the java exception. */
JS_SetPendingException(cx, js_exception);
goto done;
do_report:
error:
JS_ASSERT(0);
jsj_LogError("Out of memory while attempting to throw JSException\n");
@ -411,7 +420,7 @@ jsj_GetJavaArrayLength(JSContext *cx, JNIEnv *jEnv, jarray java_array)
static JSJavaThreadState *the_java_jsj_env = NULL;
JSJavaThreadState *
jsj_MapJSContextToJSJThread(JSContext *cx, JNIEnv **envp)
jsj_EnterJava(JSContext *cx, JNIEnv **envp)
{
JSJavaThreadState *jsj_env;
char *err_msg;
@ -429,13 +438,24 @@ jsj_MapJSContextToJSJThread(JSContext *cx, JNIEnv **envp)
}
return NULL;
}
/* need to assign the context field. */
JS_ASSERT((jsj_env->recursion_depth == 0) || (jsj_env->cx == cx));
jsj_env->recursion_depth++;
jsj_env->cx = cx;
if (envp)
*envp = jsj_env->jEnv;
return jsj_env;
}
extern void
jsj_ExitJava(JSJavaThreadState *jsj_env)
{
JS_ASSERT(jsj_env->recursion_depth > 0);
if (--jsj_env->recursion_depth == 0)
jsj_env->cx = NULL;
}
/**
* Since only one Java thread is allowed to enter JavaScript, this function is
* used to enforce the use of that thread's state. The static global the_java_jsj_env

Просмотреть файл

@ -78,7 +78,9 @@ typedef struct JSJCallbacks {
callback can call JSJ_SetJSContextForJavaThread() to avoid any further
callbacks of this type for this Java thread. */
JSContext * (*map_jsj_thread_to_js_context)(JSJavaThreadState *jsj_env,
#ifdef OJI
void *java_applet_obj,
#endif
JNIEnv *jEnv,
char **errp);

Просмотреть файл

@ -101,7 +101,7 @@ nsCLiveconnect::GetMember(JNIEnv *jEnv, jsobject obj, const jchar *name, jsize l
JSJavaThreadState *jsj_env = NULL;
JSObjectHandle *handle = (JSObjectHandle*)obj;
JSObject *js_obj = handle->js_obj;
JSContext *cx = handle->cx;
JSContext *cx = NULL;
jobject member = NULL;
jsval js_val;
int dummy_cost = 0;
@ -155,7 +155,7 @@ nsCLiveconnect::GetSlot(JNIEnv *jEnv, jsobject obj, jint slot, void* principalsA
JSJavaThreadState *jsj_env = NULL;
JSObjectHandle *handle = (JSObjectHandle*)obj;
JSObject *js_obj = handle->js_obj;
JSContext *cx = handle->cx;
JSContext *cx = NULL;
jobject member = NULL;
jsval js_val;
int dummy_cost = 0;
@ -203,7 +203,7 @@ nsCLiveconnect::SetMember(JNIEnv *jEnv, jsobject obj, const jchar *name, jsize l
JSJavaThreadState *jsj_env = NULL;
JSObjectHandle *handle = (JSObjectHandle*)obj;
JSObject *js_obj = handle->js_obj;
JSContext *cx = handle->cx;
JSContext *cx = NULL;
jsval js_val;
JSErrorReporter saved_state = NULL;
@ -249,7 +249,7 @@ nsCLiveconnect::SetSlot(JNIEnv *jEnv, jsobject obj, jint slot, jobject java_obj,
JSJavaThreadState *jsj_env = NULL;
JSObjectHandle *handle = (JSObjectHandle*)obj;
JSObject *js_obj = handle->js_obj;
JSContext *cx = handle->cx;
JSContext *cx = NULL;
jsval js_val;
JSErrorReporter saved_state = NULL;
@ -285,7 +285,7 @@ nsCLiveconnect::RemoveMember(JNIEnv *jEnv, jsobject obj, const jchar *name, jsiz
JSJavaThreadState *jsj_env = NULL;
JSObjectHandle *handle = (JSObjectHandle*)obj;
JSObject *js_obj = handle->js_obj;
JSContext *cx = handle->cx;
JSContext *cx = NULL;
jsval js_val;
JSErrorReporter saved_state = NULL;
@ -329,7 +329,7 @@ nsCLiveconnect::Call(JNIEnv *jEnv, jsobject obj, const jchar *name, jsize length
JSJavaThreadState *jsj_env = NULL;
JSObjectHandle *handle = (JSObjectHandle*)obj;
JSObject *js_obj = handle->js_obj;
JSContext *cx = handle->cx;
JSContext *cx = NULL;
jsval js_val;
jsval function_val = 0;
int dummy_cost = 0;
@ -404,7 +404,7 @@ nsCLiveconnect::Eval(JNIEnv *jEnv, jsobject obj, const jchar *script, jsize leng
JSJavaThreadState *jsj_env = NULL;
JSObjectHandle *handle = (JSObjectHandle*)obj;
JSObject *js_obj = handle->js_obj;
JSContext *cx = handle->cx;
JSContext *cx = NULL;
jsval js_val;
int dummy_cost = 0;
JSBool dummy_bool = PR_FALSE;
@ -507,7 +507,7 @@ nsCLiveconnect::GetWindow(JNIEnv *jEnv, void *java_applet_obj, void* principals
if (handle != NULL)
{
handle->js_obj = js_obj;
handle->cx = cx;
handle->rt = JS_GetRuntime(cx);
}
*pobj = (jsobject)handle;
/* FIXME: what if the window is explicitly disposed of, how do we
@ -530,14 +530,13 @@ NS_METHOD
nsCLiveconnect::FinalizeJSObject(JNIEnv *jEnv, jsobject obj)
{
JSObjectHandle *handle = (JSObjectHandle *)obj;
JSContext *cx = handle->cx;
if(jEnv == NULL)
return NS_ERROR_FAILURE;
if (!handle)
return NS_ERROR_NULL_POINTER;
JS_RemoveRoot(cx, &handle->js_obj);
JS_free(cx, handle);
JS_RemoveRootRT(handle->rt, &handle->js_obj);
free(handle);
return NS_OK;
}
@ -548,7 +547,7 @@ nsCLiveconnect::ToString(JNIEnv *jEnv, jsobject obj, jstring *pjstring)
JSJavaThreadState *jsj_env = NULL;
JSObjectHandle *handle = (JSObjectHandle*)obj;
JSObject *js_obj = handle->js_obj;
JSContext *cx = handle->cx;
JSContext *cx = NULL;
JSErrorReporter saved_state = NULL;
jstring result = NULL;
JSString *jsstr = NULL;