X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fnative%2Fnative.c;h=37f86f45c72fbd3da3442479f1440b929d0d0271;hb=9f859ad50d3d5d98c185d40b86b2179bc4dc9aeb;hp=c6f3238a0dcd633c660a1d760ca6209e1e2a9746;hpb=e86cf0a3b8a36028a8d5a15afe7d147d1f0897ae;p=cacao.git diff --git a/src/native/native.c b/src/native/native.c index c6f3238a0..37f86f45c 100644 --- a/src/native/native.c +++ b/src/native/native.c @@ -1,9 +1,9 @@ /* src/native/native.c - table of native functions - Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates, - R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, - C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, - Institut f. Computersprachen - TU Wien + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien This file is part of CACAO. @@ -19,94 +19,66 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. - - Contact: cacao@complang.tuwien.ac.at - - Authors: Reinhard Grafl - Roman Obermaisser - Andreas Krall - - Changes: Christian Thalinger - - $Id: native.c 2151 2005-03-30 19:27:47Z twisti $ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ -#include -#include -#include -#include -#include -#include -#include -#include +#include "config.h" -/* Include files for IO functions */ +#include +#include -#include -#include -#include -#ifdef _OSF_SOURCE -#include +#if defined(ENABLE_LTDL) && defined(HAVE_LTDL_H) +# include #endif -#include -#include "config.h" -#include "cacao/cacao.h" +#include + +#include "vm/types.h" + #include "mm/memory.h" + #include "native/jni.h" #include "native/native.h" -#include "native/include/java_lang_Throwable.h" + +#include "native/vm/nativevm.h" + +#include "threads/lock-common.h" + +#include "toolbox/avl.h" +#include "toolbox/hashtable.h" #include "toolbox/logging.h" + #include "vm/builtin.h" #include "vm/exceptions.h" #include "vm/global.h" -#include "vm/loader.h" -#include "vm/options.h" #include "vm/stringlocal.h" -#include "vm/tables.h" +#include "vm/vm.h" + #include "vm/jit/asmpart.h" #include "vm/jit/jit.h" +#include "vmcore/loader.h" +#include "vmcore/options.h" +#include "vm/resolve.h" -/* include table of native functions ******************************************/ - -#include "nativetable.inc" - +#if defined(ENABLE_JVMTI) +#include "native/jvmti/cacaodbg.h" +#endif -/************* use classinfo structure as java.lang.Class object **************/ -void use_class_as_object(classinfo *c) -{ - if (!c->classvftbl) { - /* is the class loaded */ - if (!c->loaded) -/* if (!class_load(c)) */ -/* throw_exception_exit(); */ - panic("use_class_as_object: class_load should not happen"); - - /* is the class linked */ - if (!c->linked) - if (!link_class(c)) - throw_exception_exit(); - - /*if (class_java_lang_Class ==0) panic("java/lang/Class not loaded in use_class_as_object"); - if (class_java_lang_Class->vftbl ==0) panic ("vftbl == 0 in use_class_as_object");*/ - c->header.vftbl = class_java_lang_Class->vftbl; - c->classvftbl = true; - } -} +/* include table of native functions ******************************************/ +#if defined(WITH_STATIC_CLASSPATH) +# include "native/nativetable.inc" +#endif -/************************** tables for methods ********************************/ -#undef JOWENN_DEBUG -#undef JOWENN_DEBUG1 +/* tables for methods *********************************************************/ -#ifdef STATIC_CLASSPATH +#if defined(WITH_STATIC_CLASSPATH) #define NATIVETABLESIZE (sizeof(nativetable)/sizeof(struct nativeref)) /* table for fast string comparison */ @@ -117,775 +89,868 @@ static bool nativecompdone = false; #endif -/* XXX don't define this in a header file!!! */ +/* global variables ***********************************************************/ -static struct nativeCall nativeCalls[] = -{ -#include "nativecalls.inc" -}; +static avl_tree_t *tree_native_methods; + +#if defined(ENABLE_LTDL) +static hashtable *hashtable_library; +#endif -#define NATIVECALLSSIZE (sizeof(nativeCalls) / sizeof(struct nativeCall)) -struct nativeCompCall nativeCompCalls[NATIVECALLSSIZE]; +/* prototypes *****************************************************************/ +static s4 native_tree_native_methods_comparator(const void *treenode, const void *node); -/* native_loadclasses ********************************************************** - Load classes required for native methods. +/* native_init ***************************************************************** + + Initializes the native subsystem. *******************************************************************************/ bool native_init(void) { -#if !defined(STATIC_CLASSPATH) - void *p; +#if defined(ENABLE_LTDL) + /* initialize libltdl */ + + if (lt_dlinit()) + vm_abort("native_init: lt_dlinit failed: %s\n", lt_dlerror()); + + /* initialize library hashtable, 10 entries should be enough */ - /* We need to access the dummy native table, not only to remove a warning */ - /* but to be sure that the table is not optimized away (gcc does this */ - /* since 3.4). */ - p = &dummynativetable; + hashtable_library = NEW(hashtable); + + hashtable_create(hashtable_library, 10); #endif + /* initialize the native methods table */ + + tree_native_methods = avl_create(&native_tree_native_methods_comparator); + /* everything's ok */ return true; } -/*********************** Function: native_findfunction ************************* +/* native_tree_native_methods_comparator *************************************** + + Comparison function for AVL tree of native methods. - Looks up a method (must have the same class name, method name, descriptor - and 'static'ness) and returns a function pointer to it. - Returns: function pointer or NULL (if there is no such method) + IN: + treenode....node in the tree + node........node to compare with tree-node - Remark: For faster operation, the names/descriptors are converted from C - strings to Unicode the first time this function is called. + RETURN VALUE: + -1, 0, +1 *******************************************************************************/ -functionptr native_findfunction(utf *cname, utf *mname, - utf *desc, bool isstatic) +static s4 native_tree_native_methods_comparator(const void *treenode, const void *node) { -#ifdef STATIC_CLASSPATH - int i; - /* entry of table for fast string comparison */ - struct nativecompref *n; - /* for warning message if no function is found */ - char *buffer; - int buffer_len; + const native_methods_node_t *treenmn; + const native_methods_node_t *nmn; - isstatic = isstatic ? true : false; - - if (!nativecompdone) { - for (i = 0; i < NATIVETABLESIZE; i++) { - nativecomptable[i].classname = - utf_new_char(nativetable[i].classname); - nativecomptable[i].methodname = - utf_new_char(nativetable[i].methodname); - nativecomptable[i].descriptor = - utf_new_char(nativetable[i].descriptor); - nativecomptable[i].isstatic = - nativetable[i].isstatic; - nativecomptable[i].func = - nativetable[i].func; - } - nativecompdone = true; - } + treenmn = treenode; + nmn = node; -#ifdef JOWENN_DEBUG - buffer_len = - utf_strlen(cname) + utf_strlen(mname) + utf_strlen(desc) + 64; - - buffer = MNEW(char, buffer_len); + /* these are for walking the tree */ - strcpy(buffer, "searching matching function in native table:"); - utf_sprint(buffer+strlen(buffer), mname); - strcpy(buffer+strlen(buffer), ": "); - utf_sprint(buffer+strlen(buffer), desc); - strcpy(buffer+strlen(buffer), " for class "); - utf_sprint(buffer+strlen(buffer), cname); + if (treenmn->classname < nmn->classname) + return -1; + else if (treenmn->classname > nmn->classname) + return 1; - log_text(buffer); + if (treenmn->name < nmn->name) + return -1; + else if (treenmn->name > nmn->name) + return 1; - MFREE(buffer, char, buffer_len); -#endif - - for (i = 0; i < NATIVETABLESIZE; i++) { - n = &(nativecomptable[i]); + if (treenmn->descriptor < nmn->descriptor) + return -1; + else if (treenmn->descriptor > nmn->descriptor) + return 1; - if (cname == n->classname && mname == n->methodname && - desc == n->descriptor && isstatic == n->isstatic) - return n->func; -#ifdef JOWENN_DEBUG - else { - if (cname == n->classname && mname == n->methodname ) log_text("static and descriptor mismatch"); - - else { - buffer_len = - utf_strlen(n->classname) + utf_strlen(n->methodname) + utf_strlen(n->descriptor) + 64; - - buffer = MNEW(char, buffer_len); + /* all pointers are equal, we have found the entry */ - strcpy(buffer, "comparing with:"); - utf_sprint(buffer+strlen(buffer), n->methodname); - strcpy (buffer+strlen(buffer), ": "); - utf_sprint(buffer+strlen(buffer), n->descriptor); - strcpy(buffer+strlen(buffer), " for class "); - utf_sprint(buffer+strlen(buffer), n->classname); + return 0; +} - log_text(buffer); - MFREE(buffer, char, buffer_len); - } - } -#endif +/* native_make_overloaded_function ********************************************* + + XXX + +*******************************************************************************/ + +#if !defined(WITH_STATIC_CLASSPATH) +static utf *native_make_overloaded_function(utf *name, utf *descriptor) +{ + char *newname; + s4 namelen; + char *utf_ptr; + u2 c; + s4 i; + s4 dumpsize; + utf *u; + + /* mark memory */ + + dumpsize = dump_size(); + + utf_ptr = descriptor->text; + namelen = strlen(name->text) + strlen("__") + strlen("0"); + + /* calculate additional length */ + + while ((c = utf_nextu2(&utf_ptr)) != ')') { + switch (c) { + case 'Z': + case 'B': + case 'C': + case 'S': + case 'I': + case 'J': + case 'F': + case 'D': + namelen++; + break; + case '[': + namelen += 2; + break; + case 'L': + namelen++; + while (utf_nextu2(&utf_ptr) != ';') + namelen++; + namelen += 2; + break; + case '(': + break; + default: + assert(0); + } } - - /* no function was found, display warning */ + /* reallocate memory */ + + i = strlen(name->text); + + newname = DMNEW(char, namelen); + MCOPY(newname, name->text, char, i); + + utf_ptr = descriptor->text; + + newname[i++] = '_'; + newname[i++] = '_'; + + while ((c = utf_nextu2(&utf_ptr)) != ')') { + switch (c) { + case 'Z': + case 'B': + case 'C': + case 'S': + case 'J': + case 'I': + case 'F': + case 'D': + newname[i++] = c; + break; + case '[': + newname[i++] = '_'; + newname[i++] = '3'; + break; + case 'L': + newname[i++] = 'L'; + while ((c = utf_nextu2(&utf_ptr)) != ';') + if (((c >= 'a') && (c <= 'z')) || + ((c >= 'A') && (c <= 'Z')) || + ((c >= '0') && (c <= '9'))) + newname[i++] = c; + else + newname[i++] = '_'; + newname[i++] = '_'; + newname[i++] = '2'; + break; + case '(': + break; + default: + assert(0); + } + } - buffer_len = - utf_strlen(cname) + utf_strlen(mname) + utf_strlen(desc) + 64; + /* close string */ - buffer = MNEW(char, buffer_len); + newname[i] = '\0'; - strcpy(buffer, "warning: native function "); - utf_sprint(buffer + strlen(buffer), mname); - strcpy(buffer + strlen(buffer), ": "); - utf_sprint(buffer + strlen(buffer), desc); - strcpy(buffer + strlen(buffer), " not found in class "); - utf_sprint(buffer + strlen(buffer), cname); + /* make a utf-string */ - log_text(buffer); + u = utf_new_char(newname); - MFREE(buffer, char, buffer_len); + /* release memory */ -/* exit(1); */ + dump_release(dumpsize); - /* keep compiler happy */ - return NULL; -#else -/* dynamic classpath */ - return 0; -#endif + return u; } -/****************** function class_findfield_approx **************************** - - searches in 'classinfo'-structure for a field with the - specified name +/* native_insert_char ********************************************************** + + Inserts the passed UTF character into the native method name. If + necessary it is escaped properly. *******************************************************************************/ - -fieldinfo *class_findfield_approx(classinfo *c, utf *name) + +static s4 native_insert_char(char *name, u4 pos, u2 c) { + s4 val; s4 i; - for (i = 0; i < c->fieldscount; i++) { - /* compare field names */ - if ((c->fields[i].name == name)) - return &(c->fields[i]); + switch (c) { + case '/': + case '.': + /* replace '/' or '.' with '_' */ + name[pos] = '_'; + break; + + case '_': + /* escape sequence for '_' is '_1' */ + name[pos] = '_'; + name[++pos] = '1'; + break; + + case ';': + /* escape sequence for ';' is '_2' */ + name[pos] = '_'; + name[++pos] = '2'; + break; + + case '[': + /* escape sequence for '[' is '_1' */ + name[pos] = '_'; + name[++pos] = '3'; + break; + + default: + if (isalnum(c)) + name[pos] = c; + else { + /* unicode character */ + name[pos] = '_'; + name[++pos] = '0'; + + for (i = 0; i < 4; ++i) { + val = c & 0x0f; + name[pos + 4 - i] = (val > 10) ? ('a' + val - 10) : ('0' + val); + c >>= 4; + } + + pos += 4; + } + break; } - /* field was not found, raise exception */ - *exceptionptr = new_exception(string_java_lang_NoSuchFieldException); + /* return the new buffer index */ - return NULL; + return pos; } -s4 class_findfield_index_approx(classinfo *c, utf *name) +/* native_method_symbol ******************************************************** + + Generate a method-symbol string out of the class name and the + method name. + +*******************************************************************************/ + +static utf *native_method_symbol(utf *classname, utf *methodname) { - s4 i; + char *name; + s4 namelen; + char *utf_ptr; + char *utf_endptr; + u2 c; + u4 pos; + s4 dumpsize; + utf *u; + + /* mark memory */ + + dumpsize = dump_size(); + + /* Calculate length of native function name. We multiply the + class and method name length by 6 as this is the maxium + escape-sequence that can be generated (unicode). */ + + namelen = + strlen("Java_") + + utf_get_number_of_u2s(classname) * 6 + + strlen("_") + + utf_get_number_of_u2s(methodname) * 6 + + strlen("0"); + + /* allocate memory */ + + name = DMNEW(char, namelen); + + /* generate name of native functions */ + + strcpy(name, "Java_"); + pos = strlen("Java_"); - for (i = 0; i < c->fieldscount; i++) { - /* compare field names */ - if ((c->fields[i].name == name)) - return i; + utf_ptr = classname->text; + utf_endptr = UTF_END(classname); + + for (; utf_ptr < utf_endptr; utf_ptr++, pos++) { + c = *utf_ptr; + pos = native_insert_char(name, pos, c); } - /* field was not found, raise exception */ - *exceptionptr = new_exception(string_java_lang_NoSuchFieldException); + /* seperator between class and method */ + + name[pos++] = '_'; + + utf_ptr = methodname->text; + utf_endptr = UTF_END(methodname); + + for (; utf_ptr < utf_endptr; utf_ptr++, pos++) { + c = *utf_ptr; + pos = native_insert_char(name, pos, c); + } + + /* close string */ + + name[pos] = '\0'; + + /* check for an buffer overflow */ + + assert(pos <= namelen); - return -1; + /* make a utf-string */ + + u = utf_new_char(name); + + /* release memory */ + + dump_release(dumpsize); + + return u; } -/* native_new_and_init ********************************************************* +/* native_method_register ****************************************************** + + Register a native method in the native method table. - Creates a new object on the heap and calls the initializer. - Returns the object pointer or NULL if memory is exhausted. - *******************************************************************************/ -java_objectheader *native_new_and_init(classinfo *c) +void native_method_register(utf *classname, const JNINativeMethod *methods, + int32_t count) { - methodinfo *m; - java_objectheader *o; + native_methods_node_t *nmn; + utf *name; + utf *descriptor; + int32_t i; + + /* insert all methods passed */ + + for (i = 0; i < count; i++) { + if (opt_verbosejni) { + printf("[Registering JNI native method "); + utf_display_printable_ascii_classname(classname); + printf(".%s]\n", methods[i].name); + } - if (!c) - return *exceptionptr; + /* generate the utf8 names */ - /* create object */ + name = utf_new_char(methods[i].name); + descriptor = utf_new_char(methods[i].signature); - o = builtin_new(c); - - if (!o) - return NULL; + /* allocate a new tree node */ - /* find initializer */ + nmn = NEW(native_methods_node_t); - m = class_findmethod(c, utf_init, utf_void__void); - - /* initializer not found */ + nmn->classname = classname; + nmn->name = name; + nmn->descriptor = descriptor; + nmn->function = (functionptr) (ptrint) methods[i].fnPtr; - if (!m) - return o; + /* insert the method into the tree */ - /* call initializer */ + avl_insert(tree_native_methods, nmn); + } +} - asm_calljavafunction(m, o, NULL, NULL, NULL); - return o; -} +/* native_method_find ********************************************************** + + Find a native method in the native method table. +*******************************************************************************/ -java_objectheader *native_new_and_init_string(classinfo *c, java_lang_String *s) +static functionptr native_method_find(methodinfo *m) { - methodinfo *m; - java_objectheader *o; + native_methods_node_t tmpnmn; + native_methods_node_t *nmn; - if (!c) - return *exceptionptr; + /* fill the temporary structure used for searching the tree */ - /* create object */ + tmpnmn.classname = m->class->name; + tmpnmn.name = m->name; + tmpnmn.descriptor = m->descriptor; - o = builtin_new(c); + /* find the entry in the AVL-tree */ + + nmn = avl_find(tree_native_methods, &tmpnmn); - if (!o) + if (nmn == NULL) return NULL; - /* find initializer */ + return nmn->function; +} - m = class_resolveclassmethod(c, - utf_init, - utf_java_lang_String__void, - NULL, - true); - /* initializer not found */ +/* native_library_open ********************************************************* - if (!m) - return NULL; + Open a native library with the given utf8 name. - /* call initializer */ +*******************************************************************************/ - asm_calljavafunction(m, o, s, NULL, NULL); +#if defined(ENABLE_LTDL) +lt_dlhandle native_library_open(utf *filename) +{ + lt_dlhandle handle; - return o; + if (opt_verbosejni) { + printf("[Loading native library "); + utf_display_printable_ascii(filename); + printf(" ... "); + } + + /* try to open the library */ + + handle = lt_dlopen(filename->text); + + if (handle == NULL) { + if (opt_verbose) { + log_start(); + log_print("native_library_load: lt_dlopen failed: "); + log_print(lt_dlerror()); + log_finish(); + } + + return NULL; + } + + return handle; } +#endif + + +/* native_library_add ********************************************************** + Adds an entry to the native library hashtable. -java_objectheader *native_new_and_init_int(classinfo *c, s4 i) +*******************************************************************************/ + +#if defined(ENABLE_LTDL) +void native_library_add(utf *filename, classloader *loader, lt_dlhandle handle) { - methodinfo *m; - java_objectheader *o; + hashtable_library_loader_entry *le; + hashtable_library_name_entry *ne; /* library name */ + u4 key; /* hashkey */ + u4 slot; /* slot in hashtable */ - if (!c) - return *exceptionptr; + LOCK_MONITOR_ENTER(hashtable_library->header); - /* create object */ + /* normally addresses are aligned to 4, 8 or 16 bytes */ - o = builtin_new(c); - - if (!o) - return NULL; + key = ((u4) (ptrint) loader) >> 4; /* align to 16-byte boundaries */ + slot = key & (hashtable_library->size - 1); + le = hashtable_library->ptr[slot]; - /* find initializer */ + /* search external hash chain for the entry */ - m = class_resolveclassmethod(c, utf_init, utf_int__void, NULL, true); + while (le) { + if (le->loader == loader) + break; - /* initializer not found */ + le = le->hashlink; /* next element in external chain */ + } - if (!m) - return NULL; + /* no loader found? create a new entry */ - /* call initializer */ + if (le == NULL) { + le = NEW(hashtable_library_loader_entry); - asm_calljavafunction(m, o, (void *) (ptrint) i, NULL, NULL); + le->loader = loader; + le->namelink = NULL; - return o; -} + /* insert entry into hashtable */ + le->hashlink = + (hashtable_library_loader_entry *) hashtable_library->ptr[slot]; + hashtable_library->ptr[slot] = le; -java_objectheader *native_new_and_init_throwable(classinfo *c, java_lang_Throwable *t) -{ - methodinfo *m; - java_objectheader *o; + /* update number of hashtable-entries */ - if (!c) - return *exceptionptr; + hashtable_library->entries++; + } - /* create object */ - o = builtin_new(c); - - if (!o) - return NULL; + /* search for library name */ - /* find initializer */ + ne = le->namelink; - m = class_findmethod(c, utf_init, utf_java_lang_Throwable__void); - - /* initializer not found */ + while (ne) { + if (ne->name == filename) { + LOCK_MONITOR_EXIT(hashtable_library->header); - if (!m) - return NULL; + return; + } - /* call initializer */ + ne = ne->hashlink; /* next element in external chain */ + } - asm_calljavafunction(m, o, t, NULL, NULL); + /* not found? add the library name to the classloader */ - return o; -} + ne = NEW(hashtable_library_name_entry); + ne->name = filename; + ne->handle = handle; -void copy_vftbl(vftbl_t **dest, vftbl_t *src) -{ - *dest = src; -#if 0 - /* XXX this kind of copying does not work (in the general - * case). The interface tables would have to be copied, too. I - * don't see why we should make a copy anyway. -Edwin - */ - *dest = mem_alloc(sizeof(vftbl) + sizeof(methodptr)*(src->vftbllength-1)); - memcpy(*dest, src, sizeof(vftbl) - sizeof(methodptr)); - memcpy(&(*dest)->table, &src->table, src->vftbllength * sizeof(methodptr)); -#endif -} + /* insert entry into external chain */ + ne->hashlink = le->namelink; + le->namelink = ne; + + LOCK_MONITOR_EXIT(hashtable_library->header); +} +#endif -/****************************************************************************************** - creates method signature (excluding return type) from array of - class-objects representing the parameters of the method +/* native_library_find ********************************************************* -*******************************************************************************************/ + Find an entry in the native library hashtable. +*******************************************************************************/ -utf *create_methodsig(java_objectarray* types, char *retType) +#if defined(ENABLE_LTDL) +hashtable_library_name_entry *native_library_find(utf *filename, + classloader *loader) { - char *buffer; /* buffer for building the desciptor */ - char *pos; /* current position in buffer */ - utf *result; /* the method signature */ - u4 buffer_size = 3; /* minimal size=3: room for parenthesis and returntype */ - u4 i, j; - - if (!types) return NULL; - - /* determine required buffer-size */ - for (i = 0; i < types->header.size; i++) { - classinfo *c = (classinfo *) types->data[i]; - buffer_size = buffer_size + c->name->blength + 2; - } - - if (retType) buffer_size += strlen(retType); - - /* allocate buffer */ - buffer = MNEW(char, buffer_size); - pos = buffer; - - /* method-desciptor starts with parenthesis */ - *pos++ = '('; - - for (i = 0; i < types->header.size; i++) { - char ch; - - /* current argument */ - classinfo *c = (classinfo *) types->data[i]; - - /* current position in utf-text */ - char *utf_ptr = c->name->text; - - /* determine type of argument */ - if ((ch = utf_nextu2(&utf_ptr)) == '[') { - /* arrayclass */ - for (utf_ptr--; utf_ptr < utf_end(c->name); utf_ptr++) { - *pos++ = *utf_ptr; /* copy text */ - } + hashtable_library_loader_entry *le; + hashtable_library_name_entry *ne; /* library name */ + u4 key; /* hashkey */ + u4 slot; /* slot in hashtable */ - } else { - /* check for primitive types */ - for (j = 0; j < PRIMITIVETYPE_COUNT; j++) { - char *utf_pos = utf_ptr - 1; - char *primitive = primitivetype_table[j].wrapname; + /* normally addresses are aligned to 4, 8 or 16 bytes */ - /* compare text */ - while (utf_pos < utf_end(c->name)) { - if (*utf_pos++ != *primitive++) goto nomatch; - } + key = ((u4) (ptrint) loader) >> 4; /* align to 16-byte boundaries */ + slot = key & (hashtable_library->size - 1); + le = hashtable_library->ptr[slot]; - /* primitive type found */ - *pos++ = primitivetype_table[j].typesig; - goto next_type; + /* search external hash chain for the entry */ - nomatch: - ; - } + while (le) { + if (le->loader == loader) + break; - /* no primitive type and no arrayclass, so must be object */ - *pos++ = 'L'; + le = le->hashlink; /* next element in external chain */ + } - /* copy text */ - for (utf_ptr--; utf_ptr < utf_end(c->name); utf_ptr++) { - *pos++ = *utf_ptr; - } + /* no loader found? return NULL */ - *pos++ = ';'; + if (le == NULL) + return NULL; - next_type: - ; - } - } + /* search for library name */ - *pos++ = ')'; + ne = le->namelink; - if (retType) { - for (i = 0; i < strlen(retType); i++) { - *pos++ = retType[i]; - } - } + while (ne) { + if (ne->name == filename) + return ne; - /* create utf-string */ - result = utf_new(buffer, (pos - buffer)); - MFREE(buffer, char, buffer_size); + ne = ne->hashlink; /* next element in external chain */ + } + + /* return entry, if no entry was found, ne is NULL */ - return result; + return ne; } +#endif /* !defined(WITH_STATIC_CLASSPATH) */ -/****************************************************************************************** +/* native_findfunction ********************************************************* - retrieve the next argument or returntype from a descriptor - and return the corresponding class + Looks up a method (must have the same class name, method name, + descriptor and 'static'ness) and returns a function pointer to it. + Returns: function pointer or NULL (if there is no such method) -*******************************************************************************************/ + Remark: For faster operation, the names/descriptors are converted + from C strings to Unicode the first time this function is called. -classinfo *get_type(char **utf_ptr,char *desc_end, bool skip) +*******************************************************************************/ + +#if defined(WITH_STATIC_CLASSPATH) +functionptr native_findfunction(utf *cname, utf *mname, utf *desc, + bool isstatic) { - classinfo *c = class_from_descriptor(*utf_ptr,desc_end,utf_ptr, - (skip) ? CLASSLOAD_SKIP : CLASSLOAD_LOAD); - if (!c) - /* unknown type */ - panic("illegal descriptor"); + /* entry of table for fast string comparison */ + struct nativecompref *n; + s4 i; - if (skip) return NULL; + isstatic = isstatic ? true : false; + + if (!nativecompdone) { + for (i = 0; i < NATIVETABLESIZE; i++) { + nativecomptable[i].classname = + utf_new_char(nativetable[i].classname); - use_class_as_object(c); - return c; -} + nativecomptable[i].methodname = + utf_new_char(nativetable[i].methodname); + nativecomptable[i].descriptor = + utf_new_char(nativetable[i].descriptor); -/* get_parametertypes ********************************************************** + nativecomptable[i].isstatic = nativetable[i].isstatic; + nativecomptable[i].func = nativetable[i].func; + } - use the descriptor of a method to generate a java/lang/Class array - which contains the classes of the parametertypes of the method + nativecompdone = true; + } -*******************************************************************************/ + for (i = 0; i < NATIVETABLESIZE; i++) { + n = &(nativecomptable[i]); -java_objectarray* get_parametertypes(methodinfo *m) -{ - utf *descr = m->descriptor; /* method-descriptor */ - char *utf_ptr = descr->text; /* current position in utf-text */ - char *desc_end = utf_end(descr); /* points behind utf string */ - java_objectarray* result; - int parametercount = 0; - int i; - - /* skip '(' */ - utf_nextu2(&utf_ptr); - - /* determine number of parameters */ - while (*utf_ptr != ')') { - get_type(&utf_ptr, desc_end, true); - parametercount++; - } - - /* create class-array */ - result = builtin_anewarray(parametercount, class_java_lang_Class); - - utf_ptr = descr->text; - utf_nextu2(&utf_ptr); - - /* get returntype classes */ - for (i = 0; i < parametercount; i++) - result->data[i] = - (java_objectheader *) get_type(&utf_ptr, desc_end, false); - - return result; + if (cname == n->classname && mname == n->methodname && + desc == n->descriptor && isstatic == n->isstatic) + return n->func; + } + + /* no function was found, throw exception */ + + exceptions_throw_unsatisfiedlinkerror(mname); + + return NULL; } +#endif /* defined(WITH_STATIC_CLASSPATH) */ -/* get_exceptiontypes ********************************************************** +/* native_resolve_function ***************************************************** - get the exceptions which can be thrown by a method + Resolves a native function, maybe from a dynamic library. *******************************************************************************/ -java_objectarray* get_exceptiontypes(methodinfo *m) +functionptr native_resolve_function(methodinfo *m) { - u2 excount; - u2 i; - java_objectarray *result; + classloader *cl; + utf *name; + utf *newname; + functionptr f; +#if defined(ENABLE_LTDL) + hashtable_library_loader_entry *le; + hashtable_library_name_entry *ne; + u4 key; /* hashkey */ + u4 slot; /* slot in hashtable */ +#endif +#if defined(WITH_CLASSPATH_SUN) + methodinfo *method_findNative; + java_handle_t *s; +#endif - excount = m->thrownexceptionscount; + cl = m->class->classloader; - /* create class-array */ - result = builtin_anewarray(excount, class_java_lang_Class); + /* verbose output */ - for (i = 0; i < excount; i++) { - java_objectheader *o = (java_objectheader *) (m->thrownexceptions[i]); - use_class_as_object((classinfo *) o); - result->data[i] = o; - } + if (opt_verbosejni) { + printf("[Dynamic-linking native method "); + utf_display_printable_ascii_classname(m->class->name); + printf("."); + utf_display_printable_ascii(m->name); + printf(" ... "); + } - return result; -} + /* generate method symbol string */ + name = native_method_symbol(m->class->name, m->name); + /* generate overloaded function (having the types in it's name) */ + newname = native_make_overloaded_function(name, m->descriptor); + /* check the library hash entries of the classloader of the + methods's class */ -/****************************************************************************************** + f = NULL; - get the returntype class of a method +#if defined(ENABLE_LTDL) + /* normally addresses are aligned to 4, 8 or 16 bytes */ -*******************************************************************************************/ + key = ((u4) (ptrint) cl) >> 4; /* align to 16-byte */ + slot = key & (hashtable_library->size - 1); + le = hashtable_library->ptr[slot]; -classinfo *get_returntype(methodinfo *m) -{ - char *utf_ptr; /* current position in utf-text */ - char *desc_end; /* points behind utf string */ - utf *desc = m->descriptor; /* method-descriptor */ + /* iterate through loaders in this hash slot */ - utf_ptr = desc->text; - desc_end = utf_end(desc); + while ((le != NULL) && (f == NULL)) { + /* iterate through names in this loader */ - /* ignore parametertypes */ - while ((utf_ptrnamelink; + + while ((ne != NULL) && (f == NULL)) { + f = (functionptr) (ptrint) lt_dlsym(ne->handle, name->text); - return get_type(&utf_ptr,desc_end, false); -} + if (f == NULL) + f = (functionptr) (ptrint) lt_dlsym(ne->handle, newname->text); + ne = ne->hashlink; + } -/*****************************************************************************/ -/*****************************************************************************/ + le = le->hashlink; + } +# if defined(WITH_CLASSPATH_SUN) + if (f == NULL) { + /* We can resolve the function directly from + java.lang.ClassLoader as it's a static function. */ + /* XXX should be done in native_init */ -/*--------------------------------------------------------*/ -void printNativeCall(nativeCall nc) { - int i,j; + method_findNative = + class_resolveclassmethod(class_java_lang_ClassLoader, + utf_findNative, + utf_java_lang_ClassLoader_java_lang_String__J, + class_java_lang_ClassLoader, + true); - printf("\n%s's Native Methods call:\n",nc.classname); fflush(stdout); - for (i=0; iaCalled = %s %s %s\n",i,j, - nc.methods[i].methodCalls[j].classname, - nc.methods[i].methodCalls[j].methodname, - nc.methods[i].methodCalls[j].descriptor);fflush(stdout); - } - } - printf("-+++++--------------------\n");fflush(stdout); -} + /* try the normal name */ -/*--------------------------------------------------------*/ -void printCompNativeCall(nativeCompCall nc) { - int i,j; - printf("printCompNativeCall BEGIN\n");fflush(stdout); - printf("\n%s's Native Comp Methods call:\n",nc.classname->text);fflush(stdout); - utf_display(nc.classname); fflush(stdout); - - for (i=0; itext,nc.methods[i].descriptor->text);fflush(stdout); - utf_display(nc.methods[i].methodname); fflush(stdout); - utf_display(nc.methods[i].descriptor);fflush(stdout); - printf("\n");fflush(stdout); - - for (j=0; jbCalled = ",i,j);fflush(stdout); - utf_display(nc.methods[i].methodCalls[j].classname);fflush(stdout); - utf_display(nc.methods[i].methodCalls[j].methodname); fflush(stdout); - utf_display(nc.methods[i].methodCalls[j].descriptor);fflush(stdout); - printf("\n");fflush(stdout); - } - } -printf("---------------------\n");fflush(stdout); -} + s = javastring_new(name); + f = (functionptr) (intptr_t) vm_call_method_long(method_findNative, + NULL, cl, s); -/*--------------------------------------------------------*/ -classMeth findNativeMethodCalls(utf *c, utf *m, utf *d ) -{ - int i = 0; - int j = 0; - int cnt = 0; - classMeth mc; - mc.i_class = i; - mc.j_method = j; - mc.methCnt = cnt; - - return mc; -} + /* if not found, try the mangled name */ -/*--------------------------------------------------------*/ -nativeCall* findNativeClassCalls(char *aclassname ) { -int i; + if (f == NULL) { + s = javastring_new(newname); -for (i=0;iclassname = utf_new_char(nc.classname); - ncc->methCnt = nc.methCnt; - - for (i=0; imethods[i].methodname = utf_new_char(nc.methods[i].methodname); - ncc->methods[i].descriptor = utf_new_char(nc.methods[i].descriptor); - ncc->callCnt[i] = nc.callCnt[i]; - - for (j=0; jmethods[i].methodCalls[j].classname = utf_new_char(nc.methods[i].methodCalls[j].classname); - - if (strcmp("", nc.methods[i].methodCalls[j].methodname) != 0) { - ncc->methods[i].methodCalls[j].methodname = utf_new_char(nc.methods[i].methodCalls[j].methodname); - ncc->methods[i].methodCalls[j].descriptor = utf_new_char(nc.methods[i].methodCalls[j].descriptor); - } - else { - ncc->methods[i].methodCalls[j].methodname = NULL; - ncc->methods[i].methodCalls[j].descriptor = NULL; - } - } - } -} + if (f != NULL) + if (opt_verbosejni) + printf("JNI ]\n"); +#endif + /* If not found, try to find the native function symbol in the + main program. */ + if (f == NULL) { + f = native_method_find(m); + + if (f != NULL) + if (opt_verbosejni) + printf("internal ]\n"); + } -/*--------------------------------------------------------*/ +#if defined(ENABLE_JVMTI) + /* fire Native Method Bind event */ + if (jvmti) jvmti_NativeMethodBind(m, f, &f); +#endif -bool natcall2utf(bool natcallcompdone) { -int i; + /* no symbol found? throw exception */ -if (natcallcompdone) - return true; + if (f == NULL) { + if (opt_verbosejni) + printf("failed ]\n"); -for (i=0;iname); + } -return true; + return f; } +#endif /* !defined(WITH_STATIC_CLASSPATH) */ -/*--------------------------------------------------------*/ +/* native_new_and_init ********************************************************* + + Creates a new object on the heap and calls the initializer. + Returns the object pointer or NULL if memory is exhausted. + +*******************************************************************************/ -java_objectarray *builtin_asm_createclasscontextarray(classinfo **end, classinfo **start) +java_handle_t *native_new_and_init(classinfo *c) { -#if defined(__GNUC__) -#warning platform dependend -#endif - java_objectarray *tmpArray; - int i; - classinfo **current; - classinfo *c; - size_t size; - - size = (((size_t) start) - ((size_t) end)) / sizeof(classinfo*); - - /*printf("end %p, start %p, size %ld\n",end,start,size);*/ - if (!class_java_lang_Class) - class_java_lang_Class = class_new(utf_new_char("java/lang/Class")); - - if (!class_java_lang_SecurityManager) - class_java_lang_SecurityManager = - class_new(utf_new_char("java/lang/SecurityManager")); - - if (size > 0) { - if (start == class_java_lang_SecurityManager) { - size--; - start--; - } - } + methodinfo *m; + java_handle_t *o; - tmpArray = - builtin_newarray(size, class_array_of(class_java_lang_Class)->vftbl); + if (c == NULL) + vm_abort("native_new_and_init: c == NULL"); - for(i = 0, current = start; i < size; i++, current--) { - c = *current; - /* printf("%d\n",i); - utf_display(c->name);*/ - use_class_as_object(c); - tmpArray->data[i] = (java_objectheader *) c; - } + /* create object */ + + o = builtin_new(c); + + if (o == NULL) + return NULL; + + /* try to find the initializer */ + + m = class_findmethod(c, utf_init, utf_void__void); + + /* ATTENTION: returning the object here is ok, since the class may + not have an initializer */ + + if (m == NULL) + return o; + + /* call initializer */ + + (void) vm_call_method(m, o); - return tmpArray; + return o; } -java_lang_ClassLoader *builtin_asm_getclassloader(classinfo **end, classinfo **start) +java_handle_t *native_new_and_init_string(classinfo *c, java_handle_t *s) { -#if defined(__GNUC__) -#warning platform dependend -#endif - int i; - classinfo **current; - classinfo *c; - classinfo *privilegedAction; - size_t size; + methodinfo *m; + java_handle_t *o; - size = (((size_t) start) - ((size_t) end)) / sizeof(classinfo*); + if (c == NULL) + vm_abort("native_new_and_init_string: c == NULL"); - /* log_text("builtin_asm_getclassloader"); - printf("end %p, start %p, size %ld\n",end,start,size);*/ + /* create object */ - if (!class_java_lang_SecurityManager) - class_java_lang_SecurityManager = - class_new(utf_new_char("java/lang/SecurityManager")); + o = builtin_new(c); - if (size > 0) { - if (start == class_java_lang_SecurityManager) { - size--; - start--; - } - } + if (o == NULL) + return NULL; - privilegedAction=class_new(utf_new_char("java/security/PrivilegedAction")); + /* find initializer */ - for(i = 0, current = start; i < size; i++, current--) { - c = *current; + m = class_findmethod(c, utf_init, utf_java_lang_String__void); - if (c == privilegedAction) - return NULL; + /* initializer not found */ - if (c->classloader) - return (java_lang_ClassLoader *) c->classloader; - } + if (m == NULL) + return NULL; - return NULL; + /* call initializer */ + + (void) vm_call_method(m, o, s); + + return o; }