Back to index

lightning-sunbird  0.9+nobinonly
jsj_class.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  * ***** END LICENSE BLOCK ***** */
00039 
00040 /*
00041  * This file is part of the Java-vendor-neutral implementation of LiveConnect
00042  *
00043  * It contains the code that constructs and manipulates JavaClassDescriptor
00044  * structs, which are the native wrappers for Java classes.
00045  * JavaClassDescriptors are used to describe the signatures of methods and
00046  * fields.  There is a JavaClassDescriptor associated with the reflection of
00047  * each Java Object.
00048  */
00049 
00050 #include <stdlib.h>
00051 #include <string.h>
00052 
00053 #include "jsj_private.h"        /* LiveConnect internals */
00054 #include "jsj_hash.h"           /* Hash tables */
00055 
00056 #ifdef JSJ_THREADSAFE
00057 #   include "prmon.h"
00058 #endif
00059 
00060 /* A one-to-one mapping between all referenced java.lang.Class objects and
00061    their corresponding JavaClassDescriptor objects */
00062 static JSJHashTable *java_class_reflections;
00063 
00064 #ifdef JSJ_THREADSAFE
00065 static PRMonitor *java_class_reflections_monitor;
00066 #endif
00067 
00068 /*
00069  * Given a JVM handle to a java.lang.Class object, malloc a C-string
00070  * containing the UTF8 encoding of the fully qualified name of the class.
00071  * It's the caller's responsibility to free the returned string.
00072  *
00073  * If an error occurs, NULL is returned and the error reporter called.
00074  */
00075 const char *
00076 jsj_GetJavaClassName(JSContext *cx, JNIEnv *jEnv, jclass java_class)
00077 {
00078     jstring java_class_name_jstr;
00079     const char *java_class_name;
00080 
00081     /* Get java.lang.String object containing class name */
00082     java_class_name_jstr =
00083         (*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getName);
00084 
00085     if (!java_class_name_jstr)
00086         goto error;
00087 
00088     /* Fix bugzilla #183092
00089      * It is necessary to check Exception from JPI
00090      * even though java_class_name_jstr != null */
00091 #ifdef XP_UNIX
00092     if ((*jEnv)->ExceptionOccurred(jEnv))
00093         goto error;
00094 #endif
00095 
00096     /* Convert to UTF8 encoding and copy */
00097     java_class_name = jsj_DupJavaStringUTF(cx, jEnv, java_class_name_jstr);
00098 
00099     (*jEnv)->DeleteLocalRef(jEnv, java_class_name_jstr);
00100     return java_class_name;
00101 
00102 error:
00103     jsj_UnexpectedJavaError(cx, jEnv, "Can't get Java class name using"
00104                                       "java.lang.Class.getName()");
00105     return NULL;
00106 }
00107 
00108 /*
00109  * Convert in-place a string of the form "java.lang.String" into "java/lang/String".
00110  * Though the former style is conventionally used by Java programmers, the latter is
00111  * what the JNI functions require.
00112  */
00113 void
00114 jsj_MakeJNIClassname(char * class_name)
00115 {
00116     char * c;
00117     for (c = class_name; *c; c++)
00118         if (*c == '.')
00119             *c = '/';
00120 }
00121 
00122 /*
00123  * Classify an instance of java.lang.Class as either one of the primitive
00124  * types, e.g. int, char, etc., as an array type or as a non-array object type
00125  * (subclass of java.lang.Object) by returning the appropriate enum member.
00126  *
00127  */
00128 static JavaSignatureChar
00129 get_signature_type(JSContext *cx, JavaClassDescriptor *class_descriptor)
00130 {
00131     JavaSignatureChar type;
00132     const char *java_class_name;
00133 
00134     /* Get UTF8 encoding of class name */
00135     java_class_name = class_descriptor->name;
00136     JS_ASSERT(java_class_name);
00137     if (!java_class_name)
00138         return JAVA_SIGNATURE_UNKNOWN;
00139 
00140     if (!strcmp(java_class_name, "byte"))
00141         type = JAVA_SIGNATURE_BYTE;
00142     else if (!strcmp(java_class_name, "char"))
00143         type = JAVA_SIGNATURE_CHAR;
00144     else if (!strcmp(java_class_name, "float"))
00145         type = JAVA_SIGNATURE_FLOAT;
00146     else if (!strcmp(java_class_name, "double"))
00147         type = JAVA_SIGNATURE_DOUBLE;
00148     else if (!strcmp(java_class_name, "int"))
00149         type = JAVA_SIGNATURE_INT;
00150     else if (!strcmp(java_class_name, "long"))
00151         type = JAVA_SIGNATURE_LONG;
00152     else if (!strcmp(java_class_name, "short"))
00153         type = JAVA_SIGNATURE_SHORT;
00154     else if (!strcmp(java_class_name, "boolean"))
00155         type = JAVA_SIGNATURE_BOOLEAN;
00156     else if (!strcmp(java_class_name, "void"))
00157         type = JAVA_SIGNATURE_VOID;
00158     else if (!strcmp(java_class_name, "java.lang.Boolean"))
00159         type = JAVA_SIGNATURE_JAVA_LANG_BOOLEAN;
00160     else if (!strcmp(java_class_name, "java.lang.Double"))
00161         type = JAVA_SIGNATURE_JAVA_LANG_DOUBLE;
00162     else if (!strcmp(java_class_name, "java.lang.String"))
00163         type = JAVA_SIGNATURE_JAVA_LANG_STRING;
00164     else if (!strcmp(java_class_name, "java.lang.Object"))
00165         type = JAVA_SIGNATURE_JAVA_LANG_OBJECT;
00166     else if (!strcmp(java_class_name, "java.lang.Class"))
00167         type = JAVA_SIGNATURE_JAVA_LANG_CLASS;
00168     else if (!strcmp(java_class_name, "netscape.javascript.JSObject"))
00169         type = JAVA_SIGNATURE_NETSCAPE_JAVASCRIPT_JSOBJECT;
00170     else
00171         type = JAVA_SIGNATURE_OBJECT;
00172     return type;
00173 }
00174 
00175 static JSBool
00176 is_java_array_class(JNIEnv *jEnv, jclass java_class)
00177 {
00178     return (*jEnv)->CallBooleanMethod(jEnv, java_class, jlClass_isArray);
00179 }
00180 
00181 /*
00182  * Return the class of a Java array's component type.  This is not the same
00183  * as the array's element type.  For example, the component type of an array
00184  * of type SomeType[][][] is SomeType[][], but its element type is SomeType.
00185  *
00186  * If an error occurs, NULL is returned and an error reported.
00187  */
00188 static jclass
00189 get_java_array_component_class(JSContext *cx, JNIEnv *jEnv, jclass java_class)
00190 {
00191     jclass result;
00192     result = (*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getComponentType);
00193     if (!result) {
00194         jsj_UnexpectedJavaError(cx, jEnv,
00195                                 "Can't get Java array component class using "
00196                                 "java.lang.Class.getComponentType()");
00197         return NULL;
00198     }
00199     return result;
00200 }
00201 
00202 /*
00203  * Given a Java class, fill in the signature structure that describes the class.
00204  * If an error occurs, JS_FALSE is returned and the error reporter called.
00205  */
00206 static JSBool
00207 compute_java_class_signature(JSContext *cx, JNIEnv *jEnv, JavaSignature *signature)
00208 {
00209     jclass java_class = signature->java_class;
00210 
00211     if (is_java_array_class(jEnv, java_class)) {
00212         jclass component_class;
00213         
00214         signature->type = JAVA_SIGNATURE_ARRAY;
00215 
00216         component_class = get_java_array_component_class(cx, jEnv, java_class);
00217         if (!component_class)
00218             return JS_FALSE;
00219 
00220         signature->array_component_signature =
00221             jsj_GetJavaClassDescriptor(cx, jEnv, component_class);
00222         if (!signature->array_component_signature) {
00223             (*jEnv)->DeleteLocalRef(jEnv, component_class);
00224             return JS_FALSE;
00225         }
00226     } else {
00227         signature->type = get_signature_type(cx, signature);
00228     }
00229     return JS_TRUE;
00230 }
00231 
00232 /*
00233  * Convert from JavaSignatureChar enumeration to single-character
00234  * signature used by the JDK and JNI methods.
00235  */
00236 static char
00237 get_jdk_signature_char(JavaSignatureChar type)
00238 {
00239     return "XVZCBSIJFD[LLLLLL"[(int)type];
00240 }
00241 
00242 /*
00243  * Convert a JavaSignature object into a string format as used by
00244  * the JNI functions, e.g. java.lang.Object ==> "Ljava/lang/Object;"
00245  * The caller is responsible for freeing the resulting string.
00246  *
00247  * If an error is encountered, NULL is returned and an error reported.
00248  */
00249 const char *
00250 jsj_ConvertJavaSignatureToString(JSContext *cx, JavaSignature *signature)
00251 {
00252     char *sig;
00253 
00254     if (IS_OBJECT_TYPE(signature->type)) {
00255         /* A non-array object class */
00256         sig = JS_smprintf("L%s;", signature->name);
00257         if (sig)
00258             jsj_MakeJNIClassname(sig);
00259 
00260     } else if (signature->type == JAVA_SIGNATURE_ARRAY) {
00261         /* An array class */
00262         const char *component_signature_string;
00263 
00264         component_signature_string =
00265             jsj_ConvertJavaSignatureToString(cx, signature->array_component_signature);
00266         if (!component_signature_string)
00267             return NULL;
00268         sig = JS_smprintf("[%s", component_signature_string);
00269         JS_free(cx, (char*)component_signature_string);
00270 
00271     } else {
00272         /* A primitive class */
00273         sig = JS_smprintf("%c", get_jdk_signature_char(signature->type));
00274     }
00275 
00276     if (!sig) {
00277         JS_ReportOutOfMemory(cx);
00278         return NULL;
00279     }
00280     return sig;
00281 }
00282 
00283 /*
00284  * Convert a JavaSignature object into a human-readable string format as seen
00285  * in Java source files, e.g. "byte", or "int[][]" or "java.lang.String".
00286  * The caller is responsible for freeing the resulting string.
00287  *
00288  * If an error is encountered, NULL is returned and an error reported.
00289  */
00290 const char *
00291 jsj_ConvertJavaSignatureToHRString(JSContext *cx,
00292                                    JavaSignature *signature)
00293 {
00294     char *sig;
00295     JavaSignature *acs;
00296 
00297     if (signature->type == JAVA_SIGNATURE_ARRAY) {
00298         /* An array class */
00299         const char *component_signature_string;
00300         acs = signature->array_component_signature;
00301         component_signature_string =
00302             jsj_ConvertJavaSignatureToHRString(cx, acs);
00303         if (!component_signature_string)
00304             return NULL;
00305         sig = JS_smprintf("%s[]", component_signature_string);
00306         JS_free(cx, (char*)component_signature_string);
00307 
00308     } else {
00309         /* A primitive class or a non-array object class */
00310         sig = JS_strdup(cx, signature->name);
00311     }
00312 
00313     if (!sig) {
00314         JS_ReportOutOfMemory(cx);
00315         return NULL;
00316     }
00317     return sig;
00318 }
00319 
00320 static void
00321 destroy_java_member_descriptor(JSContext *cx, JNIEnv *jEnv, JavaMemberDescriptor *member_descriptor)
00322 {
00323     JavaMethodSpec *method, *next_method;
00324     if (member_descriptor->field)
00325         jsj_DestroyFieldSpec(cx, jEnv, member_descriptor->field);
00326 
00327     method = member_descriptor->methods;
00328     while (method) {
00329         next_method = method->next;
00330         jsj_DestroyMethodSpec(cx, jEnv, method);
00331         method = next_method;
00332     }
00333 
00334     if (member_descriptor->invoke_func_obj)
00335         JS_RemoveRoot(cx, &member_descriptor->invoke_func_obj);
00336 
00337     JS_FREE_IF(cx, (char *)member_descriptor->name);
00338     JS_free(cx, member_descriptor);
00339 }
00340 
00341 static void
00342 destroy_class_member_descriptors(JSContext *cx, JNIEnv *jEnv, JavaMemberDescriptor *member_descriptor)
00343 {
00344     JavaMemberDescriptor *next_member;
00345     
00346     while (member_descriptor) {
00347         next_member = member_descriptor->next;
00348         destroy_java_member_descriptor(cx, jEnv, member_descriptor);
00349         member_descriptor = next_member;
00350     }
00351 }
00352 
00353 static void
00354 destroy_class_descriptor(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor)
00355 {
00356     JS_FREE_IF(cx, (char *)class_descriptor->name);
00357     if (class_descriptor->java_class)
00358         (*jEnv)->DeleteGlobalRef(jEnv, class_descriptor->java_class);
00359 
00360     if (class_descriptor->array_component_signature)
00361         jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor->array_component_signature);
00362 
00363     destroy_class_member_descriptors(cx, jEnv, class_descriptor->instance_members);
00364     destroy_class_member_descriptors(cx, jEnv, class_descriptor->static_members);
00365     destroy_class_member_descriptors(cx, jEnv, class_descriptor->constructors);
00366     JS_free(cx, class_descriptor);
00367 }
00368 
00369 static JavaClassDescriptor *
00370 new_class_descriptor(JSContext *cx, JNIEnv *jEnv, jclass java_class)
00371 {
00372     JavaClassDescriptor *class_descriptor;
00373 
00374     class_descriptor = (JavaClassDescriptor *)JS_malloc(cx, sizeof(JavaClassDescriptor));
00375     if (!class_descriptor)
00376         return NULL;
00377     memset(class_descriptor, 0, sizeof(JavaClassDescriptor));
00378 
00379     class_descriptor->name = jsj_GetJavaClassName(cx, jEnv, java_class);
00380     if (!class_descriptor->name)
00381         goto error;
00382 
00383     java_class = (*jEnv)->NewGlobalRef(jEnv, java_class);
00384     if (!java_class) {
00385         jsj_UnexpectedJavaError(cx, jEnv, "Unable to reference Java class");
00386         goto error;
00387     }
00388     class_descriptor->java_class = java_class;
00389 
00390     if (!compute_java_class_signature(cx, jEnv, class_descriptor))
00391         goto error;
00392 
00393     class_descriptor->modifiers =
00394         (*jEnv)->CallIntMethod(jEnv, java_class, jlClass_getModifiers);
00395     class_descriptor->ref_count = 1;
00396 
00397     if (!JSJ_HashTableAdd(java_class_reflections, java_class, class_descriptor,
00398                           (void*)jEnv))
00399         goto error;
00400 
00401     return class_descriptor;
00402 
00403 error:
00404     destroy_class_descriptor(cx, jEnv, class_descriptor);
00405     return NULL;
00406 }
00407 
00408 /* Trivial helper for jsj_DiscardJavaClassReflections(), below */
00409 JS_STATIC_DLL_CALLBACK(JSIntn)
00410 enumerate_remove_java_class(JSJHashEntry *he, JSIntn i, void *arg)
00411 {
00412     JSJavaThreadState *jsj_env = (JSJavaThreadState *)arg;
00413     JavaClassDescriptor *class_descriptor;
00414 
00415     class_descriptor = (JavaClassDescriptor*)he->value;
00416 
00417     destroy_class_descriptor(jsj_env->cx, jsj_env->jEnv, class_descriptor);
00418 
00419     return HT_ENUMERATE_REMOVE;
00420 }
00421 
00422 /* This shutdown routine discards all JNI references to Java objects
00423    that have been reflected into JS, even if there are still references
00424    to them from JS. */
00425 void
00426 jsj_DiscardJavaClassReflections(JNIEnv *jEnv)
00427 {
00428     JSJavaThreadState *jsj_env;
00429     char *err_msg;
00430     JSContext *cx;
00431 
00432     /* Get the per-thread state corresponding to the current Java thread */
00433     jsj_env = jsj_MapJavaThreadToJSJavaThreadState(jEnv, &err_msg);
00434     JS_ASSERT(jsj_env);
00435     if (!jsj_env)
00436         return;
00437 
00438     /* Get the JSContext that we're supposed to use for this Java thread */
00439     cx = jsj_env->cx;
00440     if (!cx) {
00441         /* We called spontaneously into JS from Java, rather than from JS into
00442            Java and back into JS.  Invoke a callback to obtain/create a
00443            JSContext for us to use. */
00444         if (JSJ_callbacks->map_jsj_thread_to_js_context) {
00445 #ifdef OJI
00446             cx = JSJ_callbacks->map_jsj_thread_to_js_context(jsj_env,
00447                                                              NULL, /* FIXME: What should this argument be ? */
00448                                                              jEnv, &err_msg);
00449 #else
00450             cx = JSJ_callbacks->map_jsj_thread_to_js_context(jsj_env,
00451                                                              jEnv, &err_msg);
00452 #endif
00453             if (!cx)
00454                 return;
00455         } else {
00456             err_msg = JS_smprintf("Unable to find/create JavaScript execution "
00457                                   "context for JNI thread 0x%08x", jEnv);
00458             jsj_LogError(err_msg);
00459             free(err_msg);
00460             return;
00461         }
00462     }
00463 
00464     if (java_class_reflections) {
00465         JSJ_HashTableEnumerateEntries(java_class_reflections,
00466                                       enumerate_remove_java_class,
00467                                       (void*)jsj_env);
00468         JSJ_HashTableDestroy(java_class_reflections);
00469         java_class_reflections = NULL;
00470     }
00471 }
00472 
00473 extern JavaClassDescriptor *
00474 jsj_GetJavaClassDescriptor(JSContext *cx, JNIEnv *jEnv, jclass java_class)
00475 {
00476     JavaClassDescriptor *class_descriptor = NULL;
00477 
00478 #ifdef JSJ_THREADSAFE
00479     PR_EnterMonitor(java_class_reflections_monitor);
00480 #endif
00481 
00482     if (java_class_reflections) {
00483         class_descriptor = JSJ_HashTableLookup(java_class_reflections,
00484                                                (const void *)java_class,
00485                                                (void*)jEnv);
00486     }
00487     if (!class_descriptor) {
00488         class_descriptor = new_class_descriptor(cx, jEnv, java_class);
00489 
00490 #ifdef JSJ_THREADSAFE
00491         PR_ExitMonitor(java_class_reflections_monitor);
00492 #endif
00493         return class_descriptor;
00494     }
00495 
00496 #ifdef JSJ_THREADSAFE
00497     PR_ExitMonitor(java_class_reflections_monitor);
00498 #endif
00499 
00500     JS_ASSERT(class_descriptor->ref_count > 0);
00501     class_descriptor->ref_count++;
00502     return class_descriptor;
00503 }
00504 
00505 void
00506 jsj_ReleaseJavaClassDescriptor(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor)
00507 {
00508 #if 0
00509     /* The ref-counting code doesn't work very well because cycles in the data
00510        structures routinely lead to uncollectible JavaClassDescriptor's.  Skip it. */
00511     JS_ASSERT(class_descriptor->ref_count >= 1);
00512     if (!--class_descriptor->ref_count) {
00513         JSJ_HashTableRemove(java_class_reflections,
00514                             class_descriptor->java_class, (void*)jEnv);
00515         destroy_class_descriptor(cx, jEnv, class_descriptor);
00516     }
00517 #endif
00518 }
00519 
00520 #ifdef JSJ_THREADSAFE
00521 static PRMonitor *java_reflect_monitor = NULL;
00522 #endif
00523 
00524 static JSBool
00525 reflect_java_methods_and_fields(JSContext *cx,
00526                                 JNIEnv *jEnv,
00527                                 JavaClassDescriptor *class_descriptor,
00528                                 JSBool reflect_statics_only)
00529 {
00530     JavaMemberDescriptor *member_descriptor;
00531     JSBool success;
00532 
00533     success = JS_TRUE;  /* optimism */
00534 
00535 #ifdef JSJ_THREADSAFE
00536     PR_EnterMonitor(java_reflect_monitor);
00537 #endif
00538 
00539     /* See if we raced with another thread to reflect members of this class.
00540        If the status is REFLECT_COMPLETE, another thread beat us to it.  If
00541        the status is REFLECT_IN_PROGRESS, we've recursively called this
00542        function within a single thread.  Either way, we're done. */
00543     if (reflect_statics_only) {
00544         if (class_descriptor->static_members_reflected != REFLECT_NO)
00545             goto done;
00546         class_descriptor->static_members_reflected = REFLECT_IN_PROGRESS;
00547     } else {
00548         if (class_descriptor->instance_members_reflected != REFLECT_NO)
00549             goto done;
00550         class_descriptor->instance_members_reflected = REFLECT_IN_PROGRESS;
00551     }
00552     
00553     if (!jsj_ReflectJavaMethods(cx, jEnv, class_descriptor, reflect_statics_only))
00554         goto error;
00555     if (!jsj_ReflectJavaFields(cx, jEnv, class_descriptor, reflect_statics_only))
00556         goto error;
00557 
00558     if (reflect_statics_only) {
00559         member_descriptor = class_descriptor->static_members;
00560         while (member_descriptor) {
00561             class_descriptor->num_static_members++;
00562             member_descriptor = member_descriptor->next;
00563         }
00564         class_descriptor->static_members_reflected = REFLECT_COMPLETE;
00565     } else {
00566         member_descriptor = class_descriptor->instance_members;
00567         while (member_descriptor) {
00568             class_descriptor->num_instance_members++;
00569             member_descriptor = member_descriptor->next;
00570         }
00571         class_descriptor->instance_members_reflected = REFLECT_COMPLETE;
00572     }
00573 
00574 done:
00575 #ifdef JSJ_THREADSAFE
00576     PR_ExitMonitor(java_reflect_monitor);
00577 #endif
00578     return success;
00579 
00580 error:
00581     success = JS_FALSE;
00582     goto done;
00583 }
00584 
00585 JavaMemberDescriptor *
00586 jsj_GetClassStaticMembers(JSContext *cx,
00587                           JNIEnv *jEnv,
00588                           JavaClassDescriptor *class_descriptor)
00589 {
00590     if (class_descriptor->static_members_reflected != REFLECT_COMPLETE)
00591         reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_TRUE);
00592     return class_descriptor->static_members;
00593 }
00594 
00595 JavaMemberDescriptor *
00596 jsj_GetClassInstanceMembers(JSContext *cx,
00597                             JNIEnv *jEnv,
00598                             JavaClassDescriptor *class_descriptor)
00599 {
00600     if (class_descriptor->instance_members_reflected != REFLECT_COMPLETE)
00601         reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_FALSE);
00602     return class_descriptor->instance_members;
00603 }
00604 
00605 JavaMemberDescriptor *
00606 jsj_LookupJavaStaticMemberDescriptorById(JSContext *cx,
00607                                          JNIEnv *jEnv,
00608                                          JavaClassDescriptor *class_descriptor,
00609                                          jsid id)
00610 {
00611     JavaMemberDescriptor *member_descriptor;
00612 
00613     member_descriptor = jsj_GetClassStaticMembers(cx, jEnv, class_descriptor);
00614     while (member_descriptor) {
00615         if (id == member_descriptor->id)
00616             return member_descriptor;
00617         member_descriptor = member_descriptor->next;
00618     }
00619     return NULL;
00620 }
00621 
00622 JavaMemberDescriptor *
00623 jsj_GetJavaStaticMemberDescriptor(JSContext *cx,
00624                                   JNIEnv *jEnv, 
00625                                   JavaClassDescriptor *class_descriptor,
00626                                   jstring member_name_jstr)
00627 {
00628     JavaMemberDescriptor *member_descriptor;
00629     jsid id;
00630 
00631     if (!JavaStringToId(cx, jEnv, member_name_jstr, &id))
00632         return NULL;
00633 
00634     member_descriptor = jsj_LookupJavaStaticMemberDescriptorById(cx, jEnv, class_descriptor, id);
00635     if (member_descriptor)
00636         return member_descriptor;
00637 
00638     member_descriptor = JS_malloc(cx, sizeof(JavaMemberDescriptor));
00639     if (!member_descriptor)
00640         return NULL;
00641     memset(member_descriptor, 0, sizeof(JavaMemberDescriptor));
00642 
00643     member_descriptor->name = jsj_DupJavaStringUTF(cx, jEnv, member_name_jstr);
00644     if (!member_descriptor->name) {
00645         JS_free(cx, member_descriptor);
00646         return NULL;
00647     }
00648     member_descriptor->id = id;
00649 
00650     member_descriptor->next = class_descriptor->static_members;
00651     class_descriptor->static_members = member_descriptor;
00652 
00653     return member_descriptor;
00654 }
00655 
00656 JavaMemberDescriptor *
00657 jsj_GetJavaClassConstructors(JSContext *cx,
00658                              JavaClassDescriptor *class_descriptor)
00659 {
00660     JavaMemberDescriptor *member_descriptor;
00661 
00662     if (class_descriptor->constructors)
00663         return class_descriptor->constructors;
00664 
00665     member_descriptor = JS_malloc(cx, sizeof(JavaMemberDescriptor));
00666     if (!member_descriptor)
00667         return NULL;
00668     memset(member_descriptor, 0, sizeof(JavaMemberDescriptor));
00669 
00670     member_descriptor->name = JS_strdup(cx, "<init>");
00671     if (!member_descriptor->name) {
00672         JS_free(cx, member_descriptor);
00673         return NULL;
00674     }
00675 
00676     class_descriptor->constructors = member_descriptor;
00677 
00678     return member_descriptor;
00679 }
00680 
00681 JavaMemberDescriptor *
00682 jsj_LookupJavaClassConstructors(JSContext *cx, JNIEnv *jEnv,
00683                                 JavaClassDescriptor *class_descriptor)
00684 {
00685     if (class_descriptor->static_members_reflected != REFLECT_COMPLETE)
00686         reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_TRUE);
00687     return class_descriptor->constructors;
00688 }
00689 
00690 JavaMemberDescriptor *
00691 jsj_LookupJavaMemberDescriptorById(JSContext *cx, JNIEnv *jEnv,
00692                                    JavaClassDescriptor *class_descriptor,
00693                                    jsid id)
00694 {
00695     JavaMemberDescriptor *member_descriptor;
00696 
00697     member_descriptor = jsj_GetClassInstanceMembers(cx, jEnv, class_descriptor);
00698     while (member_descriptor) {
00699         if (id == member_descriptor->id)
00700             return member_descriptor;
00701         member_descriptor = member_descriptor->next;
00702     }
00703     return NULL;
00704 }
00705 
00706 JavaMemberDescriptor *
00707 jsj_GetJavaMemberDescriptor(JSContext *cx,
00708                             JNIEnv *jEnv, 
00709                             JavaClassDescriptor *class_descriptor,
00710                             jstring member_name_jstr)
00711 {
00712     JavaMemberDescriptor *member_descriptor;
00713     jsid id;
00714 
00715     if (!JavaStringToId(cx, jEnv, member_name_jstr, &id))
00716         return NULL;
00717 
00718     member_descriptor = jsj_LookupJavaMemberDescriptorById(cx, jEnv, class_descriptor, id);
00719     if (member_descriptor)
00720         return member_descriptor;
00721 
00722     member_descriptor = JS_malloc(cx, sizeof(JavaMemberDescriptor));
00723     if (!member_descriptor)
00724         return NULL;
00725     memset(member_descriptor, 0, sizeof(JavaMemberDescriptor));
00726 
00727     member_descriptor->name = jsj_DupJavaStringUTF(cx, jEnv, member_name_jstr);
00728     if (!member_descriptor->name) {
00729         JS_free(cx, member_descriptor);
00730         return NULL;
00731     }
00732     member_descriptor->id = id;
00733 
00734     member_descriptor->next = class_descriptor->instance_members;
00735     class_descriptor->instance_members = member_descriptor;
00736 
00737     return member_descriptor;
00738 }
00739 
00740 JSBool
00741 jsj_InitJavaClassReflectionsTable()
00742 {
00743     if (!java_class_reflections) {
00744         java_class_reflections =
00745             JSJ_NewHashTable(64, jsj_HashJavaObject, jsj_JavaObjectComparator,
00746                             NULL, NULL, NULL);
00747 
00748         if (!java_class_reflections)
00749             return JS_FALSE;
00750 
00751 #ifdef JSJ_THREADSAFE
00752         java_class_reflections_monitor =
00753                 (struct PRMonitor *) PR_NewMonitor();
00754         if (!java_class_reflections_monitor)
00755             return JS_FALSE;
00756 
00757         java_reflect_monitor =
00758                 (struct PRMonitor *) PR_NewMonitor();
00759         if (!java_reflect_monitor)
00760             return JS_FALSE;
00761 #endif
00762     }
00763     
00764     return JS_TRUE;
00765 }