📄 jsj_method.c
字号:
if (lowest_cost != 0) return NULL; return best_method_match;}#else /* !OLD_STYLE_METHOD_RESOLUTION *//* * Determine the more natural (preferred) JavaScript->Java conversion * given one JavaScript value and two Java types. * See http://www.mozilla.org/js/liveconnect/lc3_method_overloading.html * for details. */static JSJTypePreferencepreferred_conversion(JSContext *cx, JNIEnv *jEnv, jsval js_val, JavaClassDescriptor *descriptor1, JavaClassDescriptor *descriptor2){ JSJType js_type; int rank1, rank2; jclass java_class1, java_class2; JavaObjectWrapper *java_wrapper; jobject java_obj; JSObject *js_obj; 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 (rank2 == 0) { java_class1 = descriptor1->java_class; java_class2 = descriptor2->java_class; js_obj = JSVAL_TO_OBJECT(js_val); java_wrapper = JS_GetPrivate(cx, js_obj); java_obj = java_wrapper->java_obj; /* Unwrapped JavaObject must be compatible with Java arg type */ if (!(*jEnv)->IsInstanceOf(jEnv, java_obj, java_class2)) return JSJPREF_FIRST_ARG; /* * For JavaObject arguments, any compatible reference type is preferable * to any primitive Java type or to java.lang.String. */ if (rank1 != 0) return JSJPREF_SECOND_ARG; /* * If argument of type descriptor1 is subclass of type descriptor 2, then * descriptor1 is preferred and vice-versa. */ if ((*jEnv)->IsAssignableFrom(jEnv, java_class1, java_class2)) return JSJPREF_FIRST_ARG; if ((*jEnv)->IsAssignableFrom(jEnv, java_class2, java_class1)) return JSJPREF_SECOND_ARG; /* This can happen in unusual situations involving interface types. */ return JSJPREF_AMBIGUOUS; } if (rank1 > rank2) return JSJPREF_SECOND_ARG; return JSJPREF_AMBIGUOUS;} static JSJTypePreferencemethod_preferred(JSContext *cx, JNIEnv *jEnv, jsval *argv, JavaMethodSignature *method_signature1, JavaMethodSignature *method_signature2){ int arg_index, argc, preference; jsval val; JavaSignature* *arg_signatures1; JavaSignature* *arg_signatures2; JavaSignature *arg_type1, *arg_type2; arg_signatures1 = method_signature1->arg_signatures; arg_signatures2 = method_signature2->arg_signatures; argc = method_signature1->num_args; JS_ASSERT(argc == method_signature2->num_args); preference = 0; for (arg_index = 0; arg_index < argc; arg_index++) { val = argv[arg_index]; arg_type1 = *arg_signatures1++; arg_type2 = *arg_signatures2++; if (arg_type1 == arg_type2) continue; preference |= preferred_conversion(cx, jEnv, val, arg_type1, arg_type2); if ((JSJTypePreference)preference == JSJPREF_AMBIGUOUS) return JSJPREF_AMBIGUOUS; } return (JSJTypePreference)preference;}/* * This routine applies heuristics to guess the intended Java method given the * runtime JavaScript argument types and the type signatures of the candidate * methods. Informally, the method with Java parameter types that most closely * match the JavaScript types is chosen. A more precise specification is * provided in the lc3_method_resolution.html file. The code uses a very * brute-force approach. */static JavaMethodSpec *resolve_overloaded_method(JSContext *cx, JNIEnv *jEnv, JavaMemberDescriptor *member_descriptor, JavaClassDescriptor *class_descriptor, JSBool is_static_method, uintN argc, jsval *argv){ JSJTypePreference preference; JavaMethodSpec *method, *best_method_match; MethodList ambiguous_methods; MethodListElement *method_list_element, *next_element; /* * Determine the first Java method among the overloaded methods of the same name * that matches all the JS arguments. */ for (method = member_descriptor->methods; method; method = method->next) { if (method_signature_matches_JS_args(cx, jEnv, argc, argv, &method->signature)) break; } /* Report an error if no method matched the JS arguments */ if (!method) { report_method_match_failure(cx, member_descriptor, class_descriptor, is_static_method, argc, argv); return NULL; } /* Shortcut a common case */ if (!method->next) return method; /* * Form a list of all methods that are neither more or less preferred than the * best matching method discovered so far. */ JS_INIT_CLIST(&ambiguous_methods); best_method_match = method; /* See if there are any Java methods that are a better fit for the JS args */ for (method = method->next; method; method = method->next) { if (method->signature.num_args != (int)argc) continue; preference = method_preferred(cx, jEnv, argv, &best_method_match->signature, &method->signature); if (preference == JSJPREF_SECOND_ARG) { best_method_match = method; } else if (preference == JSJPREF_AMBIGUOUS) { /* Add this method to the list of ambiguous methods */ method_list_element = (MethodListElement*)JS_malloc(cx, sizeof(MethodListElement)); if (!method_list_element) goto error; method_list_element->method = method; JS_APPEND_LINK(&method_list_element->linkage, &ambiguous_methods); } } /* * Ensure that best_method_match is preferred to all methods on the * ambiguous_methods list. */ for (method_list_element = (MethodListElement*)JS_LIST_HEAD(&ambiguous_methods); (MethodList*)method_list_element != &ambiguous_methods; method_list_element = next_element) { next_element = (MethodListElement*)method_list_element->linkage.next; method = method_list_element->method; preference = method_preferred(cx, jEnv, argv, &best_method_match->signature, &method->signature); if (preference != JSJPREF_FIRST_ARG) continue; JS_REMOVE_LINK(&method_list_element->linkage); JS_free(cx, method_list_element); } /* * The chosen method must be maximally preferred, i.e. there can be no other * method that is just as preferred. */ if (!JS_CLIST_IS_EMPTY(&ambiguous_methods)) { /* Add the best_method_match to the list of ambiguous methods */ method_list_element = (MethodListElement*)JS_malloc(cx, sizeof(MethodListElement)); if (!method_list_element) goto error; method_list_element->method = best_method_match; JS_APPEND_LINK(&method_list_element->linkage, &ambiguous_methods); /* Report the problem */ report_ambiguous_method_match(cx, member_descriptor, class_descriptor, &ambiguous_methods, is_static_method, argc, argv); goto error; } return best_method_match;error: /* Delete the storage for the ambiguous_method list */ while (!JS_CLIST_IS_EMPTY(&ambiguous_methods)) { method_list_element = (MethodListElement*)JS_LIST_HEAD(&ambiguous_methods); JS_REMOVE_LINK(&method_list_element->linkage); JS_free(cx, method_list_element); } return NULL;}#endif /* !HAS_OLD_STYLE_METHOD_RESOLUTION */static jvalue *convert_JS_method_args_to_java_argv(JSContext *cx, JNIEnv *jEnv, jsval *argv, JavaMethodSpec *method, JSBool **localvp){ jvalue *jargv; JSBool ok, *localv; uintN i, argc; JavaSignature **arg_signatures; JavaMethodSignature *signature; signature = &method->signature; argc = signature->num_args; JS_ASSERT(argc != 0); arg_signatures = signature->arg_signatures; jargv = (jvalue *)JS_malloc(cx, sizeof(jvalue) * argc); if (!jargv) return NULL; /* * Allocate an array that contains a flag for each argument, indicating whether * or not the conversion from a JS value to a Java value resulted in a new * JNI local reference. */ localv = (JSBool *)JS_malloc(cx, sizeof(JSBool) * argc); *localvp = localv; if (!localv) { JS_free(cx, jargv); return NULL; } for (i = 0; i < argc; i++) { int dummy_cost; ok = jsj_ConvertJSValueToJavaValue(cx, jEnv, argv[i], arg_signatures[i], &dummy_cost, &jargv[i], &localv[i]); if (!ok) { JS_free(cx, jargv); JS_free(cx, localv); *localvp = NULL; return NULL; } } return jargv;} static JSBoolinvoke_java_method(JSContext *cx, JSJavaThreadState *jsj_env, jobject java_class_or_instance, JavaClassDescriptor *class_descriptor, JavaMethodSpec *method, JSBool is_static_method, jsval *argv, jsval *vp){ jvalue java_value; jvalue *jargv; uintN argc, i; jobject java_object; jclass java_class; jmethodID methodID; JavaMethodSignature *signature; JavaSignature *return_val_signature; JNIEnv *jEnv; JSBool *localv, error_occurred, success; success = error_occurred = JS_FALSE; return_val_signature = NULL; /* Quiet gcc uninitialized variable warning */ methodID = method->methodID; signature = &method->signature; argc = signature->num_args; jEnv = jsj_env->jEnv; if (is_static_method) { java_object = NULL; java_class = java_class_or_instance; } else { java_object = java_class_or_instance; java_class = NULL; } jargv = NULL; localv = NULL; if (argc) { jargv = convert_JS_method_args_to_java_argv(cx, jEnv, argv, method, &localv); if (!jargv) { error_occurred = JS_TRUE; goto out; } } /* 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) { \ java_value.member = (*jEnv)->CallStatic##type##MethodA(jEnv, java_class, methodID, jargv);\ } else { \ java_value.member = (*jEnv)->Call##type##MethodA(jEnv, java_object, methodID, jargv);\ } \ if ((*jEnv)->ExceptionOccurred(jEnv)) { \ jsj_ReportJavaError(cx, jEnv, "Error calling method %s.%s()", \ class_descriptor->name, method->name); \ error_occurred = JS_TRUE; \ goto out; \ } \ JS_END_MACRO return_val_signature = signature->return_val_signature; switch(return_val_signature->type) { case JAVA_SIGNATURE_BYTE: CALL_JAVA_METHOD(Byte, b); break; case JAVA_SIGNATURE_CHAR: CALL_JAVA_METHOD(Char, c); break; case JAVA_SIGNATURE_FLOAT: CALL_JAVA_METHOD(Float, f); break; case JAVA_SIGNATURE_DOUBLE: CALL_JAVA_METHOD(Double, d); break; case JAVA_SIGNATURE_INT: CALL_JAVA_METHOD(Int, i);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -