1 /* src/native/native.c - table of native functions
3 Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 $Id: native.c 8299 2007-08-13 08:41:18Z michi $
35 #if defined(ENABLE_LTDL) && defined(HAVE_LTDL_H)
43 #include "mm/memory.h"
45 #include "native/jni.h"
46 #include "native/native.h"
48 #include "native/vm/nativevm.h"
50 #include "threads/lock-common.h"
52 #include "toolbox/avl.h"
53 #include "toolbox/hashtable.h"
54 #include "toolbox/logging.h"
56 #include "vm/builtin.h"
57 #include "vm/exceptions.h"
58 #include "vm/global.h"
59 #include "vm/stringlocal.h"
62 #include "vm/jit/asmpart.h"
63 #include "vm/jit/jit.h"
65 #include "vmcore/loader.h"
66 #include "vmcore/options.h"
67 #include "vm/resolve.h"
69 #if defined(ENABLE_JVMTI)
70 #include "native/jvmti/cacaodbg.h"
74 /* include table of native functions ******************************************/
76 #if defined(WITH_STATIC_CLASSPATH)
77 # include "native/nativetable.inc"
81 /* tables for methods *********************************************************/
83 #if defined(WITH_STATIC_CLASSPATH)
84 #define NATIVETABLESIZE (sizeof(nativetable)/sizeof(struct nativeref))
86 /* table for fast string comparison */
87 static nativecompref nativecomptable[NATIVETABLESIZE];
89 /* string comparsion table initialized */
90 static bool nativecompdone = false;
94 /* global variables ***********************************************************/
96 static avl_tree_t *tree_native_methods;
98 #if defined(ENABLE_LTDL)
99 static hashtable *hashtable_library;
103 /* prototypes *****************************************************************/
105 static s4 native_tree_native_methods_comparator(const void *treenode, const void *node);
108 /* native_init *****************************************************************
110 Initializes the native subsystem.
112 *******************************************************************************/
114 bool native_init(void)
116 #if defined(ENABLE_LTDL)
117 /* initialize libltdl */
120 vm_abort("native_init: lt_dlinit failed: %s\n", lt_dlerror());
122 /* initialize library hashtable, 10 entries should be enough */
124 hashtable_library = NEW(hashtable);
126 hashtable_create(hashtable_library, 10);
129 /* initialize the native methods table */
131 tree_native_methods = avl_create(&native_tree_native_methods_comparator);
133 /* everything's ok */
139 /* native_tree_native_methods_comparator ***************************************
141 Comparison function for AVL tree of native methods.
144 treenode....node in the tree
145 node........node to compare with tree-node
150 *******************************************************************************/
152 static s4 native_tree_native_methods_comparator(const void *treenode, const void *node)
154 const native_methods_node_t *treenmn;
155 const native_methods_node_t *nmn;
160 /* these are for walking the tree */
162 if (treenmn->classname < nmn->classname)
164 else if (treenmn->classname > nmn->classname)
167 if (treenmn->name < nmn->name)
169 else if (treenmn->name > nmn->name)
172 if (treenmn->descriptor < nmn->descriptor)
174 else if (treenmn->descriptor > nmn->descriptor)
177 /* all pointers are equal, we have found the entry */
183 /* native_make_overloaded_function *********************************************
187 *******************************************************************************/
189 #if !defined(WITH_STATIC_CLASSPATH)
190 static utf *native_make_overloaded_function(utf *name, utf *descriptor)
202 dumpsize = dump_size();
204 utf_ptr = descriptor->text;
205 namelen = strlen(name->text) + strlen("__") + strlen("0");
207 /* calculate additional length */
209 while ((c = utf_nextu2(&utf_ptr)) != ')') {
226 while (utf_nextu2(&utf_ptr) != ';')
237 /* reallocate memory */
239 i = strlen(name->text);
241 newname = DMNEW(char, namelen);
242 MCOPY(newname, name->text, char, i);
244 utf_ptr = descriptor->text;
249 while ((c = utf_nextu2(&utf_ptr)) != ')') {
267 while ((c = utf_nextu2(&utf_ptr)) != ';')
268 if (((c >= 'a') && (c <= 'z')) ||
269 ((c >= 'A') && (c <= 'Z')) ||
270 ((c >= '0') && (c <= '9')))
288 /* make a utf-string */
290 u = utf_new_char(newname);
294 dump_release(dumpsize);
300 /* native_insert_char **********************************************************
302 Inserts the passed UTF character into the native method name. If
303 necessary it is escaped properly.
305 *******************************************************************************/
307 static s4 native_insert_char(char *name, u4 pos, u2 c)
315 /* replace '/' or '.' with '_' */
320 /* escape sequence for '_' is '_1' */
326 /* escape sequence for ';' is '_2' */
332 /* escape sequence for '[' is '_1' */
341 /* unicode character */
345 for (i = 0; i < 4; ++i) {
347 name[pos + 4 - i] = (val > 10) ? ('a' + val - 10) : ('0' + val);
356 /* return the new buffer index */
362 /* native_method_symbol ********************************************************
364 Generate a method-symbol string out of the class name and the
367 *******************************************************************************/
369 static utf *native_method_symbol(utf *classname, utf *methodname)
382 dumpsize = dump_size();
384 /* Calculate length of native function name. We multiply the
385 class and method name length by 6 as this is the maxium
386 escape-sequence that can be generated (unicode). */
390 utf_get_number_of_u2s(classname) * 6 +
392 utf_get_number_of_u2s(methodname) * 6 +
395 /* allocate memory */
397 name = DMNEW(char, namelen);
399 /* generate name of native functions */
401 strcpy(name, "Java_");
402 pos = strlen("Java_");
404 utf_ptr = classname->text;
405 utf_endptr = UTF_END(classname);
407 for (; utf_ptr < utf_endptr; utf_ptr++, pos++) {
409 pos = native_insert_char(name, pos, c);
412 /* seperator between class and method */
416 utf_ptr = methodname->text;
417 utf_endptr = UTF_END(methodname);
419 for (; utf_ptr < utf_endptr; utf_ptr++, pos++) {
421 pos = native_insert_char(name, pos, c);
428 /* check for an buffer overflow */
430 assert(pos <= namelen);
432 /* make a utf-string */
434 u = utf_new_char(name);
438 dump_release(dumpsize);
444 /* native_method_register ******************************************************
446 Register a native method in the native method table.
448 *******************************************************************************/
450 void native_method_register(utf *classname, const JNINativeMethod *methods,
453 native_methods_node_t *nmn;
458 /* insert all methods passed */
460 for (i = 0; i < count; i++) {
461 if (opt_verbosejni) {
462 printf("[Registering JNI native method ");
463 utf_display_printable_ascii_classname(classname);
464 printf(".%s]\n", methods[i].name);
467 /* generate the utf8 names */
469 name = utf_new_char(methods[i].name);
470 descriptor = utf_new_char(methods[i].signature);
472 /* allocate a new tree node */
474 nmn = NEW(native_methods_node_t);
476 nmn->classname = classname;
478 nmn->descriptor = descriptor;
479 nmn->function = (functionptr) (ptrint) methods[i].fnPtr;
481 /* insert the method into the tree */
483 avl_insert(tree_native_methods, nmn);
488 /* native_method_find **********************************************************
490 Find a native method in the native method table.
492 *******************************************************************************/
494 static functionptr native_method_find(methodinfo *m)
496 native_methods_node_t tmpnmn;
497 native_methods_node_t *nmn;
499 /* fill the temporary structure used for searching the tree */
501 tmpnmn.classname = m->class->name;
502 tmpnmn.name = m->name;
503 tmpnmn.descriptor = m->descriptor;
505 /* find the entry in the AVL-tree */
507 nmn = avl_find(tree_native_methods, &tmpnmn);
512 return nmn->function;
516 /* native_library_open *********************************************************
518 Open a native library with the given utf8 name.
520 *******************************************************************************/
522 #if defined(ENABLE_LTDL)
523 lt_dlhandle native_library_open(utf *filename)
527 if (opt_verbosejni) {
528 printf("[Loading native library ");
529 utf_display_printable_ascii(filename);
533 /* try to open the library */
535 handle = lt_dlopen(filename->text);
537 if (handle == NULL) {
540 log_print("native_library_load: lt_dlopen failed: ");
541 log_print(lt_dlerror());
553 /* native_library_add **********************************************************
555 Adds an entry to the native library hashtable.
557 *******************************************************************************/
559 #if defined(ENABLE_LTDL)
560 void native_library_add(utf *filename, classloader *loader, lt_dlhandle handle)
562 hashtable_classloader_entry *cle;
563 hashtable_library_loader_entry *le;
564 hashtable_library_name_entry *ne; /* library name */
565 u4 key; /* hashkey */
566 u4 slot; /* slot in hashtable */
568 LOCK_MONITOR_ENTER(hashtable_library->header);
570 /* insert loader into the classloader hashtable */
572 cle = loader_hashtable_classloader_add(loader);
574 /* normally addresses are aligned to 4, 8 or 16 bytes */
576 key = ((u4) (ptrint) cle) >> 4; /* align to 16-byte boundaries */
577 slot = key & (hashtable_library->size - 1);
578 le = hashtable_library->ptr[slot];
580 /* search external hash chain for the entry */
586 le = le->hashlink; /* next element in external chain */
589 /* no loader found? create a new entry */
592 le = NEW(hashtable_library_loader_entry);
597 /* insert entry into hashtable */
600 (hashtable_library_loader_entry *) hashtable_library->ptr[slot];
601 hashtable_library->ptr[slot] = le;
603 /* update number of hashtable-entries */
605 hashtable_library->entries++;
609 /* search for library name */
614 if (ne->name == filename) {
615 LOCK_MONITOR_EXIT(hashtable_library->header);
620 ne = ne->hashlink; /* next element in external chain */
623 /* not found? add the library name to the classloader */
625 ne = NEW(hashtable_library_name_entry);
630 /* insert entry into external chain */
632 ne->hashlink = le->namelink;
635 LOCK_MONITOR_EXIT(hashtable_library->header);
640 /* native_library_find *********************************************************
642 Find an entry in the native library hashtable.
644 *******************************************************************************/
646 #if defined(ENABLE_LTDL)
647 hashtable_library_name_entry *native_library_find(utf *filename,
650 hashtable_classloader_entry *cle;
651 hashtable_library_loader_entry *le;
652 hashtable_library_name_entry *ne; /* library name */
653 u4 key; /* hashkey */
654 u4 slot; /* slot in hashtable */
656 /* search loader in the classloader hashtable */
658 cle = loader_hashtable_classloader_find(loader);
663 /* normally addresses are aligned to 4, 8 or 16 bytes */
665 key = ((u4) (ptrint) cle) >> 4; /* align to 16-byte boundaries */
666 slot = key & (hashtable_library->size - 1);
667 le = hashtable_library->ptr[slot];
669 /* search external hash chain for the entry */
675 le = le->hashlink; /* next element in external chain */
678 /* no loader found? return NULL */
683 /* search for library name */
688 if (ne->name == filename)
691 ne = ne->hashlink; /* next element in external chain */
694 /* return entry, if no entry was found, ne is NULL */
698 #endif /* !defined(WITH_STATIC_CLASSPATH) */
701 /* native_findfunction *********************************************************
703 Looks up a method (must have the same class name, method name,
704 descriptor and 'static'ness) and returns a function pointer to it.
705 Returns: function pointer or NULL (if there is no such method)
707 Remark: For faster operation, the names/descriptors are converted
708 from C strings to Unicode the first time this function is called.
710 *******************************************************************************/
712 #if defined(WITH_STATIC_CLASSPATH)
713 functionptr native_findfunction(utf *cname, utf *mname, utf *desc,
716 /* entry of table for fast string comparison */
717 struct nativecompref *n;
720 isstatic = isstatic ? true : false;
722 if (!nativecompdone) {
723 for (i = 0; i < NATIVETABLESIZE; i++) {
724 nativecomptable[i].classname =
725 utf_new_char(nativetable[i].classname);
727 nativecomptable[i].methodname =
728 utf_new_char(nativetable[i].methodname);
730 nativecomptable[i].descriptor =
731 utf_new_char(nativetable[i].descriptor);
733 nativecomptable[i].isstatic = nativetable[i].isstatic;
734 nativecomptable[i].func = nativetable[i].func;
737 nativecompdone = true;
740 for (i = 0; i < NATIVETABLESIZE; i++) {
741 n = &(nativecomptable[i]);
743 if (cname == n->classname && mname == n->methodname &&
744 desc == n->descriptor && isstatic == n->isstatic)
748 /* no function was found, throw exception */
750 exceptions_throw_unsatisfiedlinkerror(mname);
754 #endif /* defined(WITH_STATIC_CLASSPATH) */
757 /* native_resolve_function *****************************************************
759 Resolves a native function, maybe from a dynamic library.
761 *******************************************************************************/
763 functionptr native_resolve_function(methodinfo *m)
769 #if defined(ENABLE_LTDL)
770 hashtable_library_loader_entry *le;
771 hashtable_library_name_entry *ne;
772 u4 key; /* hashkey */
773 u4 slot; /* slot in hashtable */
775 #if defined(WITH_CLASSPATH_SUN)
776 methodinfo *method_findNative;
780 cl = m->class->classloader;
784 if (opt_verbosejni) {
785 printf("[Dynamic-linking native method ");
786 utf_display_printable_ascii_classname(m->class->name);
788 utf_display_printable_ascii(m->name);
792 /* generate method symbol string */
794 name = native_method_symbol(m->class->name, m->name);
796 /* generate overloaded function (having the types in it's name) */
798 newname = native_make_overloaded_function(name, m->descriptor);
800 /* check the library hash entries of the classloader of the
805 #if defined(ENABLE_LTDL)
806 /* normally addresses are aligned to 4, 8 or 16 bytes */
808 key = ((u4) (ptrint) cl) >> 4; /* align to 16-byte */
809 slot = key & (hashtable_library->size - 1);
810 le = hashtable_library->ptr[slot];
812 /* iterate through loaders in this hash slot */
814 while ((le != NULL) && (f == NULL)) {
815 /* iterate through names in this loader */
819 while ((ne != NULL) && (f == NULL)) {
820 f = (functionptr) (ptrint) lt_dlsym(ne->handle, name->text);
823 f = (functionptr) (ptrint) lt_dlsym(ne->handle, newname->text);
831 # if defined(WITH_CLASSPATH_SUN)
833 /* We can resolve the function directly from
834 java.lang.ClassLoader as it's a static function. */
835 /* XXX should be done in native_init */
838 class_resolveclassmethod(class_java_lang_ClassLoader,
840 utf_java_lang_ClassLoader_java_lang_String__J,
841 class_java_lang_ClassLoader,
844 if (method_findNative == NULL)
847 /* try the normal name */
849 s = javastring_new(name);
851 f = (functionptr) (intptr_t) vm_call_method_long(method_findNative,
854 /* if not found, try the mangled name */
857 s = javastring_new(newname);
859 f = (functionptr) (intptr_t) vm_call_method_long(method_findNative,
870 /* If not found, try to find the native function symbol in the
874 f = native_method_find(m);
878 printf("internal ]\n");
881 #if defined(ENABLE_JVMTI)
882 /* fire Native Method Bind event */
883 if (jvmti) jvmti_NativeMethodBind(m, f, &f);
886 /* no symbol found? throw exception */
890 printf("failed ]\n");
892 exceptions_throw_unsatisfiedlinkerror(m->name);
897 #endif /* !defined(WITH_STATIC_CLASSPATH) */
900 /* native_new_and_init *********************************************************
902 Creates a new object on the heap and calls the initializer.
903 Returns the object pointer or NULL if memory is exhausted.
905 *******************************************************************************/
907 java_handle_t *native_new_and_init(classinfo *c)
913 vm_abort("native_new_and_init: c == NULL");
922 /* try to find the initializer */
924 m = class_findmethod(c, utf_init, utf_void__void);
926 /* ATTENTION: returning the object here is ok, since the class may
927 not have an initializer */
932 /* call initializer */
934 (void) vm_call_method(m, o);
940 java_handle_t *native_new_and_init_string(classinfo *c, java_handle_t *s)
946 vm_abort("native_new_and_init_string: c == NULL");
955 /* find initializer */
957 m = class_findmethod(c, utf_init, utf_java_lang_String__void);
959 /* initializer not found */
964 /* call initializer */
966 (void) vm_call_method(m, o, s);
973 * These are local overrides for various environment variables in Emacs.
974 * Please do not remove this and leave it at the end of the file, where
975 * Emacs will automagically detect them.
976 * ---------------------------------------------------------------------
979 * indent-tabs-mode: t