Back to index

lightning-sunbird  0.9+nobinonly
jsj_method.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is Mozilla Communicator client code, released
00017  * March 31, 1998.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Netscape Communications Corporation.
00021  * Portions created by the Initial Developer are Copyright (C) 1998
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * This Original Code has been modified by IBM Corporation. Modifications made
00039  * by IBM described herein are Copyright (c) International Business Machines
00040  * Corporation, 2000.
00041  * Modifications to Mozilla code or documentation identified per MPL Section 3.3
00042  *
00043  * Date             Modified by     Description of modification
00044  * 04/20/2000       IBM Corp.      OS/2 VisualAge build.
00045  *
00046  * ***** END LICENSE BLOCK ***** */
00047 
00048 /*
00049  * This file is part of the Java-vendor-neutral implementation of LiveConnect
00050  *
00051  * It contains the code used to reflect Java methods as properties of
00052  * JavaObject objects and the code to invoke those methods.
00053  *
00054  */
00055 
00056 #include <stdlib.h>
00057 #include <string.h>
00058 
00059 #include "jsj_private.h"        /* LiveConnect internals */
00060 #include "jsjava.h"             /* LiveConnect external API */
00061 #include "jsclist.h"            /* Circular linked lists */
00062 
00063 /* A list of Java methods */
00064 typedef JSCList MethodList;
00065 
00066 /* An element in a list of Java methods */
00067 typedef struct MethodListElement {
00068     JSCList linkage;
00069     JavaMethodSpec *method;
00070 } MethodListElement;
00071 
00072 /*
00073  * This is the return value of functions which compare either two types or two
00074  * method signatures to see if either is "preferred" when converting from
00075  * specified JavaScript value(s).
00076  */
00077 typedef enum JSJTypePreference {
00078     JSJPREF_FIRST_ARG  = 1,       /* First argument preferred */
00079     JSJPREF_SECOND_ARG = 2,       /* Second argument preferred */
00080     JSJPREF_AMBIGUOUS  = 3        /* Neither preferred over the other */
00081 } JSJTypePreference;
00082 
00083 /*
00084  * Classification of JS types with slightly different granularity than JSType.
00085  * This is used to resolve among overloaded Java methods.
00086  */
00087 typedef enum JSJType {
00088     JSJTYPE_VOID,                /* undefined */
00089     JSJTYPE_BOOLEAN,             /* boolean */
00090     JSJTYPE_NUMBER,              /* number */
00091     JSJTYPE_STRING,              /* string */
00092     JSJTYPE_NULL,                /* null */
00093     JSJTYPE_JAVACLASS,           /* JavaClass */
00094     JSJTYPE_JAVAOBJECT,          /* JavaObject */
00095     JSJTYPE_JAVAARRAY,              /* JavaArray */
00096     JSJTYPE_JSARRAY,             /* JS Array */
00097     JSJTYPE_OBJECT,              /* Any other JS Object, including functions */
00098     JSJTYPE_LIMIT
00099 } JSJType;
00100 
00101 /*
00102  * A helper function for jsj_ConvertJavaMethodSignatureToString():
00103  * Compute JNI-style (string) signatures for an array of JavaSignature objects
00104  * and concatenate the results into a single string.
00105  *
00106  * If an error is encountered, NULL is returned and the error reporter is called.
00107  */
00108 static const char *
00109 convert_java_method_arg_signatures_to_string(JSContext *cx,
00110                                              JavaSignature **arg_signatures,
00111                                              int num_args)
00112 {
00113     const char *first_arg_signature, *rest_arg_signatures, *sig;
00114     JavaSignature **rest_args;
00115 
00116     /* Convert the first method argument in the array to a string */
00117     first_arg_signature = jsj_ConvertJavaSignatureToString(cx, arg_signatures[0]);
00118     if (!first_arg_signature)
00119         return NULL;
00120 
00121     /* If this is the last method argument in the array, we're done. */
00122     if (num_args == 1)
00123         return first_arg_signature;
00124 
00125     /* Convert the remaining method arguments to a string */
00126     rest_args = &arg_signatures[1];
00127     rest_arg_signatures =
00128         convert_java_method_arg_signatures_to_string(cx, rest_args, num_args - 1);
00129     if (!rest_arg_signatures) {
00130         free((void*)first_arg_signature);
00131         return NULL;
00132     }
00133 
00134     /* Concatenate the signature string of this argument with the signature
00135        strings of all the remaining arguments. */
00136     sig = JS_smprintf("%s%s", first_arg_signature, rest_arg_signatures);
00137     free((void*)first_arg_signature);
00138     free((void*)rest_arg_signatures);
00139     if (!sig) {
00140         JS_ReportOutOfMemory(cx);
00141         return NULL;
00142     }
00143 
00144     return sig;
00145 }
00146 
00147 /*
00148  * A helper function for jsj_ConvertJavaMethodSignatureToHRString():
00149  * Compute human-readable string signatures for an array of JavaSignatures
00150  * and concatenate the results into a single string.
00151  *
00152  * If an error is encountered, NULL is returned and the error reporter is called.
00153  */
00154 static const char *
00155 convert_java_method_arg_signatures_to_hr_string(JSContext *cx,
00156                                                 JavaSignature **arg_signatures,
00157                                                 int num_args,
00158                                           JSBool whitespace)
00159 {
00160     const char *first_arg_signature, *rest_arg_signatures, *sig, *separator;
00161     JavaSignature **rest_args;
00162 
00163     if (num_args == 0)
00164         return strdup("");
00165 
00166     /* Convert the first method argument in the array to a string */
00167     first_arg_signature = jsj_ConvertJavaSignatureToHRString(cx, arg_signatures[0]);
00168     if (!first_arg_signature)
00169         return NULL;
00170 
00171     /* If this is the last method argument in the array, we're done. */
00172     if (num_args == 1)
00173         return first_arg_signature;
00174 
00175     /* Convert the remaining method arguments to a string */
00176     rest_args = &arg_signatures[1];
00177     rest_arg_signatures =
00178         convert_java_method_arg_signatures_to_hr_string(cx, rest_args, num_args - 1, whitespace);
00179     if (!rest_arg_signatures) {
00180         free((void*)first_arg_signature);
00181         return NULL;
00182     }
00183 
00184     /* Concatenate the signature string of this argument with the signature
00185        strings of all the remaining arguments. */
00186     separator = whitespace ? " " : "";
00187     sig = JS_smprintf("%s,%s%s", first_arg_signature, separator, rest_arg_signatures);
00188     free((void*)first_arg_signature);
00189     free((void*)rest_arg_signatures);
00190     if (!sig) {
00191         JS_ReportOutOfMemory(cx);
00192         return NULL;
00193     }
00194 
00195     return sig;
00196 }
00197 /*
00198  * Compute a string signature for the given method using the same type names
00199  * that appear in Java source files, e.g. "int[][]", rather than the JNI-style
00200  * type strings that are provided by the functions above.  An example return
00201  * value might be "String MyFunc(int, byte, char[][], java.lang.String)".
00202  *
00203  * If an error is encountered, NULL is returned and the error reporter is called.
00204  */
00205 const char *
00206 jsj_ConvertJavaMethodSignatureToHRString(JSContext *cx,
00207                                          const char *method_name,
00208                                          JavaMethodSignature *method_signature)
00209 {
00210     JavaSignature **arg_signatures, *return_val_signature;
00211     const char *arg_sigs_cstr;
00212     const char *return_val_sig_cstr;
00213     const char *sig_cstr;
00214 
00215     arg_signatures = method_signature->arg_signatures;
00216     return_val_signature = method_signature->return_val_signature;
00217 
00218     /* Convert the method argument signatures to a C-string */
00219     arg_sigs_cstr =
00220             convert_java_method_arg_signatures_to_hr_string(cx, arg_signatures,
00221                                                             method_signature->num_args,
00222                                                      JS_TRUE);
00223     if (!arg_sigs_cstr)
00224         return NULL;
00225 
00226     /* Convert the method return value signature to a C-string */
00227     return_val_sig_cstr = jsj_ConvertJavaSignatureToHRString(cx, return_val_signature);
00228     if (!return_val_sig_cstr) {
00229         free((void*)arg_sigs_cstr);
00230         return NULL;
00231     }
00232 
00233     /* Compose method arg signatures string and return val signature string */
00234     sig_cstr = JS_smprintf("%s %s(%s)", return_val_sig_cstr, method_name, arg_sigs_cstr);
00235     free((void*)arg_sigs_cstr);
00236     free((void*)return_val_sig_cstr);
00237 
00238     if (!sig_cstr) {
00239         JS_ReportOutOfMemory(cx);
00240         return NULL;
00241     }
00242     return sig_cstr;
00243 }
00244 /*
00245  * Destroy the sub-structure of a JavaMethodSignature object without free'ing
00246  * the method signature itself.
00247  */
00248 void
00249 jsj_PurgeJavaMethodSignature(JSContext *cx, JNIEnv *jEnv, JavaMethodSignature *method_signature)
00250 {
00251     int i, num_args;
00252     JavaSignature **arg_signatures;
00253 
00254     if (!method_signature)  /* Paranoia */
00255         return;
00256 
00257     /* Free the method argument signatures */
00258     num_args = method_signature->num_args;
00259     arg_signatures = method_signature->arg_signatures;
00260     for (i = 0; i < num_args; i++)
00261         jsj_ReleaseJavaClassDescriptor(cx, jEnv, arg_signatures[i]);
00262     if (arg_signatures)
00263         JS_free(cx, arg_signatures);
00264 
00265     /* Free the return type signature */
00266     if (method_signature->return_val_signature)
00267         jsj_ReleaseJavaClassDescriptor(cx, jEnv, method_signature->return_val_signature);
00268 }
00269 
00270 /*
00271  * Fill in the members of a JavaMethodSignature object using the method
00272  * argument, which can be either an instance of either java.lang.reflect.Method
00273  * or java.lang.reflect.Constructor.
00274  *
00275  * With normal completion, return the original method_signature argument.
00276  * If an error occurs, return NULL and call the error reporter.
00277  */
00278 JavaMethodSignature *
00279 jsj_InitJavaMethodSignature(JSContext *cx, JNIEnv *jEnv,
00280                            jobject method,
00281                            JavaMethodSignature *method_signature)
00282 {
00283     int i;
00284     jboolean is_constructor;
00285     jclass return_val_class;
00286     jsize num_args;
00287     JavaSignature *return_val_signature;
00288     jarray arg_classes;
00289     jmethodID getParameterTypes;
00290 
00291     memset(method_signature, 0, sizeof (JavaMethodSignature));
00292     
00293     is_constructor = (*jEnv)->IsInstanceOf(jEnv, method, jlrConstructor);
00294 
00295     /* Get a Java array that lists the class of each of the method's arguments */
00296     if  (is_constructor)
00297         getParameterTypes = jlrConstructor_getParameterTypes;
00298     else
00299         getParameterTypes = jlrMethod_getParameterTypes;
00300     arg_classes = (*jEnv)->CallObjectMethod(jEnv, method, getParameterTypes);
00301     if (!arg_classes) {
00302         jsj_UnexpectedJavaError(cx, jEnv,
00303                                 "Can't determine argument signature of method");
00304         goto error;
00305     }
00306 
00307     /* Compute the number of method arguments */
00308     num_args = jsj_GetJavaArrayLength(cx, jEnv, arg_classes);
00309     if (num_args < 0)
00310         goto error;
00311     method_signature->num_args = num_args;
00312 
00313     /* Build a JavaSignature array corresponding to the method's arguments */
00314     if (num_args) {
00315         JavaSignature **arg_signatures;
00316 
00317         /* Allocate an array of JavaSignatures, one for each method argument */
00318         size_t arg_signatures_size = num_args * sizeof(JavaSignature *);
00319         arg_signatures = (JavaSignature **)JS_malloc(cx, arg_signatures_size);
00320         if (!arg_signatures)
00321             goto error;
00322         memset(arg_signatures, 0, arg_signatures_size);
00323         method_signature->arg_signatures = arg_signatures;
00324         
00325         /* Build an array of JavaSignature objects, each of which corresponds
00326            to the type of an individual method argument. */
00327         for (i = 0; i < num_args; i++) {
00328             JavaSignature *a;
00329             jclass arg_class = (*jEnv)->GetObjectArrayElement(jEnv, arg_classes, i);
00330             
00331             a = arg_signatures[i] = jsj_GetJavaClassDescriptor(cx, jEnv, arg_class);
00332             (*jEnv)->DeleteLocalRef(jEnv, arg_class);
00333             if (!a) {
00334                 jsj_UnexpectedJavaError(cx, jEnv, "Could not determine Java class "
00335                                                   "signature using java.lang.reflect");
00336                 goto error;
00337             }
00338         }
00339     }
00340 
00341     /* Get the Java class of the method's return value */
00342     if (is_constructor) {
00343         /* Constructors always have a "void" return type */
00344         return_val_signature = jsj_GetJavaClassDescriptor(cx, jEnv, jlVoid_TYPE);
00345     } else {
00346         return_val_class =
00347             (*jEnv)->CallObjectMethod(jEnv, method, jlrMethod_getReturnType);
00348         if (!return_val_class) {
00349             jsj_UnexpectedJavaError(cx, jEnv,
00350                                     "Can't determine return type of method "
00351                                     "using java.lang.reflect.Method.getReturnType()");
00352             goto error;
00353         }
00354 
00355         /* Build a JavaSignature object corresponding to the method's return value */
00356         return_val_signature = jsj_GetJavaClassDescriptor(cx, jEnv, return_val_class);
00357         (*jEnv)->DeleteLocalRef(jEnv, return_val_class);
00358     }
00359 
00360     if (!return_val_signature)
00361         goto error;
00362     method_signature->return_val_signature = return_val_signature;
00363 
00364     (*jEnv)->DeleteLocalRef(jEnv, arg_classes);
00365     return method_signature;
00366 
00367 error:
00368 
00369     if (arg_classes)
00370         (*jEnv)->DeleteLocalRef(jEnv, arg_classes);
00371     jsj_PurgeJavaMethodSignature(cx, jEnv, method_signature);
00372     return NULL;
00373 }
00374 
00375 /*
00376  * Compute a JNI-style (string) signature for the given method, e.g. the method
00377  * "String MyFunc(int, byte)" is translated to "(IB)Ljava/lang/String;".
00378  *
00379  * If an error is encountered, NULL is returned and the error reporter is called.
00380  */
00381 const char *
00382 jsj_ConvertJavaMethodSignatureToString(JSContext *cx,
00383                                        JavaMethodSignature *method_signature)
00384 {
00385     JavaSignature **arg_signatures, *return_val_signature;
00386     const char *arg_sigs_cstr;
00387     const char *return_val_sig_cstr;
00388     const char *sig_cstr;
00389 
00390     arg_signatures = method_signature->arg_signatures;
00391     return_val_signature = method_signature->return_val_signature;
00392 
00393     /* Convert the method argument signatures to a C-string */
00394     arg_sigs_cstr = NULL;
00395     if (arg_signatures) {
00396         arg_sigs_cstr =
00397             convert_java_method_arg_signatures_to_string(cx, arg_signatures,
00398                                                          method_signature->num_args);
00399         if (!arg_sigs_cstr)
00400             return NULL;
00401     }
00402 
00403     /* Convert the method return value signature to a C-string */
00404     return_val_sig_cstr = jsj_ConvertJavaSignatureToString(cx, return_val_signature);
00405     if (!return_val_sig_cstr) {
00406         free((void*)arg_sigs_cstr);
00407         return NULL;
00408     }
00409 
00410     /* Compose method arg signatures string and return val signature string */
00411     if (arg_sigs_cstr) {
00412         sig_cstr = JS_smprintf("(%s)%s", arg_sigs_cstr, return_val_sig_cstr);
00413         free((void*)arg_sigs_cstr);
00414     } else {
00415         sig_cstr = JS_smprintf("()%s", return_val_sig_cstr);
00416     }
00417 
00418     free((void*)return_val_sig_cstr);
00419 
00420     if (!sig_cstr) {
00421         JS_ReportOutOfMemory(cx);
00422         return NULL;
00423     }
00424     return sig_cstr;
00425 }
00426 
00427 static JSBool
00428 add_java_method_to_class_descriptor(JSContext *cx, JNIEnv *jEnv,
00429                                     JavaClassDescriptor *class_descriptor, 
00430                                     jstring method_name_jstr,
00431                                     jobject java_method,
00432                                     JSBool is_static_method,
00433                                     JSBool is_constructor)
00434 {
00435     jmethodID methodID;
00436     JSFunction *fun;
00437     jclass java_class = class_descriptor->java_class;
00438 
00439     JavaMemberDescriptor *member_descriptor = NULL;
00440     const char *sig_cstr = NULL;
00441     const char *method_name = NULL;
00442     JavaMethodSignature *signature = NULL;
00443     JavaMethodSpec **specp, *method_spec = NULL;
00444             
00445     if (is_constructor) {
00446         member_descriptor = jsj_GetJavaClassConstructors(cx, class_descriptor);
00447     } else {
00448         if (is_static_method) {
00449             member_descriptor = jsj_GetJavaStaticMemberDescriptor(cx, jEnv, class_descriptor, method_name_jstr);
00450         } else {
00451             member_descriptor = jsj_GetJavaMemberDescriptor(cx, jEnv, class_descriptor, method_name_jstr);
00452        }
00453         fun = JS_NewFunction(cx, jsj_JavaInstanceMethodWrapper, 0,
00454                             JSFUN_BOUND_METHOD, NULL, member_descriptor->name);
00455        member_descriptor->invoke_func_obj = JS_GetFunctionObject(fun);
00456         JS_AddNamedRoot(cx, &member_descriptor->invoke_func_obj,
00457                         "&member_descriptor->invoke_func_obj");
00458     }
00459     if (!member_descriptor)
00460         return JS_FALSE;
00461     
00462     method_spec = (JavaMethodSpec*)JS_malloc(cx, sizeof(JavaMethodSpec));
00463     if (!method_spec)
00464         goto error;
00465     memset(method_spec, 0, sizeof(JavaMethodSpec));
00466 
00467     signature = jsj_InitJavaMethodSignature(cx, jEnv, java_method, &method_spec->signature);
00468     if (!signature)
00469         goto error;
00470 
00471     method_name = JS_strdup(cx, member_descriptor->name);
00472     if (!method_name)
00473         goto error;
00474     method_spec->name = method_name;
00475     
00476     sig_cstr = jsj_ConvertJavaMethodSignatureToString(cx, signature);
00477     if (!sig_cstr)
00478         goto error;
00479 
00480     if (is_static_method)
00481         methodID = (*jEnv)->GetStaticMethodID(jEnv, java_class, method_name, sig_cstr);
00482     else
00483         methodID = (*jEnv)->GetMethodID(jEnv, java_class, method_name, sig_cstr);
00484     method_spec->methodID = methodID;
00485     
00486     if (!methodID) {
00487         jsj_UnexpectedJavaError(cx, jEnv,
00488                                 "Can't get Java method ID for %s.%s() (sig=%s)",
00489                                 class_descriptor->name, method_name, sig_cstr);
00490         goto error;
00491     }
00492     
00493     JS_free(cx, (char*)sig_cstr);
00494 
00495     /* Add method to end of list of overloaded methods for this class member */ 
00496     specp = &member_descriptor->methods;
00497     while (*specp) {
00498         specp = &(*specp)->next;
00499     }
00500     *specp = method_spec;
00501 
00502     return JS_TRUE;
00503 
00504 error:
00505     if (method_spec)
00506         JS_FREE_IF(cx, (char*)method_spec->name);
00507     JS_FREE_IF(cx, (char*)sig_cstr);
00508     if (signature)
00509         jsj_PurgeJavaMethodSignature(cx, jEnv, signature);
00510     JS_FREE_IF(cx, method_spec);
00511     return JS_FALSE;
00512 }
00513 
00514 JSBool 
00515 jsj_ReflectJavaMethods(JSContext *cx, JNIEnv *jEnv,
00516                        JavaClassDescriptor *class_descriptor,
00517                        JSBool reflect_only_static_methods)
00518 {
00519     jarray joMethodArray, joConstructorArray;
00520     jsize num_methods, num_constructors;
00521     int i;
00522     jclass java_class;
00523     JSBool ok, reflect_only_instance_methods;
00524 
00525     reflect_only_instance_methods = !reflect_only_static_methods;
00526 
00527     /* Get a java array of java.lang.reflect.Method objects, by calling
00528        java.lang.Class.getMethods(). */
00529     java_class = class_descriptor->java_class;
00530     joMethodArray = (*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getMethods);
00531     if (!joMethodArray) {
00532         jsj_UnexpectedJavaError(cx, jEnv,
00533                                 "Can't determine Java object's methods "
00534                                 "using java.lang.Class.getMethods()");
00535         return JS_FALSE;
00536     }
00537 
00538     /* Iterate over the class methods */
00539     num_methods = (*jEnv)->GetArrayLength(jEnv, joMethodArray);
00540     for (i = 0; i < num_methods; i++) {
00541         jstring method_name_jstr;
00542         
00543         /* Get the i'th reflected method */
00544         jobject java_method = (*jEnv)->GetObjectArrayElement(jEnv, joMethodArray, i);
00545 
00546         /* Get the method modifiers, eg static, public, private, etc. */
00547         jint modifiers = (*jEnv)->CallIntMethod(jEnv, java_method, jlrMethod_getModifiers);
00548 
00549         /* Don't allow access to private or protected Java methods. */
00550         if (!(modifiers & ACC_PUBLIC))
00551             goto dont_reflect_method;
00552 
00553         /* Abstract methods can't be invoked */
00554         if (modifiers & ACC_ABSTRACT)
00555             goto dont_reflect_method;
00556 
00557         /* Reflect all instance methods or all static methods, but not both */
00558         if (reflect_only_static_methods != ((modifiers & ACC_STATIC) != 0))
00559             goto dont_reflect_method;
00560         
00561         /* Add a JavaMethodSpec object to the JavaClassDescriptor */
00562         method_name_jstr = (*jEnv)->CallObjectMethod(jEnv, java_method, jlrMethod_getName);
00563         ok = add_java_method_to_class_descriptor(cx, jEnv, class_descriptor, method_name_jstr, java_method,
00564                                                  reflect_only_static_methods, JS_FALSE);
00565         (*jEnv)->DeleteLocalRef(jEnv, method_name_jstr);
00566         if (!ok) {
00567             (*jEnv)->DeleteLocalRef(jEnv, java_method);
00568             (*jEnv)->DeleteLocalRef(jEnv, joMethodArray);
00569             return JS_FALSE;
00570         }
00571 
00572 dont_reflect_method:
00573         (*jEnv)->DeleteLocalRef(jEnv, java_method);
00574     }
00575 
00576     (*jEnv)->DeleteLocalRef(jEnv, joMethodArray);
00577     if (reflect_only_instance_methods)
00578         return JS_TRUE;
00579         
00580     joConstructorArray = (*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getConstructors);
00581     if (!joConstructorArray) {
00582         jsj_UnexpectedJavaError(cx, jEnv, "internal error: "
00583                                 "Can't determine Java class's constructors "
00584                                 "using java.lang.Class.getConstructors()");
00585         return JS_FALSE;
00586     }
00587 
00588     /* Iterate over the class constructors */
00589     num_constructors = (*jEnv)->GetArrayLength(jEnv, joConstructorArray);
00590     for (i = 0; i < num_constructors; i++) {
00591         /* Get the i'th reflected constructor */
00592         jobject java_constructor =
00593             (*jEnv)->GetObjectArrayElement(jEnv, joConstructorArray, i);
00594 
00595         /* Get the method modifiers, eg public, private, etc. */
00596         jint modifiers = (*jEnv)->CallIntMethod(jEnv, java_constructor,
00597                                                 jlrConstructor_getModifiers);
00598 
00599         /* Don't allow access to private or protected Java methods. */
00600         if (!(modifiers & ACC_PUBLIC))
00601             goto dont_reflect_constructor;
00602         
00603         /* Add a JavaMethodSpec object to the JavaClassDescriptor */
00604         ok = add_java_method_to_class_descriptor(cx, jEnv, class_descriptor, NULL,
00605                                                  java_constructor,
00606                                                  JS_FALSE, JS_TRUE);
00607         if (!ok) {
00608             (*jEnv)->DeleteLocalRef(jEnv, joConstructorArray);
00609             (*jEnv)->DeleteLocalRef(jEnv, java_constructor);
00610             return JS_FALSE;
00611         }
00612 
00613 dont_reflect_constructor:
00614         (*jEnv)->DeleteLocalRef(jEnv, java_constructor);
00615     }
00616 
00617     (*jEnv)->DeleteLocalRef(jEnv, joConstructorArray);
00618     return JS_TRUE;
00619 }
00620 
00621 /*
00622  * Free up a JavaMethodSpec and all its resources.
00623  */
00624 void
00625 jsj_DestroyMethodSpec(JSContext *cx, JNIEnv *jEnv, JavaMethodSpec *method_spec)
00626 {
00627     if (!method_spec->is_alias) {
00628        JS_FREE_IF(cx, (char*)method_spec->name);
00629        jsj_PurgeJavaMethodSignature(cx, jEnv, &method_spec->signature);
00630     }
00631     JS_free(cx, method_spec);
00632 }
00633 
00634 static JavaMethodSpec *
00635 copy_java_method_descriptor(JSContext *cx, JavaMethodSpec *method)
00636 {
00637     JavaMethodSpec *copy;
00638 
00639     copy = (JavaMethodSpec*)JS_malloc(cx, sizeof(JavaMethodSpec));
00640     if (!copy)
00641         return NULL;
00642     memcpy(copy, method, sizeof(JavaMethodSpec));
00643     copy->next = NULL;
00644     copy->is_alias = JS_TRUE;
00645     return copy;
00646 }
00647 
00648 /*
00649  * See if a reference to a JavaObject/JavaClass's property looks like the
00650  * explicit resolution of an overloaded method, e.g. 
00651  * java.lang.String["max(double,double)"].  If so, add a new member
00652  * (JavaMemberDescriptor) to the object that is an alias for the resolved
00653  * method.
00654  */
00655 JavaMemberDescriptor *
00656 jsj_ResolveExplicitMethod(JSContext *cx, JNIEnv *jEnv,
00657                        JavaClassDescriptor *class_descriptor, 
00658                        jsid method_name_id,
00659                        JSBool is_static)
00660 {
00661     JavaMethodSpec *method;
00662     JavaMemberDescriptor *member_descriptor;
00663     JavaMethodSignature *ms;
00664     JSString *simple_name_jsstr;
00665     JSFunction *fun;
00666     JSBool is_constructor;
00667     int left_paren;
00668     const char *sig_cstr, *method_name;
00669     char *arg_start;
00670     jsid id;
00671     jsval method_name_jsval;
00672       
00673     /*
00674      * Get the simple name of the explicit method, i.e. get "cos" from
00675      * "cos(double)", and use it to create a new JS string.
00676      */
00677     JS_IdToValue(cx, method_name_id, &method_name_jsval);
00678     method_name = JS_GetStringBytes(JSVAL_TO_STRING(method_name_jsval));
00679     arg_start = strchr(method_name, '('); /* Skip until '(' */
00680     /* If no left-paren, then this is not a case of explicit method resolution */
00681     if (!arg_start)
00682        return NULL;
00683     /* Left-paren must be first character for constructors */
00684     is_constructor = (is_static && (arg_start == method_name));
00685         
00686     left_paren = arg_start - method_name;
00687     simple_name_jsstr = JS_NewStringCopyN(cx, method_name, left_paren);
00688     if (!simple_name_jsstr)
00689        return NULL;
00690 
00691     /* Find all the methods in the same class with the same simple name */
00692     JS_ValueToId(cx, STRING_TO_JSVAL(simple_name_jsstr), &id);
00693     if (is_constructor)
00694         member_descriptor = jsj_LookupJavaClassConstructors(cx, jEnv, class_descriptor);
00695     else if (is_static)
00696        member_descriptor = jsj_LookupJavaStaticMemberDescriptorById(cx, jEnv, class_descriptor, id);
00697     else
00698        member_descriptor = jsj_LookupJavaMemberDescriptorById(cx, jEnv, class_descriptor, id);
00699     if (!member_descriptor) /* No member with matching simple name ? */
00700        return NULL;
00701     
00702     /*
00703      * Do a UTF8 comparison of method signatures with all methods of the same name,
00704      * so as to discover a method which exactly matches the specified argument types.
00705      */
00706     if (!strlen(arg_start + 1))
00707        return NULL;
00708     arg_start = JS_strdup(cx, arg_start + 1);
00709     if (!arg_start)
00710        return NULL;
00711     arg_start[strlen(arg_start) - 1] = '\0';     /* Get rid of ')' */
00712     sig_cstr = NULL; /* Quiet gcc warning about uninitialized variable */
00713     for (method = member_descriptor->methods; method; method = method->next) {
00714        ms = &method->signature;
00715        sig_cstr = convert_java_method_arg_signatures_to_hr_string(cx, ms->arg_signatures,
00716                                                            ms->num_args, JS_FALSE);
00717        if (!sig_cstr)
00718            return NULL;
00719 
00720        if (!strcmp(sig_cstr, arg_start))
00721            break;
00722        JS_free(cx, (void*)sig_cstr);
00723     }
00724     JS_free(cx, arg_start);
00725     if (!method)
00726        return NULL;
00727     JS_free(cx, (void*)sig_cstr);
00728     
00729     /* Don't bother doing anything if the method isn't overloaded */
00730     if (!member_descriptor->methods->next)
00731        return member_descriptor;
00732 
00733     /*
00734      * To speed up performance for future accesses, create a new member descriptor
00735      * with a name equal to the explicit method name, i.e. "cos(double)".
00736      */
00737     member_descriptor = JS_malloc(cx, sizeof(JavaMemberDescriptor));
00738     if (!member_descriptor)
00739         return NULL;
00740     memset(member_descriptor, 0, sizeof(JavaMemberDescriptor));
00741 
00742     member_descriptor->id = method_name_id;
00743     member_descriptor->name =
00744         JS_strdup(cx, is_constructor ? "<init>" : JS_GetStringBytes(simple_name_jsstr));
00745     if (!member_descriptor->name) {
00746         JS_free(cx, member_descriptor);
00747         return NULL;
00748     }
00749 
00750     member_descriptor->methods = copy_java_method_descriptor(cx, method);
00751     if (!member_descriptor->methods) {
00752        JS_free(cx, (void*)member_descriptor->name);
00753         JS_free(cx, member_descriptor);
00754         return NULL;
00755     }
00756  
00757     fun = JS_NewFunction(cx, jsj_JavaInstanceMethodWrapper, 0,
00758                       JSFUN_BOUND_METHOD, NULL, method_name);
00759     member_descriptor->invoke_func_obj = JS_GetFunctionObject(fun);
00760     JS_AddNamedRoot(cx, &member_descriptor->invoke_func_obj,
00761                     "&member_descriptor->invoke_func_obj");
00762 
00763     /* THREADSAFETY */
00764     /* Add the new aliased member to the list of all members for the class */
00765     if (is_static) {
00766        member_descriptor->next = class_descriptor->static_members;
00767        class_descriptor->static_members = member_descriptor;
00768     } else {
00769        member_descriptor->next = class_descriptor->instance_members;
00770        class_descriptor->instance_members = member_descriptor;
00771     }
00772 
00773     return member_descriptor;
00774 }
00775 
00776 /*
00777  * Return the JavaScript types that a JavaScript method was invoked with
00778  * as a string, e.g. a JS method invoked like foo(3, 'hey', 'you', true)
00779  * would cause a return value of "(number, string, string, boolean)".
00780  * The returned string must be free'ed by the caller.
00781  * Returns NULL and reports an error if out-of-memory.
00782  */
00783 static const char *
00784 get_js_arg_types_as_string(JSContext *cx, uintN argc, jsval *argv)
00785 {
00786     uintN i;
00787     const char *arg_type, *arg_string, *tmp;
00788 
00789     if (argc == 0)
00790         return strdup("()");
00791     
00792     arg_string = strdup("(");
00793     if (!arg_string)
00794         goto out_of_memory;
00795     for (i = 0; i < argc; i++) {
00796         arg_type = JS_GetTypeName(cx, JS_TypeOfValue(cx, argv[i]));
00797         tmp = JS_smprintf("%s%s%s%s", arg_string,  i ? ", " : "", arg_type,
00798                          (i == argc-1) ? ")" : "");
00799         free((char*)arg_string);
00800         if (!tmp)
00801             goto out_of_memory;
00802         arg_string = tmp;
00803     }
00804 
00805     return arg_string;
00806 
00807 out_of_memory:
00808     JS_ReportOutOfMemory(cx);
00809     return NULL;
00810 }
00811 
00812 /*
00813  * This is an error reporting routine used when a method of the correct name
00814  * and class exists but either the number of arguments is incorrect or the
00815  * arguments are of the wrong type.
00816  */
00817 static void
00818 report_method_match_failure(JSContext *cx,
00819                             JavaMemberDescriptor *member_descriptor,
00820                             JavaClassDescriptor *class_descriptor,
00821                             JSBool is_static_method,
00822                             uintN argc, jsval *argv)
00823 {
00824     const char *err, *js_arg_string, *tmp, *method_str, *method_name;
00825     JSBool is_constructor;
00826     JavaMethodSpec *method;
00827 
00828     err = NULL;
00829     is_constructor = (!strcmp(member_descriptor->name, "<init>"));
00830 
00831     js_arg_string = get_js_arg_types_as_string(cx, argc, argv);
00832     if (!js_arg_string)
00833         goto out_of_memory;
00834 
00835     if (is_constructor) {
00836         err =  JS_smprintf("There is no Java constructor for class %s that matches "
00837                            "JavaScript argument types %s.\n", class_descriptor->name,
00838                            js_arg_string);
00839         method_name = class_descriptor->name;
00840     } else {
00841         err =  JS_smprintf("There is no %sJava method %s.%s that matches "
00842                            "JavaScript argument types %s.\n",
00843                            is_static_method ? "static ": "",
00844                            class_descriptor->name, member_descriptor->name, js_arg_string);
00845         method_name = member_descriptor->name;
00846     }
00847     if (!err)
00848         goto out_of_memory;
00849 
00850     tmp = JS_smprintf("%sCandidate methods with the same name are:\n", err);
00851     if (!tmp)
00852         goto out_of_memory;
00853     err = tmp;
00854 
00855     method = member_descriptor->methods;
00856     while (method) {
00857         method_str =
00858             jsj_ConvertJavaMethodSignatureToHRString(cx, method_name, &method->signature);
00859         if (!method_str)
00860             goto out_of_memory;
00861         tmp = JS_smprintf("%s   %s\n", err, method_str);
00862         free((char*)method_str);
00863         if (!tmp)
00864             goto out_of_memory;
00865         err = tmp;
00866 
00867         method = method->next;
00868     }
00869     
00870     JS_ReportError(cx, err);
00871     return;
00872 
00873 out_of_memory:
00874     if (js_arg_string)
00875         free((char*)js_arg_string);
00876     if (err)
00877         free((char*)err);
00878 }
00879 
00880 /*
00881  * This is an error reporting routine used when a method of the correct name
00882  * and class exists but more than one Java method in a set of overloaded
00883  * methods are compatible with the JavaScript argument types and none of them
00884  * match any better than all the others.
00885  */
00886 static void
00887 report_ambiguous_method_match(JSContext *cx,
00888                               JavaMemberDescriptor *member_descriptor,
00889                               JavaClassDescriptor *class_descriptor,
00890                               MethodList *ambiguous_methods,
00891                               JSBool is_static_method,
00892                               uintN argc, jsval *argv)
00893 {
00894     const char *err, *js_arg_string, *tmp, *method_str, *method_name;
00895     JSBool is_constructor;
00896     JavaMethodSpec *method;
00897     MethodListElement *method_list_element;
00898 
00899     err = NULL;
00900     is_constructor = (!strcmp(member_descriptor->name, "<init>"));
00901 
00902     js_arg_string = get_js_arg_types_as_string(cx, argc, argv);
00903     if (!js_arg_string)
00904         goto out_of_memory;
00905 
00906     if (is_constructor) {
00907         err =  JS_smprintf("The choice of Java constructor for class %s with "
00908                            "JavaScript argument types %s is ambiguous.\n",
00909                            class_descriptor->name,
00910                            js_arg_string);
00911         method_name = class_descriptor->name;
00912     } else {
00913         err =  JS_smprintf("The choice of %sJava method %s.%s matching "
00914                            "JavaScript argument types %s is ambiguous.\n",
00915                            is_static_method ? "static ": "",
00916                            class_descriptor->name, member_descriptor->name,
00917                            js_arg_string);
00918         method_name = member_descriptor->name;
00919     }
00920     if (!err)
00921         goto out_of_memory;
00922 
00923     tmp = JS_smprintf("%sCandidate methods are:\n", err);
00924     if (!tmp)
00925         goto out_of_memory;
00926     err = tmp;
00927 
00928     method_list_element = (MethodListElement*)JS_LIST_HEAD(ambiguous_methods);
00929     while ((MethodList*)method_list_element != ambiguous_methods) {
00930         method = method_list_element->method;
00931         method_str =
00932             jsj_ConvertJavaMethodSignatureToHRString(cx, method_name, &method->signature);
00933         if (!method_str)
00934             goto out_of_memory;
00935         tmp = JS_smprintf("%s   %s\n", err, method_str);
00936         free((char*)method_str);
00937         if (!tmp)
00938             goto out_of_memory;
00939         err = tmp;
00940 
00941         method_list_element = (MethodListElement*)method_list_element->linkage.next;
00942     }
00943     
00944     JS_ReportError(cx, err);
00945     return;
00946 
00947 out_of_memory:
00948     if (js_arg_string)
00949         free((char*)js_arg_string);
00950     if (err)
00951         free((char*)err);
00952 }
00953 
00954 /*
00955  * Compute classification of JS types with slightly different granularity
00956  * than JSType.  This is used to resolve among overloaded Java methods.
00957  */
00958 static JSJType
00959 compute_jsj_type(JSContext *cx, jsval v)
00960 {
00961     JSObject *js_obj;
00962 
00963     if (JSVAL_IS_OBJECT(v)) {
00964         if (JSVAL_IS_NULL(v))
00965             return JSJTYPE_NULL;
00966         js_obj = JSVAL_TO_OBJECT(v);
00967         if (JS_InstanceOf(cx, js_obj, &JavaObject_class, 0))
00968            return JSJTYPE_JAVAOBJECT;
00969         if (JS_InstanceOf(cx, js_obj, &JavaArray_class, 0))
00970             return JSJTYPE_JAVAARRAY;
00971         if (JS_InstanceOf(cx, js_obj, &JavaClass_class, 0))
00972             return JSJTYPE_JAVACLASS;
00973         if (JS_IsArrayObject(cx, js_obj))
00974             return JSJTYPE_JSARRAY;
00975         return JSJTYPE_OBJECT;
00976     } else if (JSVAL_IS_NUMBER(v)) {
00977        return JSJTYPE_NUMBER;
00978     } else if (JSVAL_IS_STRING(v)) {
00979        return JSJTYPE_STRING;
00980     } else if (JSVAL_IS_BOOLEAN(v)) {
00981        return JSJTYPE_BOOLEAN;
00982     } else if (JSVAL_IS_VOID(v)) {
00983        return JSJTYPE_VOID;
00984     }
00985     JS_ASSERT(0);   /* Unknown JS type ! */
00986     return JSJTYPE_VOID;
00987 }
00988 
00989 /* 
00990  * Ranking table used to establish preferences among Java types when converting
00991  * from JavaScript types.  Each row represents a different JavaScript source
00992  * type and each column represents a different target Java type.  Lower values
00993  * in the table indicate conversions that are ranked higher.  The special
00994  * value 99 indicates a disallowed JS->Java conversion.  The special value of
00995  * 0 indicates special handling is required to determine ranking.
00996  */
00997 static int rank_table[JSJTYPE_LIMIT][JAVA_SIGNATURE_LIMIT] = {
00998 /*    boolean             long
00999       |   char            |   float           java.lang.Boolean
01000       |   |   byte        |   |   double      |   java.lang.Class
01001       |   |   |   short   |   |   |   array   |   |   java.lang.Double
01002       |   |   |   |   int |   |   |   |   object  |   |   netscape.javascript.JSObject
01003       |   |   |   |   |   |   |   |   |   |   |   |   |   |   java.lang.Object
01004       |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   java.lang.String */
01005 
01006     {99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,  1,  1}, /* undefined */
01007     { 1, 99, 99, 99, 99, 99, 99, 99, 99, 99,  2, 99, 99, 99,  3,  4}, /* boolean */
01008     {99,  7,  8,  6,  5,  4,  3,  1, 99, 99, 99, 99,  2, 99, 11,  9}, /* number */
01009     {99,  3,  4,  4,  4,  4,  4,  4, 99, 99, 99, 99, 99, 99,  2,  1}, /* string */
01010     {99, 99, 99, 99, 99, 99, 99, 99,  1,  1,  1,  1,  1,  1,  1,  1}, /* null */
01011     {99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,  1, 99,  2,  3,  4}, /* JavaClass */
01012     {99,  7,  8,  6,  5,  4,  3,  2,  0,  0,  0,  0,  0,  0,  0,  1}, /* JavaObject */
01013     {99, 99, 99, 99, 99, 99, 99, 99,  0,  0, 99, 99, 99, 99,  0,  1}, /* JavaArray */
01014     {99, 99, 99, 99, 99, 99, 99, 99,  2, 99, 99, 99, 99,  1,  3,  4}, /* JS Array */
01015     {99,  9, 10,  8,  7,  6,  5,  4, 99, 99, 99, 99, 99,  1,  2,  3}  /* other JS object */
01016 };
01017 
01018 /*
01019  * Returns JS_TRUE if JavaScript arguments are compatible with the specified
01020  * Java method signature.
01021  */
01022 static JSBool
01023 method_signature_matches_JS_args(JSContext *cx, JNIEnv *jEnv, uintN argc, jsval *argv,
01024                                  JavaMethodSignature *method_signature)
01025 {
01026     uintN i;
01027     JavaClassDescriptor *descriptor;
01028     JavaObjectWrapper *java_wrapper;
01029     jclass java_class;
01030     jobject java_obj;
01031     JSObject *js_obj;
01032     JSJType js_type;
01033     jsval js_val;
01034     int rank;
01035 
01036     if (argc != (uintN)method_signature->num_args)
01037         return JS_FALSE;
01038 
01039     for (i = 0; i < argc; i++) {
01040         js_val = argv[i];
01041         js_type = compute_jsj_type(cx, js_val);
01042         descriptor = method_signature->arg_signatures[i];
01043         rank = rank_table[js_type][(int)descriptor->type - 2];
01044 
01045         /* Check for disallowed JS->Java conversion */
01046         if (rank == 99)
01047             return JS_FALSE;
01048 
01049         /* Check for special handling required by conversion from JavaObject */
01050         if (rank == 0) {
01051             java_class = descriptor->java_class;
01052         
01053             js_obj = JSVAL_TO_OBJECT(js_val);
01054             java_wrapper = JS_GetPrivate(cx, js_obj);
01055             java_obj = java_wrapper->java_obj;
01056         
01057             if (!(*jEnv)->IsInstanceOf(jEnv, java_obj, java_class))
01058                 return JS_FALSE;
01059         }
01060     }
01061 
01062     return JS_TRUE;
01063 }
01064 
01065 #ifdef HAS_OLD_STYLE_METHOD_RESOLUTION
01066 
01067 static JavaMethodSpec *
01068 resolve_overloaded_method(JSContext *cx, JNIEnv *jEnv, JavaMemberDescriptor *member_descriptor,
01069                           JavaClassDescriptor *class_descriptor,
01070                           JSBool is_static_method,
01071                           uintN argc, jsval *argv)
01072 {
01073     int cost, lowest_cost, num_method_matches;
01074     JavaMethodSpec *best_method_match, *method;
01075 
01076     num_method_matches = 0;
01077     lowest_cost = 10000;
01078     best_method_match = NULL;
01079 
01080     for (method = member_descriptor->methods; method; method = method->next) {
01081         cost = 0;
01082         if (!method_signature_matches_JS_args(cx, jEnv, argc, argv, &method->signature, &cost))
01083             continue;
01084 
01085         if (cost < lowest_cost) {
01086             lowest_cost = cost;
01087             best_method_match = method;
01088             num_method_matches++;
01089         }
01090     }
01091 
01092     if (!best_method_match)
01093         report_method_match_failure(cx, member_descriptor, class_descriptor,
01094                                     is_static_method, argc, argv);
01095 
01096     if (lowest_cost != 0)
01097         return NULL;
01098 
01099     return best_method_match;
01100 }
01101 
01102 #else   /* !OLD_STYLE_METHOD_RESOLUTION */
01103 
01104 /*
01105  * Determine the more natural (preferred) JavaScript->Java conversion
01106  * given one JavaScript value and two Java types.
01107  * See http://www.mozilla.org/js/liveconnect/lc3_method_overloading.html
01108  * for details.
01109  */
01110 static JSJTypePreference
01111 preferred_conversion(JSContext *cx, JNIEnv *jEnv, jsval js_val,
01112                      JavaClassDescriptor *descriptor1,
01113                      JavaClassDescriptor *descriptor2)
01114 {
01115     JSJType js_type;
01116     int rank1, rank2;
01117     jclass java_class1, java_class2;
01118     JavaObjectWrapper *java_wrapper;
01119     jobject java_obj;
01120     JSObject *js_obj;
01121     
01122     js_type = compute_jsj_type(cx, js_val);
01123     rank1 = rank_table[js_type][(int)descriptor1->type - 2];
01124     rank2 = rank_table[js_type][(int)descriptor2->type - 2];
01125         
01126     /* Fast path for conversion from most JS types */  
01127     if (rank1 < rank2)
01128         return JSJPREF_FIRST_ARG;
01129 
01130     /*
01131      * Special logic is required for matching the classes of wrapped
01132      * Java objects.
01133      */
01134     if (rank2 == 0) {
01135         java_class1 = descriptor1->java_class;
01136         java_class2 = descriptor2->java_class;
01137         
01138         js_obj = JSVAL_TO_OBJECT(js_val);
01139         java_wrapper = JS_GetPrivate(cx, js_obj);
01140         java_obj = java_wrapper->java_obj;
01141         
01142         /* Unwrapped JavaObject must be compatible with Java arg type */
01143         if (!(*jEnv)->IsInstanceOf(jEnv, java_obj, java_class2))
01144             return JSJPREF_FIRST_ARG;
01145 
01146         /*
01147          * For JavaObject arguments, any compatible reference type is preferable
01148          * to any primitive Java type or to java.lang.String.
01149          */
01150         if (rank1 != 0)
01151             return JSJPREF_SECOND_ARG;
01152         
01153         /*
01154          * If argument of type descriptor1 is subclass of type descriptor 2, then
01155          * descriptor1 is preferred and vice-versa.
01156          */
01157         if ((*jEnv)->IsAssignableFrom(jEnv, java_class1, java_class2))
01158             return JSJPREF_FIRST_ARG;
01159         
01160         if ((*jEnv)->IsAssignableFrom(jEnv, java_class2, java_class1))
01161             return JSJPREF_SECOND_ARG;
01162 
01163         /* This can happen in unusual situations involving interface types. */
01164         return JSJPREF_AMBIGUOUS;
01165     }
01166     
01167     if (rank1 > rank2)
01168         return JSJPREF_SECOND_ARG;
01169     
01170     return JSJPREF_AMBIGUOUS;
01171 }
01172               
01173 static JSJTypePreference
01174 method_preferred(JSContext *cx, JNIEnv *jEnv, jsval *argv,
01175                  JavaMethodSignature *method_signature1,
01176                  JavaMethodSignature *method_signature2)
01177 {
01178     int arg_index, argc, preference;
01179     jsval val;
01180     JavaSignature* *arg_signatures1;
01181     JavaSignature* *arg_signatures2;
01182     JavaSignature *arg_type1, *arg_type2;
01183 
01184     arg_signatures1 = method_signature1->arg_signatures;
01185     arg_signatures2 = method_signature2->arg_signatures;
01186     argc = method_signature1->num_args;
01187     JS_ASSERT(argc == method_signature2->num_args);
01188 
01189     preference = 0;
01190     for (arg_index = 0; arg_index < argc; arg_index++) {
01191         val = argv[arg_index];
01192         arg_type1 = *arg_signatures1++;
01193         arg_type2 = *arg_signatures2++;
01194 
01195         if (arg_type1 == arg_type2)
01196             continue;
01197 
01198         preference |= preferred_conversion(cx, jEnv, val, arg_type1, arg_type2);
01199 
01200         if ((JSJTypePreference)preference == JSJPREF_AMBIGUOUS)
01201             return JSJPREF_AMBIGUOUS;
01202     }
01203     return (JSJTypePreference)preference;
01204 }
01205 
01206 /*
01207  * This routine applies heuristics to guess the intended Java method given the
01208  * runtime JavaScript argument types and the type signatures of the candidate
01209  * methods.  Informally, the method with Java parameter types that most closely
01210  * match the JavaScript types is chosen.  A more precise specification is
01211  * provided in the lc3_method_resolution.html file.  The code uses a very
01212  * brute-force approach.
01213  */
01214 static JavaMethodSpec *
01215 resolve_overloaded_method(JSContext *cx, JNIEnv *jEnv,
01216                           JavaMemberDescriptor *member_descriptor,
01217                           JavaClassDescriptor *class_descriptor,
01218                           JSBool is_static_method,
01219                           uintN argc, jsval *argv)
01220 {
01221     JSJTypePreference preference;
01222     JavaMethodSpec *method, *best_method_match;
01223     MethodList ambiguous_methods;
01224     MethodListElement *method_list_element, *next_element;
01225 
01226     /*
01227      * Determine the first Java method among the overloaded methods of the same name
01228      * that matches all the JS arguments.
01229      */
01230     for (method = member_descriptor->methods; method; method = method->next) {
01231         if (method_signature_matches_JS_args(cx, jEnv, argc, argv, &method->signature))
01232             break;
01233     }
01234 
01235     /* Report an error if no method matched the JS arguments */
01236     if (!method) {
01237         report_method_match_failure(cx, member_descriptor, class_descriptor,
01238                                     is_static_method, argc, argv);
01239         return NULL;
01240     }
01241 
01242     /* Shortcut a common case */
01243     if (!method->next)
01244         return method;
01245 
01246     /*
01247      * Form a list of all methods that are neither more or less preferred than the
01248      * best matching method discovered so far.
01249      */
01250     JS_INIT_CLIST(&ambiguous_methods);
01251 
01252     best_method_match = method;
01253 
01254     /* See if there are any Java methods that are a better fit for the JS args */
01255     for (method = method->next; method; method = method->next) {
01256         if (method->signature.num_args != (int)argc)
01257             continue;
01258         preference = method_preferred(cx, jEnv, argv, &best_method_match->signature,
01259                                       &method->signature);
01260         if (preference == JSJPREF_SECOND_ARG) {
01261             best_method_match = method;
01262         } else  if (preference == JSJPREF_AMBIGUOUS) {
01263             /* Add this method to the list of ambiguous methods */
01264             method_list_element =
01265                 (MethodListElement*)JS_malloc(cx, sizeof(MethodListElement));
01266             if (!method_list_element)
01267                 goto error;
01268             method_list_element->method = method;
01269             JS_APPEND_LINK(&method_list_element->linkage, &ambiguous_methods);
01270         }
01271     }
01272     
01273     /*
01274      * Ensure that best_method_match is preferred to all methods on the
01275      * ambiguous_methods list.
01276      */
01277     
01278     for (method_list_element = (MethodListElement*)JS_LIST_HEAD(&ambiguous_methods);
01279         (MethodList*)method_list_element != &ambiguous_methods;
01280          method_list_element = next_element) {
01281         next_element = (MethodListElement*)method_list_element->linkage.next;
01282         method = method_list_element->method;
01283         preference = method_preferred(cx, jEnv, argv, &best_method_match->signature,
01284                                       &method->signature);
01285         if (preference != JSJPREF_FIRST_ARG)
01286             continue;
01287         JS_REMOVE_LINK(&method_list_element->linkage);
01288         JS_free(cx, method_list_element);
01289     }
01290     
01291     /*
01292      * The chosen method must be maximally preferred, i.e. there can be no other
01293      * method that is just as preferred.
01294      */
01295     if (!JS_CLIST_IS_EMPTY(&ambiguous_methods)) {
01296         /* Add the best_method_match to the list of ambiguous methods */
01297        method_list_element =
01298            (MethodListElement*)JS_malloc(cx, sizeof(MethodListElement));
01299        if (!method_list_element)
01300            goto error;
01301        method_list_element->method = best_method_match;
01302        JS_APPEND_LINK(&method_list_element->linkage, &ambiguous_methods);
01303 
01304        /* Report the problem */
01305         report_ambiguous_method_match(cx, member_descriptor, class_descriptor,
01306                                       &ambiguous_methods, is_static_method, argc, argv);
01307         goto error;
01308     }
01309 
01310     return best_method_match;
01311 
01312 error:
01313     /* Delete the storage for the ambiguous_method list */
01314     while (!JS_CLIST_IS_EMPTY(&ambiguous_methods)) {
01315         method_list_element = (MethodListElement*)JS_LIST_HEAD(&ambiguous_methods);
01316         JS_REMOVE_LINK(&method_list_element->linkage);
01317         JS_free(cx, method_list_element);
01318     }
01319 
01320     return NULL;
01321 }
01322 
01323 #endif  /* !HAS_OLD_STYLE_METHOD_RESOLUTION */
01324 
01325 static jvalue *
01326 convert_JS_method_args_to_java_argv(JSContext *cx, JNIEnv *jEnv, jsval *argv,
01327                         JavaMethodSpec *method, JSBool **localvp)
01328 {
01329     jvalue *jargv;
01330     JSBool ok, *localv;
01331     uintN i, argc;
01332     JavaSignature **arg_signatures;
01333     JavaMethodSignature *signature;
01334     
01335     
01336     signature = &method->signature;
01337     argc = signature->num_args;
01338     JS_ASSERT(argc != 0);
01339     arg_signatures = signature->arg_signatures;
01340     
01341     jargv = (jvalue *)JS_malloc(cx, sizeof(jvalue) * argc);
01342     
01343     if (!jargv)
01344         return NULL;
01345 
01346     /*
01347      * Allocate an array that contains a flag for each argument, indicating whether
01348      * or not the conversion from a JS value to a Java value resulted in a new
01349      * JNI local reference.
01350      */
01351     localv = (JSBool *)JS_malloc(cx, sizeof(JSBool) * argc);
01352     *localvp = localv;
01353     if (!localv) {
01354         JS_free(cx, jargv);
01355         return NULL;
01356     }
01357  
01358     for (i = 0; i < argc; i++) {
01359         int dummy_cost;
01360         
01361         ok = jsj_ConvertJSValueToJavaValue(cx, jEnv, argv[i], arg_signatures[i],
01362                                            &dummy_cost, &jargv[i], &localv[i]);
01363         if (!ok) {
01364             JS_free(cx, jargv);
01365             JS_free(cx, localv);
01366             *localvp = NULL;
01367             return NULL;
01368         }
01369     }
01370 
01371     return jargv;
01372 }  
01373 
01374 static JSBool
01375 invoke_java_method(JSContext *cx, JSJavaThreadState *jsj_env,
01376                    jobject java_class_or_instance,
01377                    JavaClassDescriptor *class_descriptor,
01378                    JavaMethodSpec *method,
01379                    JSBool is_static_method,
01380                    jsval *argv, jsval *vp)
01381 {
01382     jvalue java_value;
01383     jvalue *jargv;
01384     uintN argc, i;
01385     jobject java_object;
01386     jclass java_class;
01387     jmethodID methodID;
01388     JavaMethodSignature *signature;
01389     JavaSignature *return_val_signature;
01390     JNIEnv *jEnv;
01391     JSBool *localv, error_occurred, success;
01392 
01393     success = error_occurred = JS_FALSE;
01394     return_val_signature = NULL;    /* Quiet gcc uninitialized variable warning */
01395 
01396     methodID = method->methodID;
01397     signature = &method->signature;
01398     argc = signature->num_args;
01399 
01400     jEnv = jsj_env->jEnv;
01401 
01402     if (is_static_method) {
01403         java_object = NULL;
01404         java_class = java_class_or_instance;
01405     } else {
01406         java_object = java_class_or_instance;
01407         java_class = NULL;
01408     }
01409 
01410     jargv = NULL;
01411     localv = NULL;
01412     if (argc) {
01413         jargv = convert_JS_method_args_to_java_argv(cx, jEnv, argv, method, &localv);
01414         if (!jargv) {
01415             error_occurred = JS_TRUE;
01416             goto out;
01417         }
01418     }
01419 
01420     /* Prevent deadlocking if we re-enter JS on another thread as a result of a Java
01421        method call and that new thread wants to perform a GC. */
01422 #ifdef JSJ_THREADSAFE
01423     JS_EndRequest(cx);
01424 #endif
01425 
01426 #define CALL_JAVA_METHOD(type, member)                                       \
01427     JS_BEGIN_MACRO                                                           \
01428     if (is_static_method) {                                                  \
01429         java_value.member = (*jEnv)->CallStatic##type##MethodA(jEnv, java_class, methodID, jargv);\
01430     } else {                                                                 \
01431         java_value.member = (*jEnv)->Call##type##MethodA(jEnv, java_object, methodID, jargv);\
01432     }                                                                        \
01433     if ((*jEnv)->ExceptionOccurred(jEnv)) {                                  \
01434         jsj_ReportJavaError(cx, jEnv, "Error calling method %s.%s()",        \
01435                             class_descriptor->name, method->name);           \
01436         error_occurred = JS_TRUE;                                            \
01437         goto out;                                                            \
01438     }                                                                        \
01439     JS_END_MACRO
01440 
01441     return_val_signature = signature->return_val_signature;
01442     switch(return_val_signature->type) {
01443     case JAVA_SIGNATURE_BYTE:
01444         CALL_JAVA_METHOD(Byte, b);
01445         break;
01446 
01447     case JAVA_SIGNATURE_CHAR:
01448         CALL_JAVA_METHOD(Char, c);
01449         break;
01450     
01451     case JAVA_SIGNATURE_FLOAT:
01452         CALL_JAVA_METHOD(Float, f);
01453         break;
01454     
01455     case JAVA_SIGNATURE_DOUBLE:
01456         CALL_JAVA_METHOD(Double, d);
01457         break;
01458     
01459     case JAVA_SIGNATURE_INT:
01460         CALL_JAVA_METHOD(Int, i);
01461         break;
01462     
01463     case JAVA_SIGNATURE_LONG:
01464         CALL_JAVA_METHOD(Long, j);
01465         break;
01466     
01467     case JAVA_SIGNATURE_SHORT:
01468         CALL_JAVA_METHOD(Short, s);
01469         break;
01470     
01471     case JAVA_SIGNATURE_BOOLEAN:
01472         CALL_JAVA_METHOD(Boolean, z);
01473         break;
01474     
01475     case JAVA_SIGNATURE_VOID:
01476         if (is_static_method)
01477             (*jEnv)->CallStaticVoidMethodA(jEnv, java_class, methodID, jargv);
01478         else
01479             (*jEnv)->CallVoidMethodA(jEnv, java_object, methodID, jargv);
01480         if ((*jEnv)->ExceptionOccurred(jEnv)) {
01481             jsj_ReportJavaError(cx, jEnv, "Error calling method %s.%s()",
01482                                 class_descriptor->name, method->name);
01483             error_occurred = JS_TRUE;
01484             goto out;
01485         }
01486         break;
01487         
01488     case JAVA_SIGNATURE_UNKNOWN:
01489         JS_ASSERT(0);
01490         error_occurred = JS_TRUE;
01491         goto out;
01492             
01493     /* Non-primitive (reference) type */
01494     default:
01495         JS_ASSERT(IS_REFERENCE_TYPE(return_val_signature->type));
01496         CALL_JAVA_METHOD(Object, l);
01497         break;
01498     }
01499 
01500 out:
01501 
01502     if (localv) {
01503         for (i = 0; i < argc; i++) {
01504             if (localv[i])
01505                 (*jEnv)->DeleteLocalRef(jEnv, jargv[i].l);
01506         }
01507         JS_free(cx, localv);
01508     }
01509     if (jargv)
01510        JS_free(cx, jargv);
01511 
01512 #ifdef JSJ_THREADSAFE
01513     JS_BeginRequest(cx);
01514 #endif
01515 
01516     if (!error_occurred) {
01517         success = jsj_ConvertJavaValueToJSValue(cx, jEnv, return_val_signature, &java_value, vp);
01518         if (IS_REFERENCE_TYPE(return_val_signature->type))
01519             (*jEnv)->DeleteLocalRef(jEnv, java_value.l);
01520     }
01521     return success;
01522 }
01523 
01524 static JSBool
01525 invoke_overloaded_java_method(JSContext *cx, JSJavaThreadState *jsj_env,
01526                               JavaMemberDescriptor *member,
01527                               JSBool is_static_method,
01528                               jobject java_class_or_instance,
01529                               JavaClassDescriptor *class_descriptor,
01530                               uintN argc, jsval *argv,
01531                               jsval *vp)
01532 {
01533     JavaMethodSpec *method;
01534     JNIEnv *jEnv;
01535 
01536     jEnv = jsj_env->jEnv;
01537 
01538     method = resolve_overloaded_method(cx, jEnv, member, class_descriptor,
01539                                        is_static_method, argc, argv);
01540     if (!method)
01541         return JS_FALSE;
01542 
01543     return invoke_java_method(cx, jsj_env, java_class_or_instance, class_descriptor, 
01544                               method, is_static_method, argv, vp);
01545 }
01546 
01547 static JSBool
01548 invoke_java_constructor(JSContext *cx,
01549                         JSJavaThreadState *jsj_env,
01550                         jclass java_class,
01551                 JavaMethodSpec *method,
01552                 jsval *argv, jsval *vp)
01553 {
01554     jvalue *jargv;
01555     uintN argc, i;
01556     jobject java_object;
01557     jmethodID methodID;
01558     JavaMethodSignature *signature;
01559     JNIEnv *jEnv;
01560     JSBool *localv;
01561     JSBool success, error_occurred;
01562     java_object = NULL;         /* Stifle gcc uninitialized variable warning */
01563 
01564     success = error_occurred = JS_FALSE;
01565     
01566     methodID = method->methodID;
01567     signature = &method->signature;
01568     argc = signature->num_args;
01569 
01570     jEnv = jsj_env->jEnv;
01571 
01572     jargv = NULL;
01573     localv = NULL;
01574     if (argc) {
01575         jargv = convert_JS_method_args_to_java_argv(cx, jEnv, argv, method, &localv);
01576         if (!jargv) {
01577             error_occurred = JS_TRUE;
01578             goto out;
01579         }
01580     }
01581 
01582     /* Prevent deadlocking if we re-enter JS on another thread as a result of a Java
01583        method call and that new thread wants to perform a GC. */
01584 #ifdef JSJ_THREADSAFE
01585     JS_EndRequest(cx);
01586 #endif
01587 
01588     /* Call the constructor */
01589     java_object = (*jEnv)->NewObjectA(jEnv, java_class, methodID, jargv);
01590 
01591 #ifdef JSJ_THREADSAFE
01592     JS_BeginRequest(cx);
01593 #endif
01594 
01595     if (!java_object) {
01596         jsj_ReportJavaError(cx, jEnv, "Error while constructing instance of %s",
01597                             jsj_GetJavaClassName(cx, jEnv, java_class));
01598         error_occurred = JS_TRUE;
01599         goto out;
01600     }
01601 
01602 out:
01603     if (localv) {
01604         for (i = 0; i < argc; i++) {
01605             if (localv[i])
01606                 (*jEnv)->DeleteLocalRef(jEnv, jargv[i].l);
01607         }
01608         JS_free(cx, localv);
01609     }
01610     if (jargv)
01611        JS_free(cx, jargv);
01612         
01613     if (!error_occurred)
01614         success = jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_object, vp);
01615     (*jEnv)->DeleteLocalRef(jEnv, java_object);
01616     return success;
01617 }
01618 
01619 static JSBool
01620 invoke_overloaded_java_constructor(JSContext *cx,
01621                                    JSJavaThreadState *jsj_env,
01622                                    JavaMemberDescriptor *member,
01623                                    JavaClassDescriptor *class_descriptor,
01624                                    uintN argc, jsval *argv,
01625                                    jsval *vp)
01626 {
01627     jclass java_class;
01628     JavaMethodSpec *method;
01629     JNIEnv *jEnv;
01630 
01631     jEnv = jsj_env->jEnv;
01632 
01633     method = resolve_overloaded_method(cx, jEnv, member, class_descriptor, JS_TRUE, 
01634                                        argc, argv);
01635     if (!method)
01636         return JS_FALSE;
01637 
01638     java_class = class_descriptor->java_class;
01639     return invoke_java_constructor(cx, jsj_env, java_class, method, argv, vp);
01640 }
01641 
01642 static JSBool
01643 java_constructor_wrapper(JSContext *cx, JSJavaThreadState *jsj_env,
01644                          JavaMemberDescriptor *member_descriptor,
01645                          JavaClassDescriptor *class_descriptor,
01646                          uintN argc, jsval *argv, jsval *vp)
01647 {
01648     jint modifiers;
01649     JNIEnv *jEnv;
01650 
01651     jEnv = jsj_env->jEnv;
01652     
01653     /* Get class/interface flags and check them */
01654     modifiers = class_descriptor->modifiers;
01655     if (modifiers & ACC_ABSTRACT) {
01656         JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, 
01657                             JSJMSG_ABSTRACT_JCLASS, class_descriptor->name);
01658         return JS_FALSE;
01659     }
01660     if (modifiers & ACC_INTERFACE) {
01661         JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, 
01662                             JSJMSG_IS_INTERFACE, class_descriptor->name);
01663         return JS_FALSE;
01664     }
01665     if ( !(modifiers & ACC_PUBLIC) ) {
01666         JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, 
01667                             JSJMSG_NOT_PUBLIC, class_descriptor->name);
01668         return JS_FALSE;
01669     }
01670     
01671     if (!member_descriptor) {
01672         JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, 
01673                             JSJMSG_NO_CONSTRUCTORS, class_descriptor->name);
01674         return JS_FALSE;
01675     }
01676 
01677     return invoke_overloaded_java_constructor(cx, jsj_env, member_descriptor,
01678                                               class_descriptor, argc, argv, vp);
01679 }
01680 
01681 JS_EXPORT_API(JSBool)
01682 jsj_JavaConstructorWrapper(JSContext *cx, JSObject *obj,
01683                            uintN argc, jsval *argv, jsval *vp)
01684 {
01685     JavaClassDescriptor *class_descriptor;
01686     JavaMemberDescriptor *member_descriptor;
01687     JSJavaThreadState *jsj_env;
01688     JNIEnv *jEnv;
01689     JSBool result;
01690 
01691     obj = JSVAL_TO_OBJECT(argv[-2]);
01692     class_descriptor = JS_GetPrivate(cx, obj);
01693     JS_ASSERT(class_descriptor);
01694     if (!class_descriptor)
01695         return JS_FALSE;
01696 
01697     /* XXX, workaround for bug 200016, all classes in sun.plugin package should not 
01698        be accessible in liveconnect.
01699        Ideally, this checking should be done in JPI side, but it's not going to happen 
01700        until Sun JRE 1.5.1 */
01701     if (strstr(class_descriptor->name, "sun.plugin.") == class_descriptor->name)
01702         return JS_FALSE;
01703   
01704     /* Get the Java per-thread environment pointer for this JSContext */
01705     jsj_env = jsj_EnterJava(cx, &jEnv);
01706     if (!jEnv)
01707         return JS_FALSE;
01708     member_descriptor = jsj_LookupJavaClassConstructors(cx, jEnv, class_descriptor);
01709     result = java_constructor_wrapper(cx, jsj_env, member_descriptor, 
01710                                       class_descriptor, argc, argv, vp);
01711     jsj_ExitJava(jsj_env);
01712     return result;
01713 }
01714 
01715 
01716 static JSBool
01717 static_method_wrapper(JSContext *cx, JSJavaThreadState *jsj_env,
01718                       JavaClassDescriptor *class_descriptor,
01719                       jsid id,
01720                       uintN argc, jsval *argv, jsval *vp)
01721 {
01722     JNIEnv *jEnv;
01723     JavaMemberDescriptor *member_descriptor;
01724 
01725     jEnv = jsj_env->jEnv;
01726     member_descriptor = jsj_LookupJavaStaticMemberDescriptorById(cx, jEnv, class_descriptor, id);
01727     
01728     /* Is it a static method that is not a constructor ? */
01729     if (member_descriptor && strcmp(member_descriptor->name, "<init>")) {
01730         return invoke_overloaded_java_method(cx, jsj_env, member_descriptor, JS_TRUE, 
01731                                              class_descriptor->java_class,
01732                                              class_descriptor, argc, argv, vp);
01733     }
01734 
01735     JS_ASSERT(member_descriptor);
01736     if (!member_descriptor)
01737         return JS_FALSE;
01738     
01739     /* Must be an explicitly resolved overloaded constructor */
01740     return java_constructor_wrapper(cx, jsj_env, member_descriptor,
01741                                     class_descriptor, argc, argv, vp);
01742 }
01743 
01744 JS_EXTERN_API(JSBool)
01745 jsj_JavaStaticMethodWrapper(JSContext *cx, JSObject *obj,
01746                             uintN argc, jsval *argv, jsval *vp)
01747 {
01748     JSFunction *function;
01749     JavaClassDescriptor *class_descriptor;
01750     jsid id;
01751     jsval idval;
01752     JNIEnv *jEnv;
01753     JSJavaThreadState *jsj_env;
01754     JSBool result;
01755     
01756     class_descriptor = JS_GetPrivate(cx, obj);
01757     if (!class_descriptor)
01758         return JS_FALSE;
01759 
01760     /* Get the Java per-thread environment pointer for this JSContext */
01761     jsj_env = jsj_EnterJava(cx, &jEnv);
01762     if (!jEnv)
01763         return JS_FALSE;
01764     
01765     JS_ASSERT(JS_TypeOfValue(cx, argv[-2]) == JSTYPE_FUNCTION);
01766     function = JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[-2]));
01767     idval = STRING_TO_JSVAL(JS_InternString(cx, JS_GetFunctionName(function)));
01768     JS_ValueToId(cx, idval, &id);
01769 
01770     result = static_method_wrapper(cx, jsj_env, class_descriptor, id, argc, argv, vp);
01771     jsj_ExitJava(jsj_env);
01772     return result;
01773 }
01774 
01775 JS_EXPORT_API(JSBool)
01776 jsj_JavaInstanceMethodWrapper(JSContext *cx, JSObject *obj,
01777                               uintN argc, jsval *argv, jsval *vp)
01778 {
01779     JSFunction *function;
01780     JavaMemberDescriptor *member_descriptor;
01781     JavaObjectWrapper *java_wrapper;
01782     JavaClassDescriptor *class_descriptor;
01783     jsid id;
01784     jsval idval;
01785     JSJavaThreadState *jsj_env;
01786     JNIEnv *jEnv;
01787     jobject java_obj;
01788     JSBool result;
01789     
01790     java_wrapper = JS_GetPrivate(cx, obj);
01791     if (!java_wrapper)
01792         return JS_FALSE;
01793     java_obj = java_wrapper->java_obj;
01794     
01795     JS_ASSERT(JS_TypeOfValue(cx, argv[-2]) == JSTYPE_FUNCTION);
01796     function = JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[-2]));
01797     idval = STRING_TO_JSVAL(JS_InternString(cx, JS_GetFunctionName(function)));
01798     JS_ValueToId(cx, idval, &id);
01799     class_descriptor = java_wrapper->class_descriptor;
01800     
01801     /* Get the Java per-thread environment pointer for this JSContext */
01802     jsj_env = jsj_EnterJava(cx, &jEnv);
01803     if (!jEnv)
01804         return JS_FALSE;
01805 
01806     if (jaApplet && (*jEnv)->IsInstanceOf(jEnv, java_obj, jaApplet)) {
01807         jsj_JSIsCallingApplet = JS_TRUE;
01808     }
01809 
01810     /* Try to find an instance method with the given name first */
01811     member_descriptor = jsj_LookupJavaMemberDescriptorById(cx, jEnv, class_descriptor, id);
01812     if (member_descriptor)
01813         result = invoke_overloaded_java_method(cx, jsj_env, member_descriptor,
01814                                                JS_FALSE, java_obj, 
01815                                                class_descriptor, argc, argv, vp);
01816 
01817     /* If no instance method was found, try for a static method or constructor */
01818     else
01819        result = static_method_wrapper(cx, jsj_env, class_descriptor, id, argc, argv, vp);
01820     jsj_ExitJava(jsj_env);
01821     return result;
01822 }
01823