mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-26 02:30:30 +08:00
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
This commit is contained in:
parent
a89608cbeb
commit
facc279fc1
@ -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.
|
||||
|
@ -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 abstract or native method");
|
||||
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 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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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__ */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
128
libjava/jni.cc
128
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
|
||||
{
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user