diff options
author | Tom Tromey <tromey@cygnus.com> | 2000-02-04 20:49:27 +0000 |
---|---|---|
committer | Tom Tromey <tromey@gcc.gnu.org> | 2000-02-04 20:49:27 +0000 |
commit | facc279fc19a31c23323ce3eeac869eb14d07bda (patch) | |
tree | f2e35a2ea96bcecfa7499a5ec8161bd2528c22d5 /libjava | |
parent | a89608cbebb11969af54ba5a5354302fab2a0b4b (diff) | |
download | gcc-facc279fc19a31c23323ce3eeac869eb14d07bda.zip gcc-facc279fc19a31c23323ce3eeac869eb14d07bda.tar.gz gcc-facc279fc19a31c23323ce3eeac869eb14d07bda.tar.bz2 |
defineclass.cc (handleMethodsBegin): Allocate _Jv_MethodBase pointers.
* defineclass.cc (handleMethodsBegin): Allocate _Jv_MethodBase
pointers.
(handleMethodsEnd): Fixed error messages. Create a _Jv_JNIMethod
if the method is native.
* resolve.cc (ncode): Don't handle native methods.
(_Jv_JNIMethod::ncode): New method.
(_Jv_PrepareClass): Handle native methods.
* jni.cc (call): Renamed from _Jv_JNI_conversion_call.
Include AbstractMethodError.h.
(add_char): New function.
(mangled_name): Likewise.
* include/java-interp.h (class _Jv_JNIMethod): New class.
(class _Jv_MethodBase): New class.
(class _Jv_InterpMethod): Derive from _Jv_MethodBase.
(_Jv_InterpClass): Changed `interpreted_methods' field to type
`_Jv_MethodBase'.
* include/jvm.h (_Jv_FindSymbolInExecutable): Declare.
* java/lang/natRuntime.cc (libraries_size, libraries_count,
libraries): New globals.
(add_library): New function.
(_Jv_FindSymbolInExecutable): New function.
* java/lang/natClassLoader.cc (initiated_classes, loaded_classes):
Now static.
From-SVN: r31790
Diffstat (limited to 'libjava')
-rw-r--r-- | libjava/ChangeLog | 28 | ||||
-rw-r--r-- | libjava/defineclass.cc | 33 | ||||
-rw-r--r-- | libjava/include/java-interp.h | 39 | ||||
-rw-r--r-- | libjava/include/jvm.h | 3 | ||||
-rw-r--r-- | libjava/java/lang/natClassLoader.cc | 8 | ||||
-rw-r--r-- | libjava/java/lang/natRuntime.cc | 47 | ||||
-rw-r--r-- | libjava/jni.cc | 128 | ||||
-rw-r--r-- | libjava/resolve.cc | 84 |
8 files changed, 312 insertions, 58 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog index a8361a9..77122f1 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,31 @@ +2000-02-04 Tom Tromey <tromey@cygnus.com> + + * defineclass.cc (handleMethodsBegin): Allocate _Jv_MethodBase + pointers. + (handleMethodsEnd): Fixed error messages. Create a _Jv_JNIMethod + if the method is native. + * resolve.cc (ncode): Don't handle native methods. + (_Jv_JNIMethod::ncode): New method. + (_Jv_PrepareClass): Handle native methods. + * jni.cc (call): Renamed from _Jv_JNI_conversion_call. + Include AbstractMethodError.h. + (add_char): New function. + (mangled_name): Likewise. + * include/java-interp.h (class _Jv_JNIMethod): New class. + (class _Jv_MethodBase): New class. + (class _Jv_InterpMethod): Derive from _Jv_MethodBase. + (_Jv_InterpClass): Changed `interpreted_methods' field to type + `_Jv_MethodBase'. + + * include/jvm.h (_Jv_FindSymbolInExecutable): Declare. + * java/lang/natRuntime.cc (libraries_size, libraries_count, + libraries): New globals. + (add_library): New function. + (_Jv_FindSymbolInExecutable): New function. + + * java/lang/natClassLoader.cc (initiated_classes, loaded_classes): + Now static. + 2000-02-04 Andrew Haley <aph@cygnus.com> * java/lang/Throwable.java (CPlusPlusDemangler): New class. diff --git a/libjava/defineclass.cc b/libjava/defineclass.cc index a439834..215fc23 100644 --- a/libjava/defineclass.cc +++ b/libjava/defineclass.cc @@ -1142,13 +1142,15 @@ void _Jv_ClassReader::handleFieldsEnd () -void _Jv_ClassReader::handleMethodsBegin (int count) +void +_Jv_ClassReader::handleMethodsBegin (int count) { def->methods = (_Jv_Method*) _Jv_AllocBytesChecked (sizeof (_Jv_Method)*count); - def->interpreted_methods = (_Jv_InterpMethod**) - _Jv_AllocBytesChecked (sizeof (_Jv_InterpMethod*) * count); + def->interpreted_methods + = (_Jv_MethodBase **) _Jv_AllocBytesChecked (sizeof (_Jv_MethodBase *) + * count); for (int i = 0; i < count; i++) def->interpreted_methods[i] = 0; @@ -1230,7 +1232,8 @@ void _Jv_ClassReader::handleExceptionTableEntry (int method_index, int exc_index, int start_pc, int end_pc, int handler_pc, int catch_type) { - _Jv_InterpMethod *method = def->interpreted_methods[method_index]; + _Jv_InterpMethod *method = reinterpret_cast<_Jv_InterpMethod *> + (def->interpreted_methods[method_index]); _Jv_InterpException *exc = method->exceptions (); exc[exc_index].start_pc = start_pc; @@ -1246,17 +1249,29 @@ void _Jv_ClassReader::handleMethodsEnd () for (int i = 0; i < def->method_count; i++) { _Jv_Method *method = &def->methods[i]; - if (method->accflags & (Modifier::NATIVE | Modifier::ABSTRACT)) + if ((method->accflags & Modifier::NATIVE) != 0) + { + if (def->interpreted_methods[i] != 0) + throw_class_format_error ("code provided for native method"); + else + { + _Jv_JNIMethod *m = (_Jv_JNIMethod *) + _Jv_AllocBytesChecked (sizeof (_Jv_JNIMethod)); + m->defining_class = def; + m->self = method; + m->function = NULL; + def->interpreted_methods[i] = m; + } + } + else if ((method->accflags & Modifier::ABSTRACT) != 0) { if (def->interpreted_methods[i] != 0) - throw_class_format_error ("code provided " - "for abstract or native method"); + throw_class_format_error ("code provided for abstract method"); } else { if (def->interpreted_methods[i] == 0) - throw_class_format_error ("abstract or native method " - "with no code"); + throw_class_format_error ("method with no code"); } } diff --git a/libjava/include/java-interp.h b/libjava/include/java-interp.h index 0feab21..7022411 100644 --- a/libjava/include/java-interp.h +++ b/libjava/include/java-interp.h @@ -14,6 +14,18 @@ details. */ #include <jvm.h> #include <java-cpool.h> +// Base class for method representations. Subclasses are interpreted +// and JNI methods. +class _Jv_MethodBase +{ +protected: + // The class which defined this method. + _Jv_InterpClass *defining_class; + + // The method description. + _Jv_Method *self; +}; + #ifdef INTERPRETER #pragma interface @@ -66,8 +78,8 @@ class _Jv_InterpException { friend class _Jv_InterpMethod; }; -class _Jv_InterpMethod { - +class _Jv_InterpMethod : public _Jv_MethodBase +{ _Jv_ushort max_stack; _Jv_ushort max_locals; int code_length; @@ -75,9 +87,6 @@ class _Jv_InterpMethod { _Jv_ushort exc_count; _Jv_ushort args_raw_size; - _Jv_InterpClass *defining_class; - _Jv_Method *self; - unsigned char* bytecode () { return @@ -121,9 +130,6 @@ class _Jv_InterpMethod { friend class gnu::gcj::runtime::MethodInvocation; friend void _Jv_PrepareClass(jclass); - - // This function is used when making a JNI call from the interpreter. - friend void _Jv_JNI_conversion_call (ffi_cif *, void *, ffi_raw *, void *); }; class _Jv_InterpMethodInvocation { @@ -140,7 +146,7 @@ class _Jv_InterpMethodInvocation { class _Jv_InterpClass : public java::lang::Class { - _Jv_InterpMethod **interpreted_methods; + _Jv_MethodBase **interpreted_methods; _Jv_ushort *field_initializers; friend class _Jv_ClassReader; @@ -165,4 +171,19 @@ struct _Jv_ResolvedMethod { #endif /* INTERPRETER */ +class _Jv_JNIMethod : public _Jv_MethodBase +{ + // The underlying function. If NULL we have to look for the + // function. + void *function; + + // This function is used when making a JNI call from the interpreter. + static void call (ffi_cif *, void *, ffi_raw *, void *); + + void *ncode (); + + friend class _Jv_ClassReader; + friend void _Jv_PrepareClass(jclass); +}; + #endif /* __JAVA_INTERP_H__ */ diff --git a/libjava/include/jvm.h b/libjava/include/jvm.h index ccf552a..325fe93 100644 --- a/libjava/include/jvm.h +++ b/libjava/include/jvm.h @@ -201,6 +201,9 @@ extern "C" extern char *_Jv_ThisExecutable (void); extern void _Jv_ThisExecutable (const char *); +/* Return a pointer to a symbol in executable or loaded library. */ +void *_Jv_FindSymbolInExecutable (const char *); + /* Initialize JNI. */ extern void _Jv_JNI_Init (void); diff --git a/libjava/java/lang/natClassLoader.cc b/libjava/java/lang/natClassLoader.cc index 77ae9f5b..ba7b2c6 100644 --- a/libjava/java/lang/natClassLoader.cc +++ b/libjava/java/lang/natClassLoader.cc @@ -308,8 +308,12 @@ struct _Jv_LoaderInfo { java::lang::ClassLoader *loader; }; -_Jv_LoaderInfo *initiated_classes[HASH_LEN]; -jclass loaded_classes[HASH_LEN]; +static _Jv_LoaderInfo *initiated_classes[HASH_LEN]; +static jclass loaded_classes[HASH_LEN]; + +// This is the root of a linked list of classes + + jclass _Jv_FindClassInCache (_Jv_Utf8Const *name, java::lang::ClassLoader *loader) diff --git a/libjava/java/lang/natRuntime.cc b/libjava/java/lang/natRuntime.cc index 3eabb90..dd8b0d0 100644 --- a/libjava/java/lang/natRuntime.cc +++ b/libjava/java/lang/natRuntime.cc @@ -24,7 +24,52 @@ details. */ /* FIXME: we don't always need this. The next libtool will let us use AC_LTDL_PREOPEN to see if we do. */ const lt_dlsymlist lt_preloaded_symbols[1] = { { 0, 0 } }; -#endif + +// We keep track of all the libraries loaded by this application. For +// now we use them to look up symbols for JNI. `libraries_size' holds +// the total size of the buffer. `libraries_count' is the number of +// items which are in use. +static int libraries_size; +static int libraries_count; +static lt_dlhandle *libraries; + +static void +add_library (lt_dlhandle lib) +{ + if (libraries_count == libraries_size) + { + int ns = libraries_size * 2; + if (ns == 0) + ns = 10; + lt_dlhandle *n = (lt_dlhandle *) _Jv_Malloc (ns * sizeof (lt_dlhandle)); + if (libraries) + { + memcpy (n, libraries, libraries_size * sizeof (lt_dlhandle)); + _Jv_Free (libraries); + } + libraries = n; + libraries_size = ns; + for (int i = libraries_count; i < libraries_size; ++i) + libraries[i] = NULL; + } + + libraries[libraries_count++] = lib; +} + +void * +_Jv_FindSymbolInExecutable (const char *symname) +{ + for (int i = 0; i < libraries_count; ++i) + { + void *r = lt_dlsym (libraries[i], symname); + if (r) + return r; + } + + return lt_dlsym (NULL, symname); +} + +#endif /* USE_LTDL */ void java::lang::Runtime::exit (jint status) diff --git a/libjava/jni.cc b/libjava/jni.cc index cb72261..da964e1 100644 --- a/libjava/jni.cc +++ b/libjava/jni.cc @@ -32,6 +32,7 @@ details. */ #include <java/lang/Throwable.h> #include <java/lang/ArrayIndexOutOfBoundsException.h> #include <java/lang/StringIndexOutOfBoundsException.h> +#include <java/lang/AbstractMethodError.h> #include <java/lang/InstantiationException.h> #include <java/lang/NoSuchFieldError.h> #include <java/lang/NoSuchMethodError.h> @@ -1204,15 +1205,101 @@ _Jv_JNI_FromReflectedMethod (JNIEnv *, jobject method) +// Add a character to the buffer, encoding properly. +static void +add_char (char *buf, jchar c, int *here) +{ + if (c == '_') + { + buf[(*here)++] = '_'; + buf[(*here)++] = '1'; + } + else if (c == ';') + { + buf[(*here)++] = '_'; + buf[(*here)++] = '2'; + } + else if (c == '[') + { + buf[(*here)++] = '_'; + buf[(*here)++] = '3'; + } + else if (c == '/') + buf[(*here)++] = '_'; + if ((c >= '0' && c <= '9') + || (c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z')) + buf[(*here)++] = (char) c; + else + { + // "Unicode" character. + buf[(*here)++] = '_'; + buf[(*here)++] = '0'; + for (int i = 0; i < 4; ++i) + { + int val = c & 0x0f; + buf[(*here) + 4 - i] = (val > 10) ? ('a' + val - 10) : ('0' + val); + c >>= 4; + } + *here += 4; + } +} + +// Compute a mangled name for a native function. This computes the +// long name, and also returns an index which indicates where a NUL +// can be placed to create the short name. This function assumes that +// the buffer is large enough for its results. +static void +mangled_name (jclass klass, _Jv_Utf8Const *func_name, + _Jv_Utf8Const *signature, char *buf, int *long_start) +{ + strcpy (buf, "Java_"); + int here = 5; + + // Add fully qualified class name. + jchar *chars = _Jv_GetStringChars (klass->getName ()); + jint len = klass->getName ()->length (); + for (int i = 0; i < len; ++i) + add_char (buf, chars[i], &here); + + // Don't use add_char because we need a literal `_'. + buf[here++] = '_'; + + const unsigned char *fn = (const unsigned char *) func_name->data; + const unsigned char *limit = fn + func_name->length; + for (int i = 0; ; ++i) + { + int ch = UTF8_GET (fn, limit); + if (ch < 0) + break; + add_char (buf, ch, &here); + } + + // This is where the long signature begins. + *long_start = here; + buf[here++] = '_'; + buf[here++] = '_'; + + const unsigned char *sig = (const unsigned char *) signature->data; + limit = sig + signature->length; + JvAssert (signature[0] == '('); + for (int i = 1; ; ++i) + { + int ch = UTF8_GET (sig, limit); + if (ch == ')' || ch < 0) + break; + add_char (buf, ch, &here); + } + + buf[here] = '\0'; +} + // This function is the stub which is used to turn an ordinary (CNI) // method call into a JNI call. void -_Jv_JNI_conversion_call (ffi_cif *cif, - void *ret, - ffi_raw *args, - void *__this) +_Jv_JNIMethod::call (ffi_cif *cif, void *ret, ffi_raw *args, void *__this) { - _Jv_InterpMethod* _this = (_Jv_InterpMethod*)__this; + _Jv_JNIMethod* _this = (_Jv_JNIMethod *) __this; JNIEnv env; _Jv_JNI_LocalFrame *frame @@ -1234,10 +1321,33 @@ _Jv_JNI_conversion_call (ffi_cif *cif, // now we assume a conservative GC, and we assume that the // references are on the stack somewhere. - ffi_raw_call (cif, - NULL, // FIXME: function pointer. - ret, - args); + // We cache the value that we find, of course, but if we don't find + // a value we don't cache that fact -- we might subsequently load a + // library which finds the function in question. + if (_this->function == NULL) + { + char buf[10 + 6 * (_this->self->name->length + + _this->self->signature->length)]; + int long_start; + mangled_name (_this->defining_class, _this->self->name, + _this->self->signature, buf, &long_start); + char c = buf[long_start]; + buf[long_start] = '\0'; + _this->function = _Jv_FindSymbolInExecutable (buf); + if (_this->function == NULL) + { + buf[long_start] = c; + _this->function = _Jv_FindSymbolInExecutable (buf); + if (_this->function == NULL) + { + jstring str = JvNewStringUTF (_this->self->name->data); + JvThrow (new java::lang::AbstractMethodError (str)); + } + } + } + + // The actual call to the JNI function. + ffi_raw_call (cif, (void (*) (...)) _this->function, ret, args); do { diff --git a/libjava/resolve.cc b/libjava/resolve.cc index 0bf6f8c..eb9a371 100644 --- a/libjava/resolve.cc +++ b/libjava/resolve.cc @@ -563,21 +563,21 @@ _Jv_PrepareClass(jclass klass) have code -- for static constructors. */ for (int i = 0; i < clz->method_count; i++) { - _Jv_InterpMethod *imeth = clz->interpreted_methods[i]; + _Jv_MethodBase *imeth = clz->interpreted_methods[i]; - if (imeth != 0) // it could be abstract or native + if ((clz->methods[i].accflags & Modifier::NATIVE) != 0) { - clz->methods[i].ncode = imeth->ncode (); + // You might think we could use a virtual `ncode' method in + // the _Jv_MethodBase and unify the native and non-native + // cases. Well, we can't, because we don't allocate these + // objects using `new', and thus they don't get a vtable. + _Jv_JNIMethod *jnim = reinterpret_cast<_Jv_JNIMethod *> (imeth); + clz->methods[i].ncode = jnim->ncode (); } - else + else if (imeth != 0) // it could be abstract { - if ((clz->methods[i].accflags & Modifier::NATIVE) != 0) - { - JvThrow - (new java::lang::VirtualMachineError - (JvNewStringLatin1 - ("the interpreter does not support native methods"))); - } + _Jv_InterpMethod *im = reinterpret_cast<_Jv_InterpMethod *> (im); + clz->methods[i].ncode = im->ncode (); } } @@ -588,13 +588,6 @@ _Jv_PrepareClass(jclass klass) return; } - /* FIXME: native methods for interpreted classes should be handled, I - * dunno exactly how, but it seems that we should try to find them at - * this point, and if we fail, try again after <clinit>, since it - * could have caused additional code to be loaded. Interfaces cannot - * have native methods (not even for static initialization). */ - - /* Now onto the actual job: vtable layout. First, count how many new methods we have */ int new_method_count = 0; @@ -1022,13 +1015,9 @@ _Jv_InterpMethod::ncode () args_raw_size = ffi_raw_size (&closure->cif); - if ((self->accflags & Modifier::NATIVE) != 0) - { - // FIXME: for now we assume that all native methods for - // interpreted code use JNI. - fun = (ffi_closure_fun) &_Jv_JNI_conversion_call; - } - else if ((self->accflags & Modifier::SYNCHRONIZED) != 0) + JvAssert ((self->accflags & Modifier::NATIVE) == 0); + + if ((self->accflags & Modifier::SYNCHRONIZED) != 0) { if (staticp) fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class; @@ -1041,9 +1030,48 @@ _Jv_InterpMethod::ncode () } ffi_prep_raw_closure (&closure->closure, - &closure->cif, - fun, - (void*)this); + &closure->cif, + fun, + (void*) this); + + self->ncode = (void*)closure; + return self->ncode; +} + + +void * +_Jv_JNIMethod::ncode () +{ + using namespace java::lang::reflect; + + if (self->ncode != 0) + return self->ncode; + + jboolean staticp = (self->accflags & Modifier::STATIC) != 0; + int arg_count = count_arguments (self->signature, staticp); + + ncode_closure *closure = + (ncode_closure*)_Jv_AllocBytesChecked (sizeof (ncode_closure) + + arg_count * sizeof (ffi_type*)); + + init_cif (self->signature, + arg_count, + staticp, + &closure->cif, + &closure->arg_types[0]); + + ffi_closure_fun fun; + + JvAssert ((self->accflags & Modifier::NATIVE) != 0); + + // FIXME: for now we assume that all native methods for + // interpreted code use JNI. + fun = (ffi_closure_fun) &_Jv_JNIMethod::call; + + ffi_prep_raw_closure (&closure->closure, + &closure->cif, + fun, + (void*) this); self->ncode = (void*)closure; return self->ncode; |