Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / js / src / liveconnect / jsj_class.c
blob7f4261ef0ec0533812889de6365e0075a1df6b69
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is Mozilla Communicator client code, released
17 * March 31, 1998.
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1998
22 * the Initial Developer. All Rights Reserved.
24 * Contributor(s):
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
41 * This file is part of the Java-vendor-neutral implementation of LiveConnect
43 * It contains the code that constructs and manipulates JavaClassDescriptor
44 * structs, which are the native wrappers for Java classes.
45 * JavaClassDescriptors are used to describe the signatures of methods and
46 * fields. There is a JavaClassDescriptor associated with the reflection of
47 * each Java Object.
50 #include <stdlib.h>
51 #include <string.h>
53 #include "jsj_private.h" /* LiveConnect internals */
54 #include "jsj_hash.h" /* Hash tables */
56 #ifdef JSJ_THREADSAFE
57 # include "prmon.h"
58 #endif
60 /* A one-to-one mapping between all referenced java.lang.Class objects and
61 their corresponding JavaClassDescriptor objects */
62 static JSJHashTable *java_class_reflections;
64 #ifdef JSJ_THREADSAFE
65 static PRMonitor *java_class_reflections_monitor;
66 #endif
69 * Given a JVM handle to a java.lang.Class object, malloc a C-string
70 * containing the UTF8 encoding of the fully qualified name of the class.
71 * It's the caller's responsibility to free the returned string.
73 * If an error occurs, NULL is returned and the error reporter called.
75 const char *
76 jsj_GetJavaClassName(JSContext *cx, JNIEnv *jEnv, jclass java_class)
78 jstring java_class_name_jstr;
79 const char *java_class_name;
81 /* Get java.lang.String object containing class name */
82 java_class_name_jstr =
83 (*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getName);
85 if (!java_class_name_jstr)
86 goto error;
88 /* Fix bugzilla #183092
89 * It is necessary to check Exception from JPI
90 * even though java_class_name_jstr != null */
91 #ifdef XP_UNIX
92 if ((*jEnv)->ExceptionOccurred(jEnv))
93 goto error;
94 #endif
96 /* Convert to UTF8 encoding and copy */
97 java_class_name = jsj_DupJavaStringUTF(cx, jEnv, java_class_name_jstr);
99 (*jEnv)->DeleteLocalRef(jEnv, java_class_name_jstr);
100 return java_class_name;
102 error:
103 jsj_UnexpectedJavaError(cx, jEnv, "Can't get Java class name using"
104 "java.lang.Class.getName()");
105 return NULL;
109 * Convert in-place a string of the form "java.lang.String" into "java/lang/String".
110 * Though the former style is conventionally used by Java programmers, the latter is
111 * what the JNI functions require.
113 void
114 jsj_MakeJNIClassname(char * class_name)
116 char * c;
117 for (c = class_name; *c; c++)
118 if (*c == '.')
119 *c = '/';
123 * Classify an instance of java.lang.Class as either one of the primitive
124 * types, e.g. int, char, etc., as an array type or as a non-array object type
125 * (subclass of java.lang.Object) by returning the appropriate enum member.
128 static JavaSignatureChar
129 get_signature_type(JSContext *cx, JavaClassDescriptor *class_descriptor)
131 JavaSignatureChar type;
132 const char *java_class_name;
134 /* Get UTF8 encoding of class name */
135 java_class_name = class_descriptor->name;
136 JS_ASSERT(java_class_name);
137 if (!java_class_name)
138 return JAVA_SIGNATURE_UNKNOWN;
140 if (!strcmp(java_class_name, "byte"))
141 type = JAVA_SIGNATURE_BYTE;
142 else if (!strcmp(java_class_name, "char"))
143 type = JAVA_SIGNATURE_CHAR;
144 else if (!strcmp(java_class_name, "float"))
145 type = JAVA_SIGNATURE_FLOAT;
146 else if (!strcmp(java_class_name, "double"))
147 type = JAVA_SIGNATURE_DOUBLE;
148 else if (!strcmp(java_class_name, "int"))
149 type = JAVA_SIGNATURE_INT;
150 else if (!strcmp(java_class_name, "long"))
151 type = JAVA_SIGNATURE_LONG;
152 else if (!strcmp(java_class_name, "short"))
153 type = JAVA_SIGNATURE_SHORT;
154 else if (!strcmp(java_class_name, "boolean"))
155 type = JAVA_SIGNATURE_BOOLEAN;
156 else if (!strcmp(java_class_name, "void"))
157 type = JAVA_SIGNATURE_VOID;
158 else if (!strcmp(java_class_name, "java.lang.Boolean"))
159 type = JAVA_SIGNATURE_JAVA_LANG_BOOLEAN;
160 else if (!strcmp(java_class_name, "java.lang.Double"))
161 type = JAVA_SIGNATURE_JAVA_LANG_DOUBLE;
162 else if (!strcmp(java_class_name, "java.lang.String"))
163 type = JAVA_SIGNATURE_JAVA_LANG_STRING;
164 else if (!strcmp(java_class_name, "java.lang.Object"))
165 type = JAVA_SIGNATURE_JAVA_LANG_OBJECT;
166 else if (!strcmp(java_class_name, "java.lang.Class"))
167 type = JAVA_SIGNATURE_JAVA_LANG_CLASS;
168 else if (!strcmp(java_class_name, "netscape.javascript.JSObject"))
169 type = JAVA_SIGNATURE_NETSCAPE_JAVASCRIPT_JSOBJECT;
170 else
171 type = JAVA_SIGNATURE_OBJECT;
172 return type;
175 static JSBool
176 is_java_array_class(JNIEnv *jEnv, jclass java_class)
178 return (*jEnv)->CallBooleanMethod(jEnv, java_class, jlClass_isArray);
182 * Return the class of a Java array's component type. This is not the same
183 * as the array's element type. For example, the component type of an array
184 * of type SomeType[][][] is SomeType[][], but its element type is SomeType.
186 * If an error occurs, NULL is returned and an error reported.
188 static jclass
189 get_java_array_component_class(JSContext *cx, JNIEnv *jEnv, jclass java_class)
191 jclass result;
192 result = (*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getComponentType);
193 if (!result) {
194 jsj_UnexpectedJavaError(cx, jEnv,
195 "Can't get Java array component class using "
196 "java.lang.Class.getComponentType()");
197 return NULL;
199 return result;
203 * Given a Java class, fill in the signature structure that describes the class.
204 * If an error occurs, JS_FALSE is returned and the error reporter called.
206 static JSBool
207 compute_java_class_signature(JSContext *cx, JNIEnv *jEnv, JavaSignature *signature)
209 jclass java_class = signature->java_class;
211 if (is_java_array_class(jEnv, java_class)) {
212 jclass component_class;
214 signature->type = JAVA_SIGNATURE_ARRAY;
216 component_class = get_java_array_component_class(cx, jEnv, java_class);
217 if (!component_class)
218 return JS_FALSE;
220 signature->array_component_signature =
221 jsj_GetJavaClassDescriptor(cx, jEnv, component_class);
222 if (!signature->array_component_signature) {
223 (*jEnv)->DeleteLocalRef(jEnv, component_class);
224 return JS_FALSE;
226 } else {
227 signature->type = get_signature_type(cx, signature);
229 return JS_TRUE;
233 * Convert from JavaSignatureChar enumeration to single-character
234 * signature used by the JDK and JNI methods.
236 static char
237 get_jdk_signature_char(JavaSignatureChar type)
239 return "XVZCBSIJFD[LLLLLL"[(int)type];
243 * Convert a JavaSignature object into a string format as used by
244 * the JNI functions, e.g. java.lang.Object ==> "Ljava/lang/Object;"
245 * The caller is responsible for freeing the resulting string.
247 * If an error is encountered, NULL is returned and an error reported.
249 const char *
250 jsj_ConvertJavaSignatureToString(JSContext *cx, JavaSignature *signature)
252 char *sig;
254 if (IS_OBJECT_TYPE(signature->type)) {
255 /* A non-array object class */
256 sig = JS_smprintf("L%s;", signature->name);
257 if (sig)
258 jsj_MakeJNIClassname(sig);
260 } else if (signature->type == JAVA_SIGNATURE_ARRAY) {
261 /* An array class */
262 const char *component_signature_string;
264 component_signature_string =
265 jsj_ConvertJavaSignatureToString(cx, signature->array_component_signature);
266 if (!component_signature_string)
267 return NULL;
268 sig = JS_smprintf("[%s", component_signature_string);
269 JS_smprintf_free((char*)component_signature_string);
271 } else {
272 /* A primitive class */
273 sig = JS_smprintf("%c", get_jdk_signature_char(signature->type));
276 if (!sig) {
277 JS_ReportOutOfMemory(cx);
278 return NULL;
280 return sig;
284 * Convert a JavaSignature object into a human-readable string format as seen
285 * in Java source files, e.g. "byte", or "int[][]" or "java.lang.String".
286 * The caller is responsible for freeing the resulting string.
288 * If an error is encountered, NULL is returned and an error reported.
290 const char *
291 jsj_ConvertJavaSignatureToHRString(JSContext *cx,
292 JavaSignature *signature)
294 char *sig;
295 JavaSignature *acs;
297 if (signature->type == JAVA_SIGNATURE_ARRAY) {
298 /* An array class */
299 const char *component_signature_string;
300 acs = signature->array_component_signature;
301 component_signature_string =
302 jsj_ConvertJavaSignatureToHRString(cx, acs);
303 if (!component_signature_string)
304 return NULL;
305 sig = JS_smprintf("%s[]", component_signature_string);
306 JS_smprintf_free((char*)component_signature_string);
308 } else {
309 /* A primitive class or a non-array object class */
310 sig = JS_smprintf("%s", signature->name);
313 if (!sig) {
314 JS_ReportOutOfMemory(cx);
315 return NULL;
317 return sig;
320 static void
321 destroy_java_member_descriptor(JSContext *cx, JNIEnv *jEnv, JavaMemberDescriptor *member_descriptor)
323 JavaMethodSpec *method, *next_method;
324 if (member_descriptor->field)
325 jsj_DestroyFieldSpec(cx, jEnv, member_descriptor->field);
327 method = member_descriptor->methods;
328 while (method) {
329 next_method = method->next;
330 jsj_DestroyMethodSpec(cx, jEnv, method);
331 method = next_method;
334 JS_RemoveRoot(cx, &member_descriptor->invoke_func_obj);
335 JS_FREE_IF(cx, (char *)member_descriptor->name);
336 JS_free(cx, member_descriptor);
339 static void
340 destroy_class_member_descriptors(JSContext *cx, JNIEnv *jEnv, JavaMemberDescriptor *member_descriptor)
342 JavaMemberDescriptor *next_member;
344 while (member_descriptor) {
345 next_member = member_descriptor->next;
346 destroy_java_member_descriptor(cx, jEnv, member_descriptor);
347 member_descriptor = next_member;
351 static void
352 destroy_class_descriptor(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor)
354 JS_FREE_IF(cx, (char *)class_descriptor->name);
355 if (class_descriptor->java_class)
356 (*jEnv)->DeleteGlobalRef(jEnv, class_descriptor->java_class);
358 if (class_descriptor->array_component_signature)
359 jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor->array_component_signature);
361 destroy_class_member_descriptors(cx, jEnv, class_descriptor->instance_members);
362 destroy_class_member_descriptors(cx, jEnv, class_descriptor->static_members);
363 destroy_class_member_descriptors(cx, jEnv, class_descriptor->constructors);
364 JS_free(cx, class_descriptor);
367 static JavaClassDescriptor *
368 new_class_descriptor(JSContext *cx, JNIEnv *jEnv, jclass java_class)
370 JavaClassDescriptor *class_descriptor;
372 class_descriptor = (JavaClassDescriptor *)JS_malloc(cx, sizeof(JavaClassDescriptor));
373 if (!class_descriptor)
374 return NULL;
375 memset(class_descriptor, 0, sizeof(JavaClassDescriptor));
377 class_descriptor->name = jsj_GetJavaClassName(cx, jEnv, java_class);
378 if (!class_descriptor->name)
379 goto error;
381 java_class = (*jEnv)->NewGlobalRef(jEnv, java_class);
382 if (!java_class) {
383 jsj_UnexpectedJavaError(cx, jEnv, "Unable to reference Java class");
384 goto error;
386 class_descriptor->java_class = java_class;
388 if (!compute_java_class_signature(cx, jEnv, class_descriptor))
389 goto error;
391 class_descriptor->modifiers =
392 (*jEnv)->CallIntMethod(jEnv, java_class, jlClass_getModifiers);
393 class_descriptor->ref_count = 1;
395 if (!JSJ_HashTableAdd(java_class_reflections, java_class, class_descriptor,
396 (void*)jEnv))
397 goto error;
399 return class_descriptor;
401 error:
402 destroy_class_descriptor(cx, jEnv, class_descriptor);
403 return NULL;
406 /* Trivial helper for jsj_DiscardJavaClassReflections(), below */
407 static JSIntn
408 enumerate_remove_java_class(JSJHashEntry *he, JSIntn i, void *arg)
410 JSJavaThreadState *jsj_env = (JSJavaThreadState *)arg;
411 JavaClassDescriptor *class_descriptor;
413 class_descriptor = (JavaClassDescriptor*)he->value;
415 destroy_class_descriptor(jsj_env->cx, jsj_env->jEnv, class_descriptor);
417 return HT_ENUMERATE_REMOVE;
420 /* This shutdown routine discards all JNI references to Java objects
421 that have been reflected into JS, even if there are still references
422 to them from JS. */
423 void
424 jsj_DiscardJavaClassReflections(JNIEnv *jEnv)
426 JSJavaThreadState *jsj_env;
427 char *err_msg;
428 JSContext *cx;
430 /* Get the per-thread state corresponding to the current Java thread */
431 jsj_env = jsj_MapJavaThreadToJSJavaThreadState(jEnv, &err_msg);
432 JS_ASSERT(jsj_env);
433 if (!jsj_env)
434 goto error;
436 /* Get the JSContext that we're supposed to use for this Java thread */
437 cx = jsj_env->cx;
438 if (!cx) {
439 /* We called spontaneously into JS from Java, rather than from JS into
440 Java and back into JS. Invoke a callback to obtain/create a
441 JSContext for us to use. */
442 if (JSJ_callbacks->map_jsj_thread_to_js_context) {
443 #ifdef OJI
444 cx = JSJ_callbacks->map_jsj_thread_to_js_context(jsj_env,
445 NULL, /* FIXME: What should this argument be ? */
446 jEnv, &err_msg);
447 #else
448 cx = JSJ_callbacks->map_jsj_thread_to_js_context(jsj_env,
449 jEnv, &err_msg);
450 #endif
451 if (!cx)
452 goto error;
453 } else {
454 err_msg = JS_smprintf("Unable to find/create JavaScript execution "
455 "context for JNI thread 0x%08x", jEnv);
456 goto error;
460 if (java_class_reflections) {
461 JSJ_HashTableEnumerateEntries(java_class_reflections,
462 enumerate_remove_java_class,
463 (void*)jsj_env);
464 JSJ_HashTableDestroy(java_class_reflections);
465 java_class_reflections = NULL;
468 return;
470 error:
471 JS_ASSERT(!cx);
472 if (err_msg) {
473 jsj_LogError(err_msg);
474 JS_smprintf_free(err_msg);
478 extern JavaClassDescriptor *
479 jsj_GetJavaClassDescriptor(JSContext *cx, JNIEnv *jEnv, jclass java_class)
481 JavaClassDescriptor *class_descriptor = NULL;
483 #ifdef JSJ_THREADSAFE
484 PR_EnterMonitor(java_class_reflections_monitor);
485 #endif
487 if (java_class_reflections) {
488 class_descriptor = JSJ_HashTableLookup(java_class_reflections,
489 (const void *)java_class,
490 (void*)jEnv);
492 if (!class_descriptor) {
493 class_descriptor = new_class_descriptor(cx, jEnv, java_class);
495 #ifdef JSJ_THREADSAFE
496 PR_ExitMonitor(java_class_reflections_monitor);
497 #endif
498 return class_descriptor;
501 #ifdef JSJ_THREADSAFE
502 PR_ExitMonitor(java_class_reflections_monitor);
503 #endif
505 JS_ASSERT(class_descriptor->ref_count > 0);
506 class_descriptor->ref_count++;
507 return class_descriptor;
510 void
511 jsj_ReleaseJavaClassDescriptor(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor)
513 #if 0
514 /* The ref-counting code doesn't work very well because cycles in the data
515 structures routinely lead to uncollectible JavaClassDescriptor's. Skip it. */
516 JS_ASSERT(class_descriptor->ref_count >= 1);
517 if (!--class_descriptor->ref_count) {
518 JSJ_HashTableRemove(java_class_reflections,
519 class_descriptor->java_class, (void*)jEnv);
520 destroy_class_descriptor(cx, jEnv, class_descriptor);
522 #endif
525 #ifdef JSJ_THREADSAFE
526 static PRMonitor *java_reflect_monitor = NULL;
527 #endif
529 static JSBool
530 reflect_java_methods_and_fields(JSContext *cx,
531 JNIEnv *jEnv,
532 JavaClassDescriptor *class_descriptor,
533 JSBool reflect_statics_only)
535 JavaMemberDescriptor *member_descriptor;
536 JSBool success;
538 success = JS_TRUE; /* optimism */
540 #ifdef JSJ_THREADSAFE
541 PR_EnterMonitor(java_reflect_monitor);
542 #endif
544 /* See if we raced with another thread to reflect members of this class.
545 If the status is REFLECT_COMPLETE, another thread beat us to it. If
546 the status is REFLECT_IN_PROGRESS, we've recursively called this
547 function within a single thread. Either way, we're done. */
548 if (reflect_statics_only) {
549 if (class_descriptor->static_members_reflected != REFLECT_NO)
550 goto done;
551 class_descriptor->static_members_reflected = REFLECT_IN_PROGRESS;
552 } else {
553 if (class_descriptor->instance_members_reflected != REFLECT_NO)
554 goto done;
555 class_descriptor->instance_members_reflected = REFLECT_IN_PROGRESS;
558 if (!jsj_ReflectJavaMethods(cx, jEnv, class_descriptor, reflect_statics_only))
559 goto error;
560 if (!jsj_ReflectJavaFields(cx, jEnv, class_descriptor, reflect_statics_only))
561 goto error;
563 if (reflect_statics_only) {
564 member_descriptor = class_descriptor->static_members;
565 while (member_descriptor) {
566 class_descriptor->num_static_members++;
567 member_descriptor = member_descriptor->next;
569 class_descriptor->static_members_reflected = REFLECT_COMPLETE;
570 } else {
571 member_descriptor = class_descriptor->instance_members;
572 while (member_descriptor) {
573 class_descriptor->num_instance_members++;
574 member_descriptor = member_descriptor->next;
576 class_descriptor->instance_members_reflected = REFLECT_COMPLETE;
579 done:
580 #ifdef JSJ_THREADSAFE
581 PR_ExitMonitor(java_reflect_monitor);
582 #endif
583 return success;
585 error:
586 success = JS_FALSE;
587 goto done;
590 JavaMemberDescriptor *
591 jsj_GetClassStaticMembers(JSContext *cx,
592 JNIEnv *jEnv,
593 JavaClassDescriptor *class_descriptor)
595 if (class_descriptor->static_members_reflected != REFLECT_COMPLETE)
596 reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_TRUE);
597 return class_descriptor->static_members;
600 JavaMemberDescriptor *
601 jsj_GetClassInstanceMembers(JSContext *cx,
602 JNIEnv *jEnv,
603 JavaClassDescriptor *class_descriptor)
605 if (class_descriptor->instance_members_reflected != REFLECT_COMPLETE)
606 reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_FALSE);
607 return class_descriptor->instance_members;
610 JavaMemberDescriptor *
611 jsj_LookupJavaStaticMemberDescriptorById(JSContext *cx,
612 JNIEnv *jEnv,
613 JavaClassDescriptor *class_descriptor,
614 jsid id)
616 JavaMemberDescriptor *member_descriptor;
618 member_descriptor = jsj_GetClassStaticMembers(cx, jEnv, class_descriptor);
619 while (member_descriptor) {
620 if (id == member_descriptor->id)
621 return member_descriptor;
622 member_descriptor = member_descriptor->next;
624 return NULL;
627 JavaMemberDescriptor *
628 jsj_GetJavaStaticMemberDescriptor(JSContext *cx,
629 JNIEnv *jEnv,
630 JavaClassDescriptor *class_descriptor,
631 jstring member_name_jstr)
633 JavaMemberDescriptor *member_descriptor;
634 jsid id;
636 if (!JavaStringToId(cx, jEnv, member_name_jstr, &id))
637 return NULL;
639 member_descriptor = jsj_LookupJavaStaticMemberDescriptorById(cx, jEnv, class_descriptor, id);
640 if (member_descriptor)
641 return member_descriptor;
643 member_descriptor = JS_malloc(cx, sizeof(JavaMemberDescriptor));
644 if (!member_descriptor)
645 return NULL;
646 memset(member_descriptor, 0, sizeof(JavaMemberDescriptor));
648 member_descriptor->name = jsj_DupJavaStringUTF(cx, jEnv, member_name_jstr);
649 if (!member_descriptor->name) {
650 JS_free(cx, member_descriptor);
651 return NULL;
653 member_descriptor->id = id;
655 member_descriptor->next = class_descriptor->static_members;
656 class_descriptor->static_members = member_descriptor;
658 return member_descriptor;
661 JavaMemberDescriptor *
662 jsj_GetJavaClassConstructors(JSContext *cx,
663 JavaClassDescriptor *class_descriptor)
665 JavaMemberDescriptor *member_descriptor;
667 if (class_descriptor->constructors)
668 return class_descriptor->constructors;
670 member_descriptor = JS_malloc(cx, sizeof(JavaMemberDescriptor));
671 if (!member_descriptor)
672 return NULL;
673 memset(member_descriptor, 0, sizeof(JavaMemberDescriptor));
675 member_descriptor->name = JS_strdup(cx, "<init>");
676 if (!member_descriptor->name) {
677 JS_free(cx, member_descriptor);
678 return NULL;
681 class_descriptor->constructors = member_descriptor;
683 return member_descriptor;
686 JavaMemberDescriptor *
687 jsj_LookupJavaClassConstructors(JSContext *cx, JNIEnv *jEnv,
688 JavaClassDescriptor *class_descriptor)
690 if (class_descriptor->static_members_reflected != REFLECT_COMPLETE)
691 reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_TRUE);
692 return class_descriptor->constructors;
695 JavaMemberDescriptor *
696 jsj_LookupJavaMemberDescriptorById(JSContext *cx, JNIEnv *jEnv,
697 JavaClassDescriptor *class_descriptor,
698 jsid id)
700 JavaMemberDescriptor *member_descriptor;
702 member_descriptor = jsj_GetClassInstanceMembers(cx, jEnv, class_descriptor);
703 while (member_descriptor) {
704 if (id == member_descriptor->id)
705 return member_descriptor;
706 member_descriptor = member_descriptor->next;
708 return NULL;
711 JavaMemberDescriptor *
712 jsj_GetJavaMemberDescriptor(JSContext *cx,
713 JNIEnv *jEnv,
714 JavaClassDescriptor *class_descriptor,
715 jstring member_name_jstr)
717 JavaMemberDescriptor *member_descriptor;
718 jsid id;
720 if (!JavaStringToId(cx, jEnv, member_name_jstr, &id))
721 return NULL;
723 member_descriptor = jsj_LookupJavaMemberDescriptorById(cx, jEnv, class_descriptor, id);
724 if (member_descriptor)
725 return member_descriptor;
727 member_descriptor = JS_malloc(cx, sizeof(JavaMemberDescriptor));
728 if (!member_descriptor)
729 return NULL;
730 memset(member_descriptor, 0, sizeof(JavaMemberDescriptor));
732 member_descriptor->name = jsj_DupJavaStringUTF(cx, jEnv, member_name_jstr);
733 if (!member_descriptor->name) {
734 JS_free(cx, member_descriptor);
735 return NULL;
737 member_descriptor->id = id;
739 member_descriptor->next = class_descriptor->instance_members;
740 class_descriptor->instance_members = member_descriptor;
742 return member_descriptor;
745 JSBool
746 jsj_InitJavaClassReflectionsTable()
748 if (!java_class_reflections) {
749 java_class_reflections =
750 JSJ_NewHashTable(64, jsj_HashJavaObject, jsj_JavaObjectComparator,
751 NULL, NULL, NULL);
753 if (!java_class_reflections)
754 return JS_FALSE;
756 #ifdef JSJ_THREADSAFE
757 java_class_reflections_monitor =
758 (struct PRMonitor *) PR_NewMonitor();
759 if (!java_class_reflections_monitor)
760 return JS_FALSE;
762 java_reflect_monitor =
763 (struct PRMonitor *) PR_NewMonitor();
764 if (!java_reflect_monitor)
765 return JS_FALSE;
766 #endif
769 return JS_TRUE;