зеркало из https://github.com/mozilla/pjs.git
Propagating fixes from SpiderMonkey140_BRANCH
This commit is contained in:
Родитель
10855247b5
Коммит
7f0a6e786b
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче