aboutsummaryrefslogtreecommitdiff
path: root/libjava
diff options
context:
space:
mode:
authorTom Tromey <tromey@cygnus.com>2000-02-04 20:49:27 +0000
committerTom Tromey <tromey@gcc.gnu.org>2000-02-04 20:49:27 +0000
commitfacc279fc19a31c23323ce3eeac869eb14d07bda (patch)
treef2e35a2ea96bcecfa7499a5ec8161bd2528c22d5 /libjava
parenta89608cbebb11969af54ba5a5354302fab2a0b4b (diff)
downloadgcc-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/ChangeLog28
-rw-r--r--libjava/defineclass.cc33
-rw-r--r--libjava/include/java-interp.h39
-rw-r--r--libjava/include/jvm.h3
-rw-r--r--libjava/java/lang/natClassLoader.cc8
-rw-r--r--libjava/java/lang/natRuntime.cc47
-rw-r--r--libjava/jni.cc128
-rw-r--r--libjava/resolve.cc84
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;