1 /* src/native/native.c - native library support
3 Copyright (C) 1996-2005, 2006, 2007, 2008
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2, or (at
11 your option) any later version.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
35 #include "mm/memory.h"
37 #include "native/jni.hpp"
38 #include "native/native.h"
40 #include "native/vm/nativevm.h"
42 #include "threads/mutex.hpp"
44 #include "toolbox/avl.h"
45 #include "toolbox/hashtable.h"
46 #include "toolbox/logging.h"
48 #include "vm/jit/builtin.hpp"
49 #include "vm/exceptions.hpp"
50 #include "vm/global.h"
51 #include "vm/globals.hpp"
52 #include "vm/loader.hpp"
53 #include "vm/options.h"
55 #include "vm/resolve.h"
56 #include "vm/string.hpp"
59 #include "vm/jit/asmpart.h"
60 #include "vm/jit/jit.hpp"
62 #if defined(ENABLE_JVMTI)
63 #include "native/jvmti/cacaodbg.h"
67 /* global variables ***********************************************************/
69 static avl_tree_t *tree_native_methods;
71 #if defined(ENABLE_DL)
72 static hashtable *hashtable_library;
76 /* prototypes *****************************************************************/
78 static s4 native_tree_native_methods_comparator(const void *treenode, const void *node);
81 /* native_init *****************************************************************
83 Initializes the native subsystem.
85 *******************************************************************************/
87 bool native_init(void)
89 TRACESUBSYSTEMINITIALIZATION("native_init");
91 #if defined(ENABLE_DL)
92 /* initialize library hashtable, 10 entries should be enough */
94 hashtable_library = NEW(hashtable);
96 hashtable_create(hashtable_library, 10);
99 /* initialize the native methods table */
101 tree_native_methods = avl_create(&native_tree_native_methods_comparator);
103 /* everything's ok */
109 /* native_tree_native_methods_comparator ***************************************
111 Comparison function for AVL tree of native methods.
114 treenode....node in the tree
115 node........node to compare with tree-node
120 *******************************************************************************/
122 static s4 native_tree_native_methods_comparator(const void *treenode, const void *node)
124 const native_methods_node_t *treenmn;
125 const native_methods_node_t *nmn;
130 /* these are for walking the tree */
132 if (treenmn->classname < nmn->classname)
134 else if (treenmn->classname > nmn->classname)
137 if (treenmn->name < nmn->name)
139 else if (treenmn->name > nmn->name)
142 if (treenmn->descriptor < nmn->descriptor)
144 else if (treenmn->descriptor > nmn->descriptor)
147 /* all pointers are equal, we have found the entry */
153 /* native_make_overloaded_function *********************************************
157 *******************************************************************************/
159 static utf *native_make_overloaded_function(utf *name, utf *descriptor)
168 utf_ptr = descriptor->text;
169 namelen = strlen(name->text) + strlen("__") + strlen("0");
171 /* calculate additional length */
173 while ((c = utf_nextu2(&utf_ptr)) != ')') {
190 while (utf_nextu2(&utf_ptr) != ';')
201 /* reallocate memory */
203 i = strlen(name->text);
205 newname = MNEW(char, namelen);
206 MCOPY(newname, name->text, char, i);
208 utf_ptr = descriptor->text;
213 while ((c = utf_nextu2(&utf_ptr)) != ')') {
231 while ((c = utf_nextu2(&utf_ptr)) != ';')
232 if (((c >= 'a') && (c <= 'z')) ||
233 ((c >= 'A') && (c <= 'Z')) ||
234 ((c >= '0') && (c <= '9')))
252 /* make a utf-string */
254 u = utf_new_char(newname);
258 MFREE(newname, char, namelen);
264 /* native_insert_char **********************************************************
266 Inserts the passed UTF character into the native method name. If
267 necessary it is escaped properly.
269 *******************************************************************************/
271 static s4 native_insert_char(char *name, u4 pos, u2 c)
279 /* replace '/' or '.' with '_' */
284 /* escape sequence for '_' is '_1' */
290 /* escape sequence for ';' is '_2' */
296 /* escape sequence for '[' is '_1' */
305 /* unicode character */
309 for (i = 0; i < 4; ++i) {
311 name[pos + 4 - i] = (val > 10) ? ('a' + val - 10) : ('0' + val);
320 /* return the new buffer index */
326 /* native_method_symbol ********************************************************
328 Generate a method-symbol string out of the class name and the
331 *******************************************************************************/
333 static utf *native_method_symbol(utf *classname, utf *methodname)
343 /* Calculate length of native function name. We multiply the
344 class and method name length by 6 as this is the maxium
345 escape-sequence that can be generated (unicode). */
349 utf_get_number_of_u2s(classname) * 6 +
351 utf_get_number_of_u2s(methodname) * 6 +
354 /* allocate memory */
356 name = MNEW(char, namelen);
358 /* generate name of native functions */
360 strcpy(name, "Java_");
361 pos = strlen("Java_");
363 utf_ptr = classname->text;
364 utf_endptr = UTF_END(classname);
366 for (; utf_ptr < utf_endptr; utf_ptr++, pos++) {
368 pos = native_insert_char(name, pos, c);
371 /* seperator between class and method */
375 utf_ptr = methodname->text;
376 utf_endptr = UTF_END(methodname);
378 for (; utf_ptr < utf_endptr; utf_ptr++, pos++) {
380 pos = native_insert_char(name, pos, c);
387 /* check for an buffer overflow */
389 assert(pos <= namelen);
391 /* make a utf-string */
393 u = utf_new_char(name);
397 MFREE(name, char, namelen);
403 /* native_method_register ******************************************************
405 Register a native method in the native method table.
407 *******************************************************************************/
409 void native_method_register(utf *classname, const JNINativeMethod *methods,
412 native_methods_node_t *nmn;
417 /* insert all methods passed */
419 for (i = 0; i < count; i++) {
420 if (opt_verbosejni) {
421 printf("[Registering JNI native method ");
422 utf_display_printable_ascii_classname(classname);
423 printf(".%s]\n", methods[i].name);
426 /* generate the utf8 names */
428 name = utf_new_char(methods[i].name);
429 descriptor = utf_new_char(methods[i].signature);
431 /* allocate a new tree node */
433 nmn = NEW(native_methods_node_t);
435 nmn->classname = classname;
437 nmn->descriptor = descriptor;
438 nmn->function = (functionptr) (ptrint) methods[i].fnPtr;
440 /* insert the method into the tree */
442 avl_insert(tree_native_methods, nmn);
447 /* native_method_find **********************************************************
449 Find a native method in the native method table.
451 *******************************************************************************/
453 static functionptr native_method_find(methodinfo *m)
455 native_methods_node_t tmpnmn;
456 native_methods_node_t *nmn;
458 /* fill the temporary structure used for searching the tree */
460 tmpnmn.classname = m->clazz->name;
461 tmpnmn.name = m->name;
462 tmpnmn.descriptor = m->descriptor;
464 /* find the entry in the AVL-tree */
466 nmn = avl_find(tree_native_methods, &tmpnmn);
471 return nmn->function;
475 /* native_method_resolve *******************************************************
477 Resolves a native method, maybe from a dynamic library.
480 m ... methodinfo of the native Java method to resolve
483 pointer to the resolved method (symbol)
485 *******************************************************************************/
487 functionptr native_method_resolve(methodinfo *m)
492 #if defined(ENABLE_DL)
494 hashtable_library_loader_entry *le;
495 hashtable_library_name_entry *ne;
496 u4 key; /* hashkey */
497 u4 slot; /* slot in hashtable */
499 #if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
500 methodinfo *method_findNative;
506 if (opt_verbosejni) {
507 printf("[Dynamic-linking native method ");
508 utf_display_printable_ascii_classname(m->clazz->name);
510 utf_display_printable_ascii(m->name);
514 /* generate method symbol string */
516 name = native_method_symbol(m->clazz->name, m->name);
518 /* generate overloaded function (having the types in it's name) */
520 newname = native_make_overloaded_function(name, m->descriptor);
522 /* check the library hash entries of the classloader of the
527 #if defined(ENABLE_DL)
528 /* Get the classloader. */
530 cl = class_get_classloader(m->clazz);
532 /* normally addresses are aligned to 4, 8 or 16 bytes */
534 key = ((u4) (ptrint) cl) >> 4; /* align to 16-byte */
535 slot = key & (hashtable_library->size - 1);
536 le = hashtable_library->ptr[slot];
538 /* iterate through loaders in this hash slot */
540 while ((le != NULL) && (f == NULL)) {
541 /* iterate through names in this loader */
545 while ((ne != NULL) && (f == NULL)) {
546 f = (functionptr) (ptrint) os_dlsym(ne->handle, name->text);
549 f = (functionptr) (ptrint) os_dlsym(ne->handle, newname->text);
557 # if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
559 /* We can resolve the function directly from
560 java.lang.ClassLoader as it's a static function. */
561 /* XXX should be done in native_init */
564 class_resolveclassmethod(class_java_lang_ClassLoader,
566 utf_java_lang_ClassLoader_java_lang_String__J,
567 class_java_lang_ClassLoader,
570 if (method_findNative == NULL)
573 /* try the normal name */
575 s = javastring_new(name);
577 f = (functionptr) (intptr_t) vm_call_method_long(method_findNative,
580 /* if not found, try the mangled name */
583 s = javastring_new(newname);
585 f = (functionptr) (intptr_t) vm_call_method_long(method_findNative,
596 /* If not found, try to find the native function symbol in the
600 f = native_method_find(m);
604 printf("internal ]\n");
607 #if defined(ENABLE_JVMTI)
608 /* fire Native Method Bind event */
609 if (jvmti) jvmti_NativeMethodBind(m, f, &f);
612 /* no symbol found? throw exception */
616 printf("failed ]\n");
618 exceptions_throw_unsatisfiedlinkerror(m->name);
625 /* native_library_open *********************************************************
627 Open a native library with the given utf8 name.
630 filename ... filename of the library to open
633 handle of the opened library
635 *******************************************************************************/
637 #if defined(ENABLE_DL)
638 void* native_library_open(utf *filename)
642 if (opt_verbosejni) {
643 printf("[Loading native library ");
644 utf_display_printable_ascii(filename);
648 /* try to open the library */
650 handle = os_dlopen(filename->text, RTLD_LAZY);
652 if (handle == NULL) {
654 printf("failed ]\n");
658 log_print("native_library_open: os_dlopen failed: ");
659 log_print(dlerror());
674 /* native_library_close ********************************************************
676 Close the native library of the given handle.
679 handle ... handle of the open library
681 *******************************************************************************/
683 #if defined(ENABLE_DL)
684 void native_library_close(void* handle)
688 if (opt_verbosejni) {
689 printf("[Unloading native library ");
690 /* utf_display_printable_ascii(filename); */
694 /* Close the library. */
696 result = os_dlclose(handle);
701 log_print("native_library_close: os_dlclose failed: ");
702 log_print(dlerror());
710 /* native_library_add **********************************************************
712 Adds an entry to the native library hashtable.
714 *******************************************************************************/
716 #if defined(ENABLE_DL)
717 void native_library_add(utf *filename, classloader_t *loader, void* handle)
719 hashtable_library_loader_entry *le;
720 hashtable_library_name_entry *ne; /* library name */
721 u4 key; /* hashkey */
722 u4 slot; /* slot in hashtable */
724 Mutex_lock(hashtable_library->mutex);
726 /* normally addresses are aligned to 4, 8 or 16 bytes */
728 key = ((u4) (ptrint) loader) >> 4; /* align to 16-byte boundaries */
729 slot = key & (hashtable_library->size - 1);
730 le = hashtable_library->ptr[slot];
732 /* search external hash chain for the entry */
735 if (le->loader == loader)
738 le = le->hashlink; /* next element in external chain */
741 /* no loader found? create a new entry */
744 le = NEW(hashtable_library_loader_entry);
749 /* insert entry into hashtable */
752 (hashtable_library_loader_entry *) hashtable_library->ptr[slot];
753 hashtable_library->ptr[slot] = le;
755 /* update number of hashtable-entries */
757 hashtable_library->entries++;
761 /* search for library name */
766 if (ne->name == filename) {
767 Mutex_unlock(hashtable_library->mutex);
772 ne = ne->hashlink; /* next element in external chain */
775 /* not found? add the library name to the classloader */
777 ne = NEW(hashtable_library_name_entry);
782 /* insert entry into external chain */
784 ne->hashlink = le->namelink;
787 Mutex_unlock(hashtable_library->mutex);
792 /* native_library_find *********************************************************
794 Find an entry in the native library hashtable.
796 *******************************************************************************/
798 #if defined(ENABLE_DL)
799 hashtable_library_name_entry *native_library_find(utf *filename,
800 classloader_t *loader)
802 hashtable_library_loader_entry *le;
803 hashtable_library_name_entry *ne; /* library name */
804 u4 key; /* hashkey */
805 u4 slot; /* slot in hashtable */
807 /* normally addresses are aligned to 4, 8 or 16 bytes */
809 key = ((u4) (ptrint) loader) >> 4; /* align to 16-byte boundaries */
810 slot = key & (hashtable_library->size - 1);
811 le = hashtable_library->ptr[slot];
813 /* search external hash chain for the entry */
816 if (le->loader == loader)
819 le = le->hashlink; /* next element in external chain */
822 /* no loader found? return NULL */
827 /* search for library name */
832 if (ne->name == filename)
835 ne = ne->hashlink; /* next element in external chain */
838 /* return entry, if no entry was found, ne is NULL */
845 /* native_library_load *********************************************************
847 Load a native library and initialize it, if possible.
850 name ... name of the library
851 cl ..... classloader which loads this library
854 1 ... library loaded successfully
857 *******************************************************************************/
859 int native_library_load(JNIEnv *env, utf *name, classloader_t *cl)
861 #if defined(ENABLE_DL)
863 # if defined(ENABLE_JNI)
869 exceptions_throw_nullpointerexception();
873 /* Is the library already loaded? */
875 if (native_library_find(name, cl) != NULL)
878 /* Open the library. */
880 handle = native_library_open(name);
885 # if defined(ENABLE_JNI)
886 /* Resolve JNI_OnLoad function. */
888 onload = os_dlsym(handle, "JNI_OnLoad");
890 if (onload != NULL) {
891 JNIEXPORT int32_t (JNICALL *JNI_OnLoad) (JavaVM *, void *);
894 JNI_OnLoad = (JNIEXPORT int32_t (JNICALL *)(JavaVM *, void *)) (ptrint) onload;
896 (*env)->GetJavaVM(env, &vm);
898 version = JNI_OnLoad(vm, NULL);
900 /* If the version is not 1.2 and not 1.4 the library cannot be
903 if ((version != JNI_VERSION_1_2) && (version != JNI_VERSION_1_4)) {
910 /* Insert the library name into the library hash. */
912 native_library_add(name, cl, handle);
916 vm_abort("native_library_load: not available");
918 /* Keep compiler happy. */
925 /* native_new_and_init *********************************************************
927 Creates a new object on the heap and calls the initializer.
928 Returns the object pointer or NULL if memory is exhausted.
930 *******************************************************************************/
932 java_handle_t *native_new_and_init(classinfo *c)
938 vm_abort("native_new_and_init: c == NULL");
947 /* try to find the initializer */
949 m = class_findmethod(c, utf_init, utf_void__void);
951 /* ATTENTION: returning the object here is ok, since the class may
952 not have an initializer */
957 /* call initializer */
959 (void) vm_call_method(m, o);
965 java_handle_t *native_new_and_init_string(classinfo *c, java_handle_t *s)
971 vm_abort("native_new_and_init_string: c == NULL");
980 /* find initializer */
982 m = class_findmethod(c, utf_init, utf_java_lang_String__void);
984 /* initializer not found */
989 /* call initializer */
991 (void) vm_call_method(m, o, s);
998 * These are local overrides for various environment variables in Emacs.
999 * Please do not remove this and leave it at the end of the file, where
1000 * Emacs will automagically detect them.
1001 * ---------------------------------------------------------------------
1004 * indent-tabs-mode: t
1008 * vim:noexpandtab:sw=4:ts=4: