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.h"
38 #include "native/native.h"
40 #include "native/vm/nativevm.h"
42 #include "threads/lock-common.h"
44 #include "toolbox/avl.h"
45 #include "toolbox/hashtable.h"
46 #include "toolbox/logging.h"
48 #include "vm/builtin.h"
49 #include "vm/exceptions.h"
50 #include "vm/global.h"
51 #include "vm/resolve.h"
52 #include "vm/stringlocal.h"
55 #include "vm/jit/asmpart.h"
56 #include "vm/jit/jit.h"
58 #include "vmcore/globals.hpp"
59 #include "vmcore/loader.h"
60 #include "vmcore/options.h"
61 #include "vmcore/system.h"
63 #if defined(ENABLE_JVMTI)
64 #include "native/jvmti/cacaodbg.h"
68 /* global variables ***********************************************************/
70 static avl_tree_t *tree_native_methods;
72 #if defined(ENABLE_DL)
73 static hashtable *hashtable_library;
77 /* prototypes *****************************************************************/
79 static s4 native_tree_native_methods_comparator(const void *treenode, const void *node);
82 /* native_init *****************************************************************
84 Initializes the native subsystem.
86 *******************************************************************************/
88 bool native_init(void)
90 TRACESUBSYSTEMINITIALIZATION("native_init");
92 #if defined(ENABLE_DL)
93 /* initialize library hashtable, 10 entries should be enough */
95 hashtable_library = NEW(hashtable);
97 hashtable_create(hashtable_library, 10);
100 /* initialize the native methods table */
102 tree_native_methods = avl_create(&native_tree_native_methods_comparator);
104 /* everything's ok */
110 /* native_tree_native_methods_comparator ***************************************
112 Comparison function for AVL tree of native methods.
115 treenode....node in the tree
116 node........node to compare with tree-node
121 *******************************************************************************/
123 static s4 native_tree_native_methods_comparator(const void *treenode, const void *node)
125 const native_methods_node_t *treenmn;
126 const native_methods_node_t *nmn;
131 /* these are for walking the tree */
133 if (treenmn->classname < nmn->classname)
135 else if (treenmn->classname > nmn->classname)
138 if (treenmn->name < nmn->name)
140 else if (treenmn->name > nmn->name)
143 if (treenmn->descriptor < nmn->descriptor)
145 else if (treenmn->descriptor > nmn->descriptor)
148 /* all pointers are equal, we have found the entry */
154 /* native_make_overloaded_function *********************************************
158 *******************************************************************************/
160 static utf *native_make_overloaded_function(utf *name, utf *descriptor)
174 utf_ptr = descriptor->text;
175 namelen = strlen(name->text) + strlen("__") + strlen("0");
177 /* calculate additional length */
179 while ((c = utf_nextu2(&utf_ptr)) != ')') {
196 while (utf_nextu2(&utf_ptr) != ';')
207 /* reallocate memory */
209 i = strlen(name->text);
211 newname = DMNEW(char, namelen);
212 MCOPY(newname, name->text, char, i);
214 utf_ptr = descriptor->text;
219 while ((c = utf_nextu2(&utf_ptr)) != ')') {
237 while ((c = utf_nextu2(&utf_ptr)) != ';')
238 if (((c >= 'a') && (c <= 'z')) ||
239 ((c >= 'A') && (c <= 'Z')) ||
240 ((c >= '0') && (c <= '9')))
258 /* make a utf-string */
260 u = utf_new_char(newname);
270 /* native_insert_char **********************************************************
272 Inserts the passed UTF character into the native method name. If
273 necessary it is escaped properly.
275 *******************************************************************************/
277 static s4 native_insert_char(char *name, u4 pos, u2 c)
285 /* replace '/' or '.' with '_' */
290 /* escape sequence for '_' is '_1' */
296 /* escape sequence for ';' is '_2' */
302 /* escape sequence for '[' is '_1' */
311 /* unicode character */
315 for (i = 0; i < 4; ++i) {
317 name[pos + 4 - i] = (val > 10) ? ('a' + val - 10) : ('0' + val);
326 /* return the new buffer index */
332 /* native_method_symbol ********************************************************
334 Generate a method-symbol string out of the class name and the
337 *******************************************************************************/
339 static utf *native_method_symbol(utf *classname, utf *methodname)
354 /* Calculate length of native function name. We multiply the
355 class and method name length by 6 as this is the maxium
356 escape-sequence that can be generated (unicode). */
360 utf_get_number_of_u2s(classname) * 6 +
362 utf_get_number_of_u2s(methodname) * 6 +
365 /* allocate memory */
367 name = DMNEW(char, namelen);
369 /* generate name of native functions */
371 strcpy(name, "Java_");
372 pos = strlen("Java_");
374 utf_ptr = classname->text;
375 utf_endptr = UTF_END(classname);
377 for (; utf_ptr < utf_endptr; utf_ptr++, pos++) {
379 pos = native_insert_char(name, pos, c);
382 /* seperator between class and method */
386 utf_ptr = methodname->text;
387 utf_endptr = UTF_END(methodname);
389 for (; utf_ptr < utf_endptr; utf_ptr++, pos++) {
391 pos = native_insert_char(name, pos, c);
398 /* check for an buffer overflow */
400 assert(pos <= namelen);
402 /* make a utf-string */
404 u = utf_new_char(name);
414 /* native_method_register ******************************************************
416 Register a native method in the native method table.
418 *******************************************************************************/
420 void native_method_register(utf *classname, const JNINativeMethod *methods,
423 native_methods_node_t *nmn;
428 /* insert all methods passed */
430 for (i = 0; i < count; i++) {
431 if (opt_verbosejni) {
432 printf("[Registering JNI native method ");
433 utf_display_printable_ascii_classname(classname);
434 printf(".%s]\n", methods[i].name);
437 /* generate the utf8 names */
439 name = utf_new_char(methods[i].name);
440 descriptor = utf_new_char(methods[i].signature);
442 /* allocate a new tree node */
444 nmn = NEW(native_methods_node_t);
446 nmn->classname = classname;
448 nmn->descriptor = descriptor;
449 nmn->function = (functionptr) (ptrint) methods[i].fnPtr;
451 /* insert the method into the tree */
453 avl_insert(tree_native_methods, nmn);
458 /* native_method_find **********************************************************
460 Find a native method in the native method table.
462 *******************************************************************************/
464 static functionptr native_method_find(methodinfo *m)
466 native_methods_node_t tmpnmn;
467 native_methods_node_t *nmn;
469 /* fill the temporary structure used for searching the tree */
471 tmpnmn.classname = m->clazz->name;
472 tmpnmn.name = m->name;
473 tmpnmn.descriptor = m->descriptor;
475 /* find the entry in the AVL-tree */
477 nmn = avl_find(tree_native_methods, &tmpnmn);
482 return nmn->function;
486 /* native_method_resolve *******************************************************
488 Resolves a native method, maybe from a dynamic library.
491 m ... methodinfo of the native Java method to resolve
494 pointer to the resolved method (symbol)
496 *******************************************************************************/
498 functionptr native_method_resolve(methodinfo *m)
503 #if defined(ENABLE_DL)
505 hashtable_library_loader_entry *le;
506 hashtable_library_name_entry *ne;
507 u4 key; /* hashkey */
508 u4 slot; /* slot in hashtable */
510 #if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
511 methodinfo *method_findNative;
517 if (opt_verbosejni) {
518 printf("[Dynamic-linking native method ");
519 utf_display_printable_ascii_classname(m->clazz->name);
521 utf_display_printable_ascii(m->name);
525 /* generate method symbol string */
527 name = native_method_symbol(m->clazz->name, m->name);
529 /* generate overloaded function (having the types in it's name) */
531 newname = native_make_overloaded_function(name, m->descriptor);
533 /* check the library hash entries of the classloader of the
538 #if defined(ENABLE_DL)
539 /* Get the classloader. */
541 cl = class_get_classloader(m->clazz);
543 /* normally addresses are aligned to 4, 8 or 16 bytes */
545 key = ((u4) (ptrint) cl) >> 4; /* align to 16-byte */
546 slot = key & (hashtable_library->size - 1);
547 le = hashtable_library->ptr[slot];
549 /* iterate through loaders in this hash slot */
551 while ((le != NULL) && (f == NULL)) {
552 /* iterate through names in this loader */
556 while ((ne != NULL) && (f == NULL)) {
557 f = (functionptr) (ptrint) system_dlsym(ne->handle, name->text);
560 f = (functionptr) (ptrint) system_dlsym(ne->handle, newname->text);
568 # if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
570 /* We can resolve the function directly from
571 java.lang.ClassLoader as it's a static function. */
572 /* XXX should be done in native_init */
575 class_resolveclassmethod(class_java_lang_ClassLoader,
577 utf_java_lang_ClassLoader_java_lang_String__J,
578 class_java_lang_ClassLoader,
581 if (method_findNative == NULL)
584 /* try the normal name */
586 s = javastring_new(name);
588 f = (functionptr) (intptr_t) vm_call_method_long(method_findNative,
591 /* if not found, try the mangled name */
594 s = javastring_new(newname);
596 f = (functionptr) (intptr_t) vm_call_method_long(method_findNative,
607 /* If not found, try to find the native function symbol in the
611 f = native_method_find(m);
615 printf("internal ]\n");
618 #if defined(ENABLE_JVMTI)
619 /* fire Native Method Bind event */
620 if (jvmti) jvmti_NativeMethodBind(m, f, &f);
623 /* no symbol found? throw exception */
627 printf("failed ]\n");
629 exceptions_throw_unsatisfiedlinkerror(m->name);
636 /* native_library_open *********************************************************
638 Open a native library with the given utf8 name.
641 filename ... filename of the library to open
644 handle of the opened library
646 *******************************************************************************/
648 #if defined(ENABLE_DL)
649 void* native_library_open(utf *filename)
653 if (opt_verbosejni) {
654 printf("[Loading native library ");
655 utf_display_printable_ascii(filename);
659 /* try to open the library */
661 handle = system_dlopen(filename->text, RTLD_LAZY);
663 if (handle == NULL) {
665 printf("failed ]\n");
669 log_print("native_library_open: system_dlopen failed: ");
670 log_print(dlerror());
685 /* native_library_close ********************************************************
687 Close the native library of the given handle.
690 handle ... handle of the open library
692 *******************************************************************************/
694 #if defined(ENABLE_DL)
695 void native_library_close(void* handle)
699 if (opt_verbosejni) {
700 printf("[Unloading native library ");
701 /* utf_display_printable_ascii(filename); */
705 /* Close the library. */
707 result = system_dlclose(handle);
712 log_print("native_library_close: system_dlclose failed: ");
713 log_print(dlerror());
721 /* native_library_add **********************************************************
723 Adds an entry to the native library hashtable.
725 *******************************************************************************/
727 #if defined(ENABLE_DL)
728 void native_library_add(utf *filename, classloader_t *loader, void* handle)
730 hashtable_library_loader_entry *le;
731 hashtable_library_name_entry *ne; /* library name */
732 u4 key; /* hashkey */
733 u4 slot; /* slot in hashtable */
735 LOCK_MONITOR_ENTER(hashtable_library->header);
737 /* normally addresses are aligned to 4, 8 or 16 bytes */
739 key = ((u4) (ptrint) loader) >> 4; /* align to 16-byte boundaries */
740 slot = key & (hashtable_library->size - 1);
741 le = hashtable_library->ptr[slot];
743 /* search external hash chain for the entry */
746 if (le->loader == loader)
749 le = le->hashlink; /* next element in external chain */
752 /* no loader found? create a new entry */
755 le = NEW(hashtable_library_loader_entry);
760 /* insert entry into hashtable */
763 (hashtable_library_loader_entry *) hashtable_library->ptr[slot];
764 hashtable_library->ptr[slot] = le;
766 /* update number of hashtable-entries */
768 hashtable_library->entries++;
772 /* search for library name */
777 if (ne->name == filename) {
778 LOCK_MONITOR_EXIT(hashtable_library->header);
783 ne = ne->hashlink; /* next element in external chain */
786 /* not found? add the library name to the classloader */
788 ne = NEW(hashtable_library_name_entry);
793 /* insert entry into external chain */
795 ne->hashlink = le->namelink;
798 LOCK_MONITOR_EXIT(hashtable_library->header);
803 /* native_library_find *********************************************************
805 Find an entry in the native library hashtable.
807 *******************************************************************************/
809 #if defined(ENABLE_DL)
810 hashtable_library_name_entry *native_library_find(utf *filename,
811 classloader_t *loader)
813 hashtable_library_loader_entry *le;
814 hashtable_library_name_entry *ne; /* library name */
815 u4 key; /* hashkey */
816 u4 slot; /* slot in hashtable */
818 /* normally addresses are aligned to 4, 8 or 16 bytes */
820 key = ((u4) (ptrint) loader) >> 4; /* align to 16-byte boundaries */
821 slot = key & (hashtable_library->size - 1);
822 le = hashtable_library->ptr[slot];
824 /* search external hash chain for the entry */
827 if (le->loader == loader)
830 le = le->hashlink; /* next element in external chain */
833 /* no loader found? return NULL */
838 /* search for library name */
843 if (ne->name == filename)
846 ne = ne->hashlink; /* next element in external chain */
849 /* return entry, if no entry was found, ne is NULL */
856 /* native_library_load *********************************************************
858 Load a native library and initialize it, if possible.
861 name ... name of the library
862 cl ..... classloader which loads this library
865 1 ... library loaded successfully
868 *******************************************************************************/
870 int native_library_load(JNIEnv *env, utf *name, classloader_t *cl)
872 #if defined(ENABLE_DL)
874 # if defined(ENABLE_JNI)
880 exceptions_throw_nullpointerexception();
884 /* Is the library already loaded? */
886 if (native_library_find(name, cl) != NULL)
889 /* Open the library. */
891 handle = native_library_open(name);
896 # if defined(ENABLE_JNI)
897 /* Resolve JNI_OnLoad function. */
899 onload = system_dlsym(handle, "JNI_OnLoad");
901 if (onload != NULL) {
902 JNIEXPORT int32_t (JNICALL *JNI_OnLoad) (JavaVM *, void *);
905 JNI_OnLoad = (JNIEXPORT int32_t (JNICALL *)(JavaVM *, void *)) (ptrint) onload;
907 (*env)->GetJavaVM(env, &vm);
909 version = JNI_OnLoad(vm, NULL);
911 /* If the version is not 1.2 and not 1.4 the library cannot be
914 if ((version != JNI_VERSION_1_2) && (version != JNI_VERSION_1_4)) {
915 system_dlclose(handle);
921 /* Insert the library name into the library hash. */
923 native_library_add(name, cl, handle);
927 vm_abort("native_library_load: not available");
929 /* Keep compiler happy. */
936 /* native_new_and_init *********************************************************
938 Creates a new object on the heap and calls the initializer.
939 Returns the object pointer or NULL if memory is exhausted.
941 *******************************************************************************/
943 java_handle_t *native_new_and_init(classinfo *c)
949 vm_abort("native_new_and_init: c == NULL");
958 /* try to find the initializer */
960 m = class_findmethod(c, utf_init, utf_void__void);
962 /* ATTENTION: returning the object here is ok, since the class may
963 not have an initializer */
968 /* call initializer */
970 (void) vm_call_method(m, o);
976 java_handle_t *native_new_and_init_string(classinfo *c, java_handle_t *s)
982 vm_abort("native_new_and_init_string: c == NULL");
991 /* find initializer */
993 m = class_findmethod(c, utf_init, utf_java_lang_String__void);
995 /* initializer not found */
1000 /* call initializer */
1002 (void) vm_call_method(m, o, s);
1009 * These are local overrides for various environment variables in Emacs.
1010 * Please do not remove this and leave it at the end of the file, where
1011 * Emacs will automagically detect them.
1012 * ---------------------------------------------------------------------
1015 * indent-tabs-mode: t
1019 * vim:noexpandtab:sw=4:ts=4: