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/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.hpp"
50 #include "vm/global.h"
51 #include "vm/globals.hpp"
52 #include "vm/loader.h"
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.h"
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)
173 utf_ptr = descriptor->text;
174 namelen = strlen(name->text) + strlen("__") + strlen("0");
176 /* calculate additional length */
178 while ((c = utf_nextu2(&utf_ptr)) != ')') {
195 while (utf_nextu2(&utf_ptr) != ';')
206 /* reallocate memory */
208 i = strlen(name->text);
210 newname = DMNEW(char, namelen);
211 MCOPY(newname, name->text, char, i);
213 utf_ptr = descriptor->text;
218 while ((c = utf_nextu2(&utf_ptr)) != ')') {
236 while ((c = utf_nextu2(&utf_ptr)) != ';')
237 if (((c >= 'a') && (c <= 'z')) ||
238 ((c >= 'A') && (c <= 'Z')) ||
239 ((c >= '0') && (c <= '9')))
257 /* make a utf-string */
259 u = utf_new_char(newname);
269 /* native_insert_char **********************************************************
271 Inserts the passed UTF character into the native method name. If
272 necessary it is escaped properly.
274 *******************************************************************************/
276 static s4 native_insert_char(char *name, u4 pos, u2 c)
284 /* replace '/' or '.' with '_' */
289 /* escape sequence for '_' is '_1' */
295 /* escape sequence for ';' is '_2' */
301 /* escape sequence for '[' is '_1' */
310 /* unicode character */
314 for (i = 0; i < 4; ++i) {
316 name[pos + 4 - i] = (val > 10) ? ('a' + val - 10) : ('0' + val);
325 /* return the new buffer index */
331 /* native_method_symbol ********************************************************
333 Generate a method-symbol string out of the class name and the
336 *******************************************************************************/
338 static utf *native_method_symbol(utf *classname, utf *methodname)
353 /* Calculate length of native function name. We multiply the
354 class and method name length by 6 as this is the maxium
355 escape-sequence that can be generated (unicode). */
359 utf_get_number_of_u2s(classname) * 6 +
361 utf_get_number_of_u2s(methodname) * 6 +
364 /* allocate memory */
366 name = DMNEW(char, namelen);
368 /* generate name of native functions */
370 strcpy(name, "Java_");
371 pos = strlen("Java_");
373 utf_ptr = classname->text;
374 utf_endptr = UTF_END(classname);
376 for (; utf_ptr < utf_endptr; utf_ptr++, pos++) {
378 pos = native_insert_char(name, pos, c);
381 /* seperator between class and method */
385 utf_ptr = methodname->text;
386 utf_endptr = UTF_END(methodname);
388 for (; utf_ptr < utf_endptr; utf_ptr++, pos++) {
390 pos = native_insert_char(name, pos, c);
397 /* check for an buffer overflow */
399 assert(pos <= namelen);
401 /* make a utf-string */
403 u = utf_new_char(name);
413 /* native_method_register ******************************************************
415 Register a native method in the native method table.
417 *******************************************************************************/
419 void native_method_register(utf *classname, const JNINativeMethod *methods,
422 native_methods_node_t *nmn;
427 /* insert all methods passed */
429 for (i = 0; i < count; i++) {
430 if (opt_verbosejni) {
431 printf("[Registering JNI native method ");
432 utf_display_printable_ascii_classname(classname);
433 printf(".%s]\n", methods[i].name);
436 /* generate the utf8 names */
438 name = utf_new_char(methods[i].name);
439 descriptor = utf_new_char(methods[i].signature);
441 /* allocate a new tree node */
443 nmn = NEW(native_methods_node_t);
445 nmn->classname = classname;
447 nmn->descriptor = descriptor;
448 nmn->function = (functionptr) (ptrint) methods[i].fnPtr;
450 /* insert the method into the tree */
452 avl_insert(tree_native_methods, nmn);
457 /* native_method_find **********************************************************
459 Find a native method in the native method table.
461 *******************************************************************************/
463 static functionptr native_method_find(methodinfo *m)
465 native_methods_node_t tmpnmn;
466 native_methods_node_t *nmn;
468 /* fill the temporary structure used for searching the tree */
470 tmpnmn.classname = m->clazz->name;
471 tmpnmn.name = m->name;
472 tmpnmn.descriptor = m->descriptor;
474 /* find the entry in the AVL-tree */
476 nmn = avl_find(tree_native_methods, &tmpnmn);
481 return nmn->function;
485 /* native_method_resolve *******************************************************
487 Resolves a native method, maybe from a dynamic library.
490 m ... methodinfo of the native Java method to resolve
493 pointer to the resolved method (symbol)
495 *******************************************************************************/
497 functionptr native_method_resolve(methodinfo *m)
502 #if defined(ENABLE_DL)
504 hashtable_library_loader_entry *le;
505 hashtable_library_name_entry *ne;
506 u4 key; /* hashkey */
507 u4 slot; /* slot in hashtable */
509 #if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
510 methodinfo *method_findNative;
516 if (opt_verbosejni) {
517 printf("[Dynamic-linking native method ");
518 utf_display_printable_ascii_classname(m->clazz->name);
520 utf_display_printable_ascii(m->name);
524 /* generate method symbol string */
526 name = native_method_symbol(m->clazz->name, m->name);
528 /* generate overloaded function (having the types in it's name) */
530 newname = native_make_overloaded_function(name, m->descriptor);
532 /* check the library hash entries of the classloader of the
537 #if defined(ENABLE_DL)
538 /* Get the classloader. */
540 cl = class_get_classloader(m->clazz);
542 /* normally addresses are aligned to 4, 8 or 16 bytes */
544 key = ((u4) (ptrint) cl) >> 4; /* align to 16-byte */
545 slot = key & (hashtable_library->size - 1);
546 le = hashtable_library->ptr[slot];
548 /* iterate through loaders in this hash slot */
550 while ((le != NULL) && (f == NULL)) {
551 /* iterate through names in this loader */
555 while ((ne != NULL) && (f == NULL)) {
556 f = (functionptr) (ptrint) os_dlsym(ne->handle, name->text);
559 f = (functionptr) (ptrint) os_dlsym(ne->handle, newname->text);
567 # if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
569 /* We can resolve the function directly from
570 java.lang.ClassLoader as it's a static function. */
571 /* XXX should be done in native_init */
574 class_resolveclassmethod(class_java_lang_ClassLoader,
576 utf_java_lang_ClassLoader_java_lang_String__J,
577 class_java_lang_ClassLoader,
580 if (method_findNative == NULL)
583 /* try the normal name */
585 s = javastring_new(name);
587 f = (functionptr) (intptr_t) vm_call_method_long(method_findNative,
590 /* if not found, try the mangled name */
593 s = javastring_new(newname);
595 f = (functionptr) (intptr_t) vm_call_method_long(method_findNative,
606 /* If not found, try to find the native function symbol in the
610 f = native_method_find(m);
614 printf("internal ]\n");
617 #if defined(ENABLE_JVMTI)
618 /* fire Native Method Bind event */
619 if (jvmti) jvmti_NativeMethodBind(m, f, &f);
622 /* no symbol found? throw exception */
626 printf("failed ]\n");
628 exceptions_throw_unsatisfiedlinkerror(m->name);
635 /* native_library_open *********************************************************
637 Open a native library with the given utf8 name.
640 filename ... filename of the library to open
643 handle of the opened library
645 *******************************************************************************/
647 #if defined(ENABLE_DL)
648 void* native_library_open(utf *filename)
652 if (opt_verbosejni) {
653 printf("[Loading native library ");
654 utf_display_printable_ascii(filename);
658 /* try to open the library */
660 handle = os_dlopen(filename->text, RTLD_LAZY);
662 if (handle == NULL) {
664 printf("failed ]\n");
668 log_print("native_library_open: os_dlopen failed: ");
669 log_print(dlerror());
684 /* native_library_close ********************************************************
686 Close the native library of the given handle.
689 handle ... handle of the open library
691 *******************************************************************************/
693 #if defined(ENABLE_DL)
694 void native_library_close(void* handle)
698 if (opt_verbosejni) {
699 printf("[Unloading native library ");
700 /* utf_display_printable_ascii(filename); */
704 /* Close the library. */
706 result = os_dlclose(handle);
711 log_print("native_library_close: os_dlclose failed: ");
712 log_print(dlerror());
720 /* native_library_add **********************************************************
722 Adds an entry to the native library hashtable.
724 *******************************************************************************/
726 #if defined(ENABLE_DL)
727 void native_library_add(utf *filename, classloader_t *loader, void* handle)
729 hashtable_library_loader_entry *le;
730 hashtable_library_name_entry *ne; /* library name */
731 u4 key; /* hashkey */
732 u4 slot; /* slot in hashtable */
734 LOCK_MONITOR_ENTER(hashtable_library->header);
736 /* normally addresses are aligned to 4, 8 or 16 bytes */
738 key = ((u4) (ptrint) loader) >> 4; /* align to 16-byte boundaries */
739 slot = key & (hashtable_library->size - 1);
740 le = hashtable_library->ptr[slot];
742 /* search external hash chain for the entry */
745 if (le->loader == loader)
748 le = le->hashlink; /* next element in external chain */
751 /* no loader found? create a new entry */
754 le = NEW(hashtable_library_loader_entry);
759 /* insert entry into hashtable */
762 (hashtable_library_loader_entry *) hashtable_library->ptr[slot];
763 hashtable_library->ptr[slot] = le;
765 /* update number of hashtable-entries */
767 hashtable_library->entries++;
771 /* search for library name */
776 if (ne->name == filename) {
777 LOCK_MONITOR_EXIT(hashtable_library->header);
782 ne = ne->hashlink; /* next element in external chain */
785 /* not found? add the library name to the classloader */
787 ne = NEW(hashtable_library_name_entry);
792 /* insert entry into external chain */
794 ne->hashlink = le->namelink;
797 LOCK_MONITOR_EXIT(hashtable_library->header);
802 /* native_library_find *********************************************************
804 Find an entry in the native library hashtable.
806 *******************************************************************************/
808 #if defined(ENABLE_DL)
809 hashtable_library_name_entry *native_library_find(utf *filename,
810 classloader_t *loader)
812 hashtable_library_loader_entry *le;
813 hashtable_library_name_entry *ne; /* library name */
814 u4 key; /* hashkey */
815 u4 slot; /* slot in hashtable */
817 /* normally addresses are aligned to 4, 8 or 16 bytes */
819 key = ((u4) (ptrint) loader) >> 4; /* align to 16-byte boundaries */
820 slot = key & (hashtable_library->size - 1);
821 le = hashtable_library->ptr[slot];
823 /* search external hash chain for the entry */
826 if (le->loader == loader)
829 le = le->hashlink; /* next element in external chain */
832 /* no loader found? return NULL */
837 /* search for library name */
842 if (ne->name == filename)
845 ne = ne->hashlink; /* next element in external chain */
848 /* return entry, if no entry was found, ne is NULL */
855 /* native_library_load *********************************************************
857 Load a native library and initialize it, if possible.
860 name ... name of the library
861 cl ..... classloader which loads this library
864 1 ... library loaded successfully
867 *******************************************************************************/
869 int native_library_load(JNIEnv *env, utf *name, classloader_t *cl)
871 #if defined(ENABLE_DL)
873 # if defined(ENABLE_JNI)
879 exceptions_throw_nullpointerexception();
883 /* Is the library already loaded? */
885 if (native_library_find(name, cl) != NULL)
888 /* Open the library. */
890 handle = native_library_open(name);
895 # if defined(ENABLE_JNI)
896 /* Resolve JNI_OnLoad function. */
898 onload = os_dlsym(handle, "JNI_OnLoad");
900 if (onload != NULL) {
901 JNIEXPORT int32_t (JNICALL *JNI_OnLoad) (JavaVM *, void *);
904 JNI_OnLoad = (JNIEXPORT int32_t (JNICALL *)(JavaVM *, void *)) (ptrint) onload;
906 (*env)->GetJavaVM(env, &vm);
908 version = JNI_OnLoad(vm, NULL);
910 /* If the version is not 1.2 and not 1.4 the library cannot be
913 if ((version != JNI_VERSION_1_2) && (version != JNI_VERSION_1_4)) {
920 /* Insert the library name into the library hash. */
922 native_library_add(name, cl, handle);
926 vm_abort("native_library_load: not available");
928 /* Keep compiler happy. */
935 /* native_new_and_init *********************************************************
937 Creates a new object on the heap and calls the initializer.
938 Returns the object pointer or NULL if memory is exhausted.
940 *******************************************************************************/
942 java_handle_t *native_new_and_init(classinfo *c)
948 vm_abort("native_new_and_init: c == NULL");
957 /* try to find the initializer */
959 m = class_findmethod(c, utf_init, utf_void__void);
961 /* ATTENTION: returning the object here is ok, since the class may
962 not have an initializer */
967 /* call initializer */
969 (void) vm_call_method(m, o);
975 java_handle_t *native_new_and_init_string(classinfo *c, java_handle_t *s)
981 vm_abort("native_new_and_init_string: c == NULL");
990 /* find initializer */
992 m = class_findmethod(c, utf_init, utf_java_lang_String__void);
994 /* initializer not found */
999 /* call initializer */
1001 (void) vm_call_method(m, o, s);
1008 * These are local overrides for various environment variables in Emacs.
1009 * Please do not remove this and leave it at the end of the file, where
1010 * Emacs will automagically detect them.
1011 * ---------------------------------------------------------------------
1014 * indent-tabs-mode: t
1018 * vim:noexpandtab:sw=4:ts=4: