📄 jsj_jsobject.c
字号:
* possible that a JS error was actually triggered by Java at some point, in * which case the original Java exception is thrown. */static voidthrow_any_pending_js_error_as_a_java_exception(JSJavaThreadState *jsj_env){ CapturedJSError *error; JNIEnv *jEnv; jstring message_jstr, linebuf_jstr, filename_jstr; jint index, lineno; JSErrorReport *report; JSContext *cx; jsval pending_exception; jobject java_obj; int dummy_cost; JSBool is_local_refp; JSType primitive_type; jthrowable java_exception; message_jstr = linebuf_jstr = filename_jstr = java_exception = NULL; /* Get the Java JNI environment */ jEnv = jsj_env->jEnv; cx = jsj_env->cx; /* Get the pending JS exception if it exists */ if (cx&&JS_IsExceptionPending(cx)) { if (!JS_GetPendingException(cx, &pending_exception)) goto out_of_memory; /* Find out the JSTYPE of this jsval. */ primitive_type = JS_TypeOfValue(cx, pending_exception); /* Convert jsval exception to a java object and then use it to create an instance of JSException. */ if (!jsj_ConvertJSValueToJavaObject(cx, jEnv, pending_exception, jsj_get_jlObject_descriptor(cx, jEnv), &dummy_cost, &java_obj, &is_local_refp)) goto done; java_exception = (*jEnv)->NewObject(jEnv, njJSException, njJSException_JSException_wrap, primitive_type, java_obj); if (is_local_refp) (*jEnv)->DeleteLocalRef(jEnv, java_obj); if (!java_exception) goto out_of_memory; /* Throw the newly-created JSException */ if ((*jEnv)->Throw(jEnv, java_exception) < 0) { JS_ASSERT(0); jsj_LogError("Couldn't throw JSException\n"); goto done; } JS_ClearPendingException(cx); return; } if (!jsj_env->pending_js_errors) {#ifdef DEBUG /* Any exception should be cleared as soon as it's detected, so there shouldn't be any pending. */ if ((*jEnv)->ExceptionOccurred(jEnv)) { /* A Java exception occurred, but nobody in JS-land noticed. */ JS_ASSERT(0); (*jEnv)->ExceptionClear(jEnv); }#endif return; } /* Get the deepest (oldest) saved JS error */ /* XXX - What's the right thing to do about newer errors ? For now we just throw them away */ error = jsj_env->pending_js_errors; while (error->next) error = error->next; /* * If the JS error was originally the result of a Java exception, rethrow * the original exception. */ if (error->java_exception) { (*jEnv)->Throw(jEnv, error->java_exception); goto done; } /* Propagate any JS errors that did not originate as Java exceptions into Java as an instance of netscape.javascript.JSException */ /* First, marshall the arguments to the JSException constructor */ message_jstr = NULL; if (error->message) { message_jstr = (*jEnv)->NewStringUTF(jEnv, error->message); if (!message_jstr) goto out_of_memory; } report = &error->report; filename_jstr = NULL; if (report->filename) { filename_jstr = (*jEnv)->NewStringUTF(jEnv, report->filename); if (!filename_jstr) goto out_of_memory; } linebuf_jstr = NULL; if (report->linebuf) { linebuf_jstr = (*jEnv)->NewStringUTF(jEnv, report->linebuf); if (!linebuf_jstr) goto out_of_memory; } lineno = report->lineno; index = report->linebuf ? report->tokenptr - report->linebuf : 0; /* Call the JSException constructor */ java_exception = (*jEnv)->NewObject(jEnv, njJSException, njJSException_JSException, message_jstr, filename_jstr, lineno, linebuf_jstr, index); if (!java_exception) goto out_of_memory; /* Throw the newly-created JSException */ if ((*jEnv)->Throw(jEnv, java_exception) < 0) { JS_ASSERT(0); jsj_UnexpectedJavaError(cx, jEnv, "Couldn't throw JSException\n"); } goto done;out_of_memory: /* No recovery possible */ JS_ASSERT(0); jsj_LogError("Out of memory while attempting to throw JSException\n");done: jsj_ClearPendingJSErrors(jsj_env); /* * Release local references to Java objects, since some JVMs seem reticent * about collecting them otherwise. */ if (message_jstr) (*jEnv)->DeleteLocalRef(jEnv, message_jstr); if (filename_jstr) (*jEnv)->DeleteLocalRef(jEnv, filename_jstr); if (linebuf_jstr) (*jEnv)->DeleteLocalRef(jEnv, linebuf_jstr); if (java_exception) (*jEnv)->DeleteLocalRef(jEnv, java_exception);}/* * This function is called up returning from Java back into JS as a result of * a thrown netscape.javascript.JSException, which itself must have been caused * by a JS error when Java called into JS. The original JS error is * reconstituted from the JSException and re-reported as a JS error. * * Returns JS_FALSE if an internal error occurs, JS_TRUE otherwise. */JSBooljsj_ReportUncaughtJSException(JSContext *cx, JNIEnv *jEnv, jthrowable java_exception){ JSBool success; JSErrorReport report; const char *linebuf, *filename, *message, *tokenptr; jint lineno, token_index; jstring linebuf_jstr, filename_jstr, message_jstr; /* Initialize everything to NULL */ memset(&report, 0, sizeof(JSErrorReport)); success = JS_FALSE; filename_jstr = linebuf_jstr = message_jstr = NULL; filename = message = linebuf = tokenptr = NULL; lineno = (*jEnv)->GetIntField(jEnv, java_exception, njJSException_lineno); report.lineno = lineno; filename_jstr = (*jEnv)->GetObjectField(jEnv, java_exception, njJSException_filename); if ((*jEnv)->ExceptionOccurred(jEnv)) { jsj_UnexpectedJavaError(cx, jEnv, "Unable to access filename field of a JSException"); goto done; } if (filename_jstr) filename = (*jEnv)->GetStringUTFChars(jEnv, filename_jstr, 0); report.filename = filename; linebuf_jstr = (*jEnv)->GetObjectField(jEnv, java_exception, njJSException_source); if ((*jEnv)->ExceptionOccurred(jEnv)) { jsj_UnexpectedJavaError(cx, jEnv, "Unable to access source field of a JSException"); goto done; } if (linebuf_jstr) linebuf = (*jEnv)->GetStringUTFChars(jEnv, linebuf_jstr, 0); report.linebuf = linebuf; token_index = (*jEnv)->GetIntField(jEnv, java_exception, njJSException_lineno); report.tokenptr = linebuf + token_index; message_jstr = (*jEnv)->CallObjectMethod(jEnv, java_exception, jlThrowable_getMessage); if ((*jEnv)->ExceptionOccurred(jEnv)) { jsj_UnexpectedJavaError(cx, jEnv, "Unable to access message of a JSException"); goto done; } if (message_jstr) message = (*jEnv)->GetStringUTFChars(jEnv, message_jstr, 0); js_ReportErrorAgain(cx, message, &report); success = JS_TRUE;done: if (filename_jstr && filename) (*jEnv)->ReleaseStringUTFChars(jEnv, filename_jstr, filename); if (linebuf_jstr && linebuf) (*jEnv)->ReleaseStringUTFChars(jEnv, linebuf_jstr, linebuf); if (message_jstr && message) (*jEnv)->ReleaseStringUTFChars(jEnv, message_jstr, message); return success;}/*************** Utilities for calling JavaScript from Java *****************//* * This routine is called just prior to invoking any JS API function from * Java. It performs a common set of chores, such as obtaining the LiveConnect * state for the invoking Java thread and determining the JSContext to be * used for this thread. * * Returns NULL on failure. */JSJavaThreadState *jsj_enter_js(JNIEnv *jEnv, void* applet_obj, jobject java_wrapper_obj, JSContext **cxp, JSObject **js_objp, JSErrorReporter *old_error_reporterp, void **pNSIPrincipaArray, int numPrincipals, void *pNSISecurityContext){ JSContext *cx; char *err_msg; JSObject *js_obj; JSJavaThreadState *jsj_env; cx = NULL; err_msg = NULL; /* Invoke callback, presumably used to implement concurrency constraints */ if (JSJ_callbacks && JSJ_callbacks->enter_js_from_java) {#ifdef OJI if (!JSJ_callbacks->enter_js_from_java(jEnv, &err_msg, pNSIPrincipaArray, numPrincipals, pNSISecurityContext,applet_obj))#else if (!JSJ_callbacks->enter_js_from_java(jEnv, &err_msg))#endif goto entry_failure; } /* Check the JSObject pointer in the wrapper object. */ if (js_objp) {#ifdef PRESERVE_JSOBJECT_IDENTITY#if JS_BYTES_PER_LONG == 8 js_obj = (JSObject *)((*jEnv)->GetLongField(jEnv, java_wrapper_obj, njJSObject_long_internal));#else js_obj = (JSObject *)((*jEnv)->GetIntField(jEnv, java_wrapper_obj, njJSObject_internal));#endif#else /* !PRESERVE_JSOBJECT_IDENTITY */ js_obj = jsj_UnwrapJSObjectWrapper(jEnv, java_wrapper_obj);#endif /* PRESERVE_JSOBJECT_IDENTITY */ JS_ASSERT(js_obj); if (!js_obj) goto error; *js_objp = js_obj; } /* Get the per-thread state corresponding to the current Java thread */ jsj_env = jsj_MapJavaThreadToJSJavaThreadState(jEnv, &err_msg); if (!jsj_env) goto error; /* 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 && JSJ_callbacks->map_jsj_thread_to_js_context) {#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 { err_msg = JS_smprintf("Unable to find/create JavaScript execution " "context for JNI thread 0x%08x", jEnv); goto error; } } *cxp = cx; /* * Capture all JS error reports so that they can be thrown into the Java * caller as an instance of netscape.javascript.JSException. */ *old_error_reporterp = JS_SetErrorReporter(cx, capture_js_error_reports_for_java);#ifdef JSJ_THREADSAFE JS_BeginRequest(cx);#endif return jsj_env;error: /* Invoke callback, presumably used to implement concurrency constraints */ if (JSJ_callbacks && JSJ_callbacks->exit_js) JSJ_callbacks->exit_js(jEnv, cx);entry_failure: if (err_msg) { if (cx) JS_ReportError(cx, err_msg); else jsj_LogError(err_msg); free(err_msg); } return NULL;}/* * This utility function is called just prior to returning into Java from JS. */JSBooljsj_exit_js(JSContext *cx, JSJavaThreadState *jsj_env, JSErrorReporter original_reporter){ JNIEnv *jEnv;#ifdef JSJ_THREADSAFE JS_EndRequest(cx);#endif /* Restore the JS error reporter */ JS_SetErrorReporter(cx, original_reporter); jEnv = jsj_env->jEnv;#ifdef DEBUG /* Any Java exceptions should have been noticed and reported already */ if ((*jEnv)->ExceptionOccurred(jEnv)) { JS_ASSERT(0); jsj_LogError("Unhandled Java exception detected"); return JS_FALSE; }#endif /* * Convert reported JS errors to JSExceptions, unless the errors were * themselves the result of Java exceptions, in which case the original * Java exception is simply propagated. */ throw_any_pending_js_error_as_a_java_exception(jsj_env); /* Invoke callback, presumably used to implement concurrency constraints */ if (JSJ_callbacks && JSJ_callbacks->exit_js) JSJ_callbacks->exit_js(jEnv, cx); return JS_TRUE;}/* Get the JavaClassDescriptor that corresponds to java.lang.Object */JavaClassDescriptor *jsj_get_jlObject_descriptor(JSContext *cx, JNIEnv *jEnv){ /* The JavaClassDescriptor for java.lang.Object */ static JavaClassDescriptor *jlObject_descriptor = NULL; if (!jlObject_descriptor) jlObject_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, jlObject); return jlObject_descriptor;}/****************** Implementation of methods of JSObject *******************//* * Class: netscape_javascript_JSObject * Method: initClass * Signature: ()V */JNIEXPORT void JNICALLJava_netscape_javascript_JSObject_initClass(JNIEnv *jEnv, jclass java_class){ jsj_init_js_obj_reflections_table();}/* * Class: netscape_javascript_JSObject * Method: getMember * Signature: (Ljava/lang/String;)Ljava/lang/Object; */JNIEXPORT jobject JNICALLJava_netscape_javascript_JSObject_getMember(JNIEnv *jEnv, jobject java_wrapper_obj, jstring property_name_jstr){ JSContext *cx = NULL; JSObject *js_obj; jsval js_val; int dummy_cost; JSBool dummy_bool; const jchar *property_name_ucs2; jsize property_name_len; JSErrorReporter saved_reporter; jobject member; jboolean is_copy; JSJavaThreadState *jsj_env; jsj_env = jsj_enter_js(jEnv, NULL, java_wrapper_obj, &cx, &js_obj, &saved_reporter, NULL, 0, NULL); if (!jsj_env) return NULL; property_name_ucs2 = NULL; if (!property_name_jstr) { JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, JSJMSG_NULL_MEMBER_NAME); member = NULL; goto done; } /* Get the Unicode string for the JS property name */ property_name_ucs2 = (*jEnv)->GetStringChars(jEnv, property_name_jstr, &is_copy); if (!property_name_ucs2) { JS_ASSERT(0); goto done; } property_name_len = (*jEnv)->GetStringLength(jEnv, property_name_jstr); if (!JS_GetUCProperty(cx, js_obj, property_name_ucs2, property_name_len, &js_val)) goto done; jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, jsj_get_jlObject_descriptor(cx, jEnv), &dummy_cost, &member, &dummy_bool);done: if (property_name_ucs2) (*jEnv)->ReleaseStringChars(jEnv, property_name_jstr, property_name_ucs2); if (!jsj_exit_js(cx, jsj_env, saved_reporter)) return NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -