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 7911 2007-05-16 09:01:10Z twisti $
35 #if !defined(WITH_STATIC_CLASSPATH)
41 #include "mm/memory.h"
43 #include "native/jni.h"
44 #include "native/native.h"
46 #include "native/vm/nativevm.h"
48 #include "threads/lock-common.h"
50 #include "toolbox/avl.h"
51 #include "toolbox/hashtable.h"
52 #include "toolbox/logging.h"
54 #include "vm/builtin.h"
55 #include "vm/exceptions.h"
56 #include "vm/global.h"
57 #include "vm/stringlocal.h"
60 #include "vm/jit/asmpart.h"
61 #include "vm/jit/jit.h"
63 #include "vmcore/loader.h"
64 #include "vmcore/options.h"
65 #include "vm/resolve.h"
67 #if defined(ENABLE_JVMTI)
68 #include "native/jvmti/cacaodbg.h"
72 /* include table of native functions ******************************************/
74 #if defined(WITH_STATIC_CLASSPATH)
75 # include "native/nativetable.inc"
79 /* tables for methods *********************************************************/
81 #if defined(WITH_STATIC_CLASSPATH)
82 #define NATIVETABLESIZE (sizeof(nativetable)/sizeof(struct nativeref))
84 /* table for fast string comparison */
85 static nativecompref nativecomptable[NATIVETABLESIZE];
87 /* string comparsion table initialized */
88 static bool nativecompdone = false;
92 /* global variables ***********************************************************/
94 static avl_tree_t *tree_native_methods;
95 static hashtable *hashtable_library;
98 /* prototypes *****************************************************************/
100 static s4 native_tree_native_methods_comparator(const void *treenode, const void *node);
103 /* native_init *****************************************************************
105 Initializes the native subsystem.
107 *******************************************************************************/
109 bool native_init(void)
111 #if !defined(WITH_STATIC_CLASSPATH)
112 /* initialize libltdl */
115 vm_abort("native_init: lt_dlinit failed: %s\n", lt_dlerror());
117 /* initialize library hashtable, 10 entries should be enough */
119 hashtable_library = NEW(hashtable);
121 hashtable_create(hashtable_library, 10);
124 /* initialize the native methods table */
126 tree_native_methods = avl_create(&native_tree_native_methods_comparator);
128 /* register the intern native functions */
132 /* everything's ok */
138 /* native_tree_native_methods_comparator ***************************************
140 Comparison function for AVL tree of native methods.
143 treenode....node in the tree
144 node........node to compare with tree-node
149 *******************************************************************************/
151 static s4 native_tree_native_methods_comparator(const void *treenode, const void *node)
153 const native_methods_node_t *treenmn;
154 const native_methods_node_t *nmn;
159 /* compare for avl_find if we have found an entry */
161 if (treenmn->name == nmn->name)
164 /* these are for walking the tree */
166 if (treenmn->name < nmn->name)
173 /* native_make_overloaded_function *********************************************
177 *******************************************************************************/
179 #if !defined(WITH_STATIC_CLASSPATH)
180 static utf *native_make_overloaded_function(utf *name, utf *descriptor)
192 dumpsize = dump_size();
194 utf_ptr = descriptor->text;
195 namelen = strlen(name->text) + strlen("__") + strlen("0");
197 /* calculate additional length */
199 while ((c = utf_nextu2(&utf_ptr)) != ')') {
216 while (utf_nextu2(&utf_ptr) != ';')
227 /* reallocate memory */
229 i = strlen(name->text);
231 newname = DMNEW(char, namelen);
232 MCOPY(newname, name->text, char, i);
234 utf_ptr = descriptor->text;
239 while ((c = utf_nextu2(&utf_ptr)) != ')') {
257 while ((c = utf_nextu2(&utf_ptr)) != ';')
258 if (((c >= 'a') && (c <= 'z')) ||
259 ((c >= 'A') && (c <= 'Z')) ||
260 ((c >= '0') && (c <= '9')))
278 /* make a utf-string */
280 u = utf_new_char(newname);
284 dump_release(dumpsize);
290 /* native_insert_char **********************************************************
292 Inserts the passed UTF character into the native method name. If
293 necessary it is escaped properly.
295 *******************************************************************************/
297 static s4 native_insert_char(char *name, u4 pos, u2 c)
305 /* replace '/' or '.' with '_' */
310 /* escape sequence for '_' is '_1' */
316 /* escape sequence for ';' is '_2' */
322 /* escape sequence for '[' is '_1' */
331 /* unicode character */
335 for (i = 0; i < 4; ++i) {
337 name[pos + 4 - i] = (val > 10) ? ('a' + val - 10) : ('0' + val);
346 /* return the new buffer index */
352 /* native_method_symbol ********************************************************
354 Generate a method-symbol string out of the class name and the
357 *******************************************************************************/
359 static utf *native_method_symbol(utf *classname, utf *methodname)
372 dumpsize = dump_size();
374 /* Calculate length of native function name. We multiply the
375 class and method name length by 6 as this is the maxium
376 escape-sequence that can be generated (unicode). */
380 utf_get_number_of_u2s(classname) * 6 +
382 utf_get_number_of_u2s(methodname) * 6 +
385 /* allocate memory */
387 name = DMNEW(char, namelen);
389 /* generate name of native functions */
391 strcpy(name, "Java_");
392 pos = strlen("Java_");
394 utf_ptr = classname->text;
395 utf_endptr = UTF_END(classname);
397 for (; utf_ptr < utf_endptr; utf_ptr++, pos++) {
399 pos = native_insert_char(name, pos, c);
402 /* seperator between class and method */
406 utf_ptr = methodname->text;
407 utf_endptr = UTF_END(methodname);
409 for (; utf_ptr < utf_endptr; utf_ptr++, pos++) {
411 pos = native_insert_char(name, pos, c);
418 /* check for an buffer overflow */
420 assert(pos <= namelen);
422 /* make a utf-string */
424 u = utf_new_char(name);
428 dump_release(dumpsize);
434 /* native_method_register ******************************************************
436 Register a native method in the native method table.
438 *******************************************************************************/
440 void native_method_register(utf *classname, JNINativeMethod *methods, s4 count)
442 native_methods_node_t *nmn;
447 /* insert all methods passed */
449 for (i = 0; i < count; i++) {
450 if (opt_verbosejni) {
451 printf("[Registering JNI native method ");
452 utf_display_printable_ascii_classname(classname);
453 printf(".%s]\n", methods[i].name);
456 /* generate the method-symbol string */
458 methodname = utf_new_char(methods[i].name);
459 name = native_method_symbol(classname, methodname);
461 /* allocate a new tree node */
463 nmn = NEW(native_methods_node_t);
466 nmn->method = (functionptr) (ptrint) methods[i].fnPtr;
468 /* insert the method into the tree */
470 avl_insert(tree_native_methods, nmn);
475 /* native_method_find **********************************************************
477 Find a native method in the native method table.
479 *******************************************************************************/
481 static functionptr native_method_find(utf *name)
483 native_methods_node_t tmpnmn;
484 native_methods_node_t *nmn;
488 nmn = avl_find(tree_native_methods, &tmpnmn);
497 /* native_library_open *********************************************************
499 Open a native library with the given utf8 name.
501 *******************************************************************************/
503 #if !defined(WITH_STATIC_CLASSPATH)
504 lt_dlhandle native_library_open(utf *filename)
508 /* try to open the library */
510 handle = lt_dlopen(filename->text);
512 if (handle == NULL) {
515 log_print("native_library_load: lt_dlopen failed: ");
516 log_print(lt_dlerror());
528 /* native_library_add **********************************************************
530 Adds an entry to the native library hashtable.
532 *******************************************************************************/
534 #if !defined(WITH_STATIC_CLASSPATH)
535 void native_library_add(utf *filename, java_objectheader *loader,
538 hashtable_library_loader_entry *le;
539 hashtable_library_name_entry *ne; /* library name */
540 u4 key; /* hashkey */
541 u4 slot; /* slot in hashtable */
543 LOCK_MONITOR_ENTER(hashtable_library->header);
545 /* normally addresses are aligned to 4, 8 or 16 bytes */
547 key = ((u4) (ptrint) loader) >> 4; /* align to 16-byte boundaries */
548 slot = key & (hashtable_library->size - 1);
549 le = hashtable_library->ptr[slot];
551 /* search external hash chain for the entry */
554 if (le->loader == loader)
557 le = le->hashlink; /* next element in external chain */
560 /* no loader found? create a new entry */
563 le = NEW(hashtable_library_loader_entry);
568 /* insert entry into hashtable */
571 (hashtable_library_loader_entry *) hashtable_library->ptr[slot];
572 hashtable_library->ptr[slot] = le;
574 /* update number of hashtable-entries */
576 hashtable_library->entries++;
580 /* search for library name */
585 if (ne->name == filename) {
586 LOCK_MONITOR_EXIT(hashtable_library->header);
591 ne = ne->hashlink; /* next element in external chain */
594 /* not found? add the library name to the classloader */
596 ne = NEW(hashtable_library_name_entry);
601 /* insert entry into external chain */
603 ne->hashlink = le->namelink;
606 LOCK_MONITOR_EXIT(hashtable_library->header);
608 #endif /* !defined(WITH_STATIC_CLASSPATH) */
611 /* native_library_find *********************************************************
613 Find an entry in the native library hashtable.
615 *******************************************************************************/
617 #if !defined(WITH_STATIC_CLASSPATH)
618 hashtable_library_name_entry *native_library_find(utf *filename,
619 java_objectheader *loader)
621 hashtable_library_loader_entry *le;
622 hashtable_library_name_entry *ne; /* library name */
623 u4 key; /* hashkey */
624 u4 slot; /* slot in hashtable */
626 /* normally addresses are aligned to 4, 8 or 16 bytes */
628 key = ((u4) (ptrint) loader) >> 4; /* align to 16-byte boundaries */
629 slot = key & (hashtable_library->size - 1);
630 le = hashtable_library->ptr[slot];
632 /* search external hash chain for the entry */
635 if (le->loader == loader)
638 le = le->hashlink; /* next element in external chain */
641 /* no loader found? return NULL */
646 /* search for library name */
651 if (ne->name == filename)
654 ne = ne->hashlink; /* next element in external chain */
657 /* return entry, if no entry was found, ne is NULL */
661 #endif /* !defined(WITH_STATIC_CLASSPATH) */
664 /* native_findfunction *********************************************************
666 Looks up a method (must have the same class name, method name,
667 descriptor and 'static'ness) and returns a function pointer to it.
668 Returns: function pointer or NULL (if there is no such method)
670 Remark: For faster operation, the names/descriptors are converted
671 from C strings to Unicode the first time this function is called.
673 *******************************************************************************/
675 #if defined(WITH_STATIC_CLASSPATH)
676 functionptr native_findfunction(utf *cname, utf *mname, utf *desc,
679 /* entry of table for fast string comparison */
680 struct nativecompref *n;
683 isstatic = isstatic ? true : false;
685 if (!nativecompdone) {
686 for (i = 0; i < NATIVETABLESIZE; i++) {
687 nativecomptable[i].classname =
688 utf_new_char(nativetable[i].classname);
690 nativecomptable[i].methodname =
691 utf_new_char(nativetable[i].methodname);
693 nativecomptable[i].descriptor =
694 utf_new_char(nativetable[i].descriptor);
696 nativecomptable[i].isstatic = nativetable[i].isstatic;
697 nativecomptable[i].func = nativetable[i].func;
700 nativecompdone = true;
703 for (i = 0; i < NATIVETABLESIZE; i++) {
704 n = &(nativecomptable[i]);
706 if (cname == n->classname && mname == n->methodname &&
707 desc == n->descriptor && isstatic == n->isstatic)
711 /* no function was found, throw exception */
714 new_exception_utfmessage(string_java_lang_UnsatisfiedLinkError,
719 #endif /* defined(WITH_STATIC_CLASSPATH) */
722 /* native_resolve_function *****************************************************
724 Resolves a native function, maybe from a dynamic library.
726 *******************************************************************************/
728 functionptr native_resolve_function(methodinfo *m)
733 hashtable_library_loader_entry *le;
734 hashtable_library_name_entry *ne;
735 u4 key; /* hashkey */
736 u4 slot; /* slot in hashtable */
740 if (opt_verbosejni) {
741 printf("[Dynamic-linking native method ");
742 utf_display_printable_ascii_classname(m->class->name);
744 utf_display_printable_ascii(m->name);
748 /* generate method symbol string */
750 name = native_method_symbol(m->class->name, m->name);
752 /* generate overloaded function (having the types in it's name) */
754 newname = native_make_overloaded_function(name, m->descriptor);
756 /* check the library hash entries of the classloader of the
761 /* normally addresses are aligned to 4, 8 or 16 bytes */
763 key = ((u4) (ptrint) m->class->classloader) >> 4; /* align to 16-byte */
764 slot = key & (hashtable_library->size - 1);
765 le = hashtable_library->ptr[slot];
767 /* iterate through loaders in this hash slot */
769 while ((le != NULL) && (f == NULL)) {
770 /* iterate through names in this loader */
774 while ((ne != NULL) && (f == NULL)) {
775 f = (functionptr) (ptrint) lt_dlsym(ne->handle, name->text);
778 f = (functionptr) (ptrint) lt_dlsym(ne->handle, newname->text);
790 /* If not found, try to find the native function symbol in the
794 f = native_method_find(name);
797 f = native_method_find(newname);
801 printf("internal ]\n");
804 #if defined(ENABLE_JVMTI)
805 /* fire Native Method Bind event */
806 if (jvmti) jvmti_NativeMethodBind(m, f, &f);
809 /* no symbol found? throw exception */
813 printf("failed ]\n");
815 exceptions_throw_unsatisfiedlinkerror(m->name);
820 #endif /* !defined(WITH_STATIC_CLASSPATH) */
823 /* native_new_and_init *********************************************************
825 Creates a new object on the heap and calls the initializer.
826 Returns the object pointer or NULL if memory is exhausted.
828 *******************************************************************************/
830 java_objectheader *native_new_and_init(classinfo *c)
833 java_objectheader *o;
836 vm_abort("native_new_and_init: c == NULL");
845 /* try to find the initializer */
847 m = class_findmethod(c, utf_init, utf_void__void);
849 /* ATTENTION: returning the object here is ok, since the class may
850 not have an initializer */
855 /* call initializer */
857 (void) vm_call_method(m, o);
863 java_objectheader *native_new_and_init_string(classinfo *c, java_objectheader *s)
866 java_objectheader *o;
869 vm_abort("native_new_and_init_string: c == NULL");
878 /* find initializer */
880 m = class_resolveclassmethod(c,
882 utf_java_lang_String__void,
886 /* initializer not found */
891 /* call initializer */
893 (void) vm_call_method(m, o, s);
899 java_objectheader *native_new_and_init_int(classinfo *c, s4 i)
902 java_objectheader *o;
905 vm_abort("native_new_and_init_int: c == NULL");
914 /* find initializer */
916 m = class_resolveclassmethod(c, utf_init, utf_int__void, NULL, true);
918 /* initializer not found */
923 /* call initializer */
925 (void) vm_call_method(m, o, i);
931 java_objectheader *native_new_and_init_throwable(classinfo *c, java_objectheader *t)
933 java_objectheader *o;
937 vm_abort("native_new_and_init_throwable: c == NULL");
946 /* find initializer */
948 m = class_findmethod(c, utf_init, utf_java_lang_Throwable__void);
950 /* initializer not found */
955 /* call initializer */
957 (void) vm_call_method(m, o, t);
964 * These are local overrides for various environment variables in Emacs.
965 * Please do not remove this and leave it at the end of the file, where
966 * Emacs will automagically detect them.
967 * ---------------------------------------------------------------------
970 * indent-tabs-mode: t