From 0f918fea8b46618edfb2d302c9a920ceb64c22d0 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Tue, 4 Jan 2000 08:46:52 +0000 Subject: [PATCH] [multiple changes] 2000-01-04 Tom Tromey * java/lang/reflect/natConstructor.cc (newInstance): Pass declaring class as return_type argument to _Jv_CallNonvirtualMethodA. * java/lang/reflect/natMethod.cc (_Jv_CallNonvirtualMethodA): In constructor case, create object and use it as `this' argument. * java/lang/Class.h (_getConstructors): Declare. (_getFields): Declare. * java/lang/Class.java (getConstructors): Wrote. (_getConstructors): New native method. (getDeclaredConstructors): Wrote. (_getFields): Declare new native method. * java/lang/natClass.cc (_Jv_LookupInterfaceMethod): Removed incorrect comment. (getMethod): Work correctly when class is primitive. (getDeclaredMethods): Likewise. Compute offset using `method', not `mptr'. (getDeclaredMethod): Likewise. (getConstructor): Wrote. (ConstructorClass): New define. (getDeclaredConstructor): Wrote. (_getConstructors): New method. (_getFields): New method. (getFields): Wrote. * Makefile.in: Rebuilt. * Makefile.am (AM_CXXFLAGS): Added -D_GNU_SOURCE. * prims.cc: Remove `#pragma implementation'. * gcj/array.h: Remove `#pragma interface'. * prims.cc (_Jv_equaln): New function. * java/lang/Class.java (getSignature): Declare. * resolve.cc (_Jv_LookupDeclaredMethod): Moved to natClass.cc. * java/lang/natClass.cc (_Jv_LookupDeclaredMethod): Moved from resolve.cc. (getSignature): New method. (getDeclaredMethod): Wrote. (getMethod): Wrote. Include StringBuffer.h. * java/lang/Class.h (Class): Added _Jv_FromReflectedConstructor as a friend. Unconditionally declare _Jv_LookupDeclaredMethod as a friend. (getSignature): Declare. * include/jvm.h (_Jv_GetTypesFromSignature): Declare. (_Jv_equaln): Declare. (_Jv_CallNonvirtualMethodA): Declare. * Makefile.in: Rebuilt. * Makefile.am (nat_source_files): Added natConstructor.cc. (java/lang/reflect/Constructor.h): New target. * java/lang/reflect/natConstructor.cc: New file. * java/lang/reflect/Constructor.java (newInstance): Now native. (declaringClass): Renamed from decl_class. (offset): Renamed from index. (getType): New native method. (getModifiers): Now native. (getParameterTypes): Call getType if required. (hashCode): Include hash code from declaring class. (modifiers): Removed. (toString): Call getType if required. * gcj/method.h (_Jv_FromReflectedConstructor): New function. * java/lang/reflect/natMethod.cc (hack_call): New method. Removed `#if 0' around FFI code. Include . (invoke): Use _Jv_CallNonvirtualMethodA. Throw IllegalArgumentException when argument object and class disagree. (_Jv_GetTypesFromSignature): New function. (getType): Use it. (ObjectClass): New define. (_Jv_CallNonvirtualMethodA): New function. * java/lang/reflect/Method.java (hack_trampoline): New method. (hack_call): New native method. 1999-12-21 Per Bothner * java/lang/natClass.cc (getDeclaredMethods): Correctly compute offset in new Method. From-SVN: r31199 --- libjava/ChangeLog | 79 +++++ libjava/Makefile.am | 11 +- libjava/Makefile.in | 13 +- libjava/gcj/Makefile.in | 4 +- libjava/gcj/array.h | 2 - libjava/gcj/method.h | 7 + libjava/include/Makefile.in | 4 +- libjava/include/jvm.h | 8 + libjava/java/lang/Class.h | 11 +- libjava/java/lang/Class.java | 28 +- libjava/java/lang/natClass.cc | 261 ++++++++++++-- libjava/java/lang/reflect/Constructor.java | 47 ++- libjava/java/lang/reflect/Method.java | 28 +- libjava/java/lang/reflect/natConstructor.cc | 53 +++ libjava/java/lang/reflect/natMethod.cc | 374 ++++++++++++-------- libjava/prims.cc | 22 +- libjava/resolve.cc | 15 - libjava/testsuite/Makefile.in | 4 +- 18 files changed, 739 insertions(+), 232 deletions(-) create mode 100644 libjava/java/lang/reflect/natConstructor.cc diff --git a/libjava/ChangeLog b/libjava/ChangeLog index cfdd9860e89d..5cd39d244495 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,82 @@ +2000-01-04 Tom Tromey + + * java/lang/reflect/natConstructor.cc (newInstance): Pass + declaring class as return_type argument to + _Jv_CallNonvirtualMethodA. + * java/lang/reflect/natMethod.cc (_Jv_CallNonvirtualMethodA): In + constructor case, create object and use it as `this' argument. + * java/lang/Class.h (_getConstructors): Declare. + (_getFields): Declare. + * java/lang/Class.java (getConstructors): Wrote. + (_getConstructors): New native method. + (getDeclaredConstructors): Wrote. + (_getFields): Declare new native method. + * java/lang/natClass.cc (_Jv_LookupInterfaceMethod): Removed + incorrect comment. + (getMethod): Work correctly when class is primitive. + (getDeclaredMethods): Likewise. Compute offset using `method', + not `mptr'. + (getDeclaredMethod): Likewise. + (getConstructor): Wrote. + (ConstructorClass): New define. + (getDeclaredConstructor): Wrote. + (_getConstructors): New method. + (_getFields): New method. + (getFields): Wrote. + + * Makefile.in: Rebuilt. + * Makefile.am (AM_CXXFLAGS): Added -D_GNU_SOURCE. + + * prims.cc: Remove `#pragma implementation'. + * gcj/array.h: Remove `#pragma interface'. + + * prims.cc (_Jv_equaln): New function. + * java/lang/Class.java (getSignature): Declare. + * resolve.cc (_Jv_LookupDeclaredMethod): Moved to natClass.cc. + * java/lang/natClass.cc (_Jv_LookupDeclaredMethod): Moved from + resolve.cc. + (getSignature): New method. + (getDeclaredMethod): Wrote. + (getMethod): Wrote. + Include StringBuffer.h. + * java/lang/Class.h (Class): Added _Jv_FromReflectedConstructor + as a friend. Unconditionally declare _Jv_LookupDeclaredMethod as + a friend. + (getSignature): Declare. + * include/jvm.h (_Jv_GetTypesFromSignature): Declare. + (_Jv_equaln): Declare. + (_Jv_CallNonvirtualMethodA): Declare. + * Makefile.in: Rebuilt. + * Makefile.am (nat_source_files): Added natConstructor.cc. + (java/lang/reflect/Constructor.h): New target. + * java/lang/reflect/natConstructor.cc: New file. + * java/lang/reflect/Constructor.java (newInstance): Now native. + (declaringClass): Renamed from decl_class. + (offset): Renamed from index. + (getType): New native method. + (getModifiers): Now native. + (getParameterTypes): Call getType if required. + (hashCode): Include hash code from declaring class. + (modifiers): Removed. + (toString): Call getType if required. + * gcj/method.h (_Jv_FromReflectedConstructor): New function. + * java/lang/reflect/natMethod.cc (hack_call): New method. + Removed `#if 0' around FFI code. + Include . + (invoke): Use _Jv_CallNonvirtualMethodA. Throw + IllegalArgumentException when argument object and class disagree. + (_Jv_GetTypesFromSignature): New function. + (getType): Use it. + (ObjectClass): New define. + (_Jv_CallNonvirtualMethodA): New function. + * java/lang/reflect/Method.java (hack_trampoline): New method. + (hack_call): New native method. + +1999-12-21 Per Bothner + + * java/lang/natClass.cc (getDeclaredMethods): Correctly compute + offset in new Method. + 1999-12-22 Bryce McKinlay * java/lang/natObject.cc (notify): Throw message with diff --git a/libjava/Makefile.am b/libjava/Makefile.am index ee5a88e00122..d15784dfb421 100644 --- a/libjava/Makefile.am +++ b/libjava/Makefile.am @@ -74,8 +74,10 @@ JAVAC = $(GCJ) -C EH_COMMON_INCLUDE = @EH_COMMON_INCLUDE@ WARNINGS = -W -Wall +## We need _GNU_SOURCE defined for some Linux builds. It doesn't hurt +## to always define it. AM_CXXFLAGS = -fno-rtti -fvtable-thunks @LIBGCJ_CXXFLAGS@ @EXCEPTIONSPEC@ \ - $(WARNINGS) + $(WARNINGS) -D_GNU_SOURCE if USING_GCC AM_CFLAGS = @LIBGCJ_CFLAGS@ $(WARNINGS) else @@ -229,6 +231,12 @@ java/lang/String.h: java/lang/String.class libgcj.zip -friend 'jstring _Jv_AllocString (jsize);' \ $(basename $<) +java/lang/reflect/Constructor.h: java/lang/reflect/Constructor.class libgcj.zip + $(GCJH) -classpath $(top_builddir) \ + -friend 'jmethodID _Jv_FromReflectedConstructor (java::lang::reflect::Constructor *);' \ + -friend 'java::lang::Class;' \ + $(basename $<) + java/lang/reflect/Field.h: java/lang/reflect/Field.class libgcj.zip $(GCJH) -classpath $(top_builddir) \ -friend 'jfieldID _Jv_FromReflectedField (java::lang::reflect::Field *);' \ @@ -797,6 +805,7 @@ java/lang/natString.cc \ java/lang/natSystem.cc \ java/lang/natThread.cc \ java/lang/reflect/natArray.cc \ +java/lang/reflect/natConstructor.cc \ java/lang/reflect/natField.cc \ java/lang/reflect/natMethod.cc \ java/net/natInetAddress.cc \ diff --git a/libjava/Makefile.in b/libjava/Makefile.in index d71f07061dea..feb516de38de 100644 --- a/libjava/Makefile.in +++ b/libjava/Makefile.in @@ -158,7 +158,7 @@ EH_COMMON_INCLUDE = @EH_COMMON_INCLUDE@ WARNINGS = -W -Wall AM_CXXFLAGS = -fno-rtti -fvtable-thunks @LIBGCJ_CXXFLAGS@ @EXCEPTIONSPEC@ \ - $(WARNINGS) + $(WARNINGS) -D_GNU_SOURCE @USING_GCC_TRUE@AM_CFLAGS = \ @USING_GCC_TRUE@@LIBGCJ_CFLAGS@ $(WARNINGS) @@ -619,6 +619,7 @@ java/lang/natString.cc \ java/lang/natSystem.cc \ java/lang/natThread.cc \ java/lang/reflect/natArray.cc \ +java/lang/reflect/natConstructor.cc \ java/lang/reflect/natField.cc \ java/lang/reflect/natMethod.cc \ java/net/natInetAddress.cc \ @@ -726,7 +727,7 @@ THANKS acinclude.m4 aclocal.m4 configure configure.in libgcj.spec.in DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) -TAR = gtar +TAR = tar GZIP_ENV = --best DIST_SUBDIRS = testsuite gcj include gcj include DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \ @@ -1267,7 +1268,7 @@ distdir: $(DISTFILES) @for file in $(DISTFILES); do \ d=$(srcdir); \ if test -d $$d/$$file; then \ - cp -pr $$d/$$file $(distdir)/$$file; \ + cp -pr $$/$$file $(distdir)/$$file; \ else \ test -f $(distdir)/$$file \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ @@ -1513,6 +1514,12 @@ java/lang/String.h: java/lang/String.class libgcj.zip -friend 'jstring _Jv_AllocString (jsize);' \ $(basename $<) +java/lang/reflect/Constructor.h: java/lang/reflect/Constructor.class libgcj.zip + $(GCJH) -classpath $(top_builddir) \ + -friend 'jmethodID _Jv_FromReflectedConstructor (java::lang::reflect::Constructor *);' \ + -friend 'java::lang::Class;' \ + $(basename $<) + java/lang/reflect/Field.h: java/lang/reflect/Field.class libgcj.zip $(GCJH) -classpath $(top_builddir) \ -friend 'jfieldID _Jv_FromReflectedField (java::lang::reflect::Field *);' \ diff --git a/libjava/gcj/Makefile.in b/libjava/gcj/Makefile.in index 7bbcec49f685..a149935cf1e7 100644 --- a/libjava/gcj/Makefile.in +++ b/libjava/gcj/Makefile.in @@ -76,12 +76,14 @@ DLLTOOL = @DLLTOOL@ EH_COMMON_INCLUDE = @EH_COMMON_INCLUDE@ EXCEPTIONSPEC = @EXCEPTIONSPEC@ EXEEXT = @EXEEXT@ +FORCELIBGCCSPEC = @FORCELIBGCCSPEC@ GCDEPS = @GCDEPS@ GCINCS = @GCINCS@ GCLIBS = @GCLIBS@ GCOBJS = @GCOBJS@ GCSPEC = @GCSPEC@ LD = @LD@ +LIBDATASTARTSPEC = @LIBDATASTARTSPEC@ LIBGCJ_CFLAGS = @LIBGCJ_CFLAGS@ LIBGCJ_CXXFLAGS = @LIBGCJ_CXXFLAGS@ LIBGCJ_JAVAFLAGS = @LIBGCJ_JAVAFLAGS@ @@ -90,7 +92,6 @@ LN_S = @LN_S@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ NM = @NM@ -OBJDUMP = @OBJDUMP@ PACKAGE = @PACKAGE@ PERL = @PERL@ RANLIB = @RANLIB@ @@ -100,6 +101,7 @@ THREADINCS = @THREADINCS@ THREADLIBS = @THREADLIBS@ THREADOBJS = @THREADOBJS@ THREADSPEC = @THREADSPEC@ +USE_SYMBOL_UNDERSCORE = @USE_SYMBOL_UNDERSCORE@ VERSION = @VERSION@ ZDEPS = @ZDEPS@ ZINCS = @ZINCS@ diff --git a/libjava/gcj/array.h b/libjava/gcj/array.h index f3733595e76d..76a75f61e0d9 100644 --- a/libjava/gcj/array.h +++ b/libjava/gcj/array.h @@ -11,8 +11,6 @@ details. */ #ifndef __GCJ_ARRAY_H__ #define __GCJ_ARRAY_H__ -#pragma interface - #include extern "Java" { diff --git a/libjava/gcj/method.h b/libjava/gcj/method.h index a97ba4a682fb..e5402a0ed8ae 100644 --- a/libjava/gcj/method.h +++ b/libjava/gcj/method.h @@ -18,4 +18,11 @@ _Jv_FromReflectedMethod(java::lang::reflect::Method *method) ((char *) method->declaringClass->methods + method->offset); } +extern inline jmethodID +_Jv_FromReflectedConstructor (java::lang::reflect::Constructor *constructor) +{ + return (jmethodID) + ((char *) constructor->declaringClass->methods + constructor->offset); +} + #endif /* __GCJ_METHOD_H__ */ diff --git a/libjava/include/Makefile.in b/libjava/include/Makefile.in index d68544b9e729..38af4a5872b6 100644 --- a/libjava/include/Makefile.in +++ b/libjava/include/Makefile.in @@ -76,12 +76,14 @@ DLLTOOL = @DLLTOOL@ EH_COMMON_INCLUDE = @EH_COMMON_INCLUDE@ EXCEPTIONSPEC = @EXCEPTIONSPEC@ EXEEXT = @EXEEXT@ +FORCELIBGCCSPEC = @FORCELIBGCCSPEC@ GCDEPS = @GCDEPS@ GCINCS = @GCINCS@ GCLIBS = @GCLIBS@ GCOBJS = @GCOBJS@ GCSPEC = @GCSPEC@ LD = @LD@ +LIBDATASTARTSPEC = @LIBDATASTARTSPEC@ LIBGCJ_CFLAGS = @LIBGCJ_CFLAGS@ LIBGCJ_CXXFLAGS = @LIBGCJ_CXXFLAGS@ LIBGCJ_JAVAFLAGS = @LIBGCJ_JAVAFLAGS@ @@ -90,7 +92,6 @@ LN_S = @LN_S@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ NM = @NM@ -OBJDUMP = @OBJDUMP@ PACKAGE = @PACKAGE@ PERL = @PERL@ RANLIB = @RANLIB@ @@ -100,6 +101,7 @@ THREADINCS = @THREADINCS@ THREADLIBS = @THREADLIBS@ THREADOBJS = @THREADOBJS@ THREADSPEC = @THREADSPEC@ +USE_SYMBOL_UNDERSCORE = @USE_SYMBOL_UNDERSCORE@ VERSION = @VERSION@ ZDEPS = @ZDEPS@ ZINCS = @ZINCS@ diff --git a/libjava/include/jvm.h b/libjava/include/jvm.h index 791cdfadec95..3b59b8dfe7c3 100644 --- a/libjava/include/jvm.h +++ b/libjava/include/jvm.h @@ -53,6 +53,7 @@ _Jv_Utf8Const *_Jv_makeUtf8Const (char *s, int len); _Jv_Utf8Const *_Jv_makeUtf8Const (jstring string); extern jboolean _Jv_equalUtf8Consts (_Jv_Utf8Const *, _Jv_Utf8Const *); extern jboolean _Jv_equal (_Jv_Utf8Const *, jstring, jint); +extern jboolean _Jv_equaln (_Jv_Utf8Const *, jstring, jint); #define StringClass _CL_Q34java4lang6String extern java::lang::Class StringClass; @@ -161,6 +162,13 @@ extern jclass _Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader); extern jclass _Jv_FindClassFromSignature (char *, java::lang::ClassLoader *loader); +extern void _Jv_GetTypesFromSignature (jmethodID method, + jclass declaringClass, + JArray **arg_types_out, + jclass *return_type_out); +extern jobject _Jv_CallNonvirtualMethodA (jobject, jclass, + jmethodID, jboolean, + JArray *, jobjectArray); extern jobject _Jv_NewMultiArray (jclass, jint ndims, jint* dims) __attribute__((__malloc__)); diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h index c88c86e2e84b..dfdbf72c831e 100644 --- a/libjava/java/lang/Class.h +++ b/libjava/java/lang/Class.h @@ -1,6 +1,6 @@ // Class.h - Header file for java.lang.Class. -*- c++ -*- -/* Copyright (C) 1998, 1999 Cygnus Solutions +/* Copyright (C) 1998, 1999, 2000 Cygnus Solutions This file is part of libgcj. @@ -94,12 +94,16 @@ public: java::lang::reflect::Field *getField (jstring); private: + jint _getFields (JArray *result, jint offset); + JArray *_getConstructors (jboolean); java::lang::reflect::Field *getField (jstring, jint); public: JArray *getFields (void); JArray *getInterfaces (void); + void getSignature (java::lang::StringBuffer *buffer); + static jstring getSignature (JArray *); java::lang::reflect::Method *getMethod (jstring, JArray *); JArray *getMethods (void); @@ -156,6 +160,8 @@ private: // Friend functions implemented in natClass.cc. friend _Jv_Method *_Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name, _Jv_Utf8Const *signature); + friend _Jv_Method* _Jv_LookupDeclaredMethod (jclass, _Jv_Utf8Const *, + _Jv_Utf8Const*); friend void _Jv_InitClass (jclass klass); friend jfieldID JvGetFirstInstanceField (jclass); @@ -166,6 +172,7 @@ private: friend jobject _Jv_JNI_ToReflectedField (_Jv_JNIEnv *, jclass, jfieldID); friend jfieldID _Jv_FromReflectedField (java::lang::reflect::Field *); friend jmethodID _Jv_FromReflectedMethod (java::lang::reflect::Method *); + friend jmethodID _Jv_FromReflectedConstructor (java::lang::reflect::Constructor *); friend class _Jv_PrimClass; @@ -190,8 +197,6 @@ private: #ifdef INTERPRETER friend jboolean _Jv_IsInterpretedClass (jclass); friend void _Jv_InitField (jobject, jclass, _Jv_Field*); - friend _Jv_Method* _Jv_LookupDeclaredMethod (jclass, _Jv_Utf8Const *, - _Jv_Utf8Const*); friend int _Jv_DetermineVTableIndex (jclass, _Jv_Utf8Const *, _Jv_Utf8Const*); friend void _Jv_InitField (jobject, jclass, int); diff --git a/libjava/java/lang/Class.java b/libjava/java/lang/Class.java index f9bd59b25981..a304e6c01137 100644 --- a/libjava/java/lang/Class.java +++ b/libjava/java/lang/Class.java @@ -1,6 +1,6 @@ // Class.java - Representation of a Java class. -/* Copyright (C) 1998, 1999 Cygnus Solutions +/* Copyright (C) 1998, 1999, 2000 Cygnus Solutions This file is part of libgcj. @@ -36,14 +36,27 @@ public final class Class implements Serializable public native Constructor getConstructor (Class[] parameterTypes) throws NoSuchMethodException, SecurityException; - public native Constructor[] getConstructors () throws SecurityException; - public native Class[] getDeclaredClasses () throws SecurityException; + // This is used to implement getConstructors and + // getDeclaredConstructors. + private native Constructor[] _getConstructors (boolean declared) + throws SecurityException; + + public Constructor[] getConstructors () throws SecurityException + { + return _getConstructors (false); + } public native Constructor getDeclaredConstructor (Class[] parameterTypes) throws NoSuchMethodException, SecurityException; - public native Constructor[] getDeclaredConstructors () - throws SecurityException; + + public native Class[] getDeclaredClasses () throws SecurityException; + + public Constructor[] getDeclaredConstructors () throws SecurityException + { + return _getConstructors (true); + } + public native Field getDeclaredField (String fieldName) throws NoSuchFieldException, SecurityException; public native Field[] getDeclaredFields () throws SecurityException; @@ -69,10 +82,15 @@ public final class Class implements Serializable throw new NoSuchFieldException(fieldName); return fld; } + + private native Field[] _getFields (Field[] result, int offset); public native Field[] getFields () throws SecurityException; public native Class[] getInterfaces (); + private final native void getSignature (StringBuffer buffer); + private static final native String getSignature (Class[] parameterTypes); + public native Method getMethod (String methodName, Class[] parameterTypes) throws NoSuchMethodException, SecurityException; public native Method[] getMethods () throws SecurityException; diff --git a/libjava/java/lang/natClass.cc b/libjava/java/lang/natClass.cc index 20720312f588..939fe387e7ae 100644 --- a/libjava/java/lang/natClass.cc +++ b/libjava/java/lang/natClass.cc @@ -1,6 +1,6 @@ // natClass.cc - Implementation of java.lang.Class native methods. -/* Copyright (C) 1998, 1999 Cygnus Solutions +/* Copyright (C) 1998, 1999, 2000 Cygnus Solutions This file is part of libgcj. @@ -38,6 +38,7 @@ details. */ #include #include #include +#include #include @@ -55,6 +56,8 @@ extern java::lang::Class ClassClass; extern java::lang::Class MethodClass; #define FieldClass _CL_Q44java4lang7reflect5Field extern java::lang::Class FieldClass; +#define ConstructorClass _CL_Q44java4lang7reflect11Constructor +extern java::lang::Class ConstructorClass; // Some constants we use to look up the class initializer. static _Jv_Utf8Const *void_signature = _Jv_makeUtf8Const ("()V", 3); @@ -96,27 +99,95 @@ java::lang::Class::forName (jstring className) } java::lang::reflect::Constructor * -java::lang::Class::getConstructor (JArray *) +java::lang::Class::getConstructor (JArray *param_types) { - JvFail ("java::lang::Class::getConstructor not implemented"); + jstring partial_sig = getSignature (param_types); + jint hash = partial_sig->hashCode (); + + int i = isPrimitive () ? 0 : method_count; + while (--i >= 0) + { + // FIXME: access checks. + if (_Jv_equalUtf8Consts (methods[i].name, init_name) + && _Jv_equal (methods[i].signature, partial_sig, hash)) + { + // Found it. For getConstructor, the constructor must be + // public. + using namespace java::lang::reflect; + if (Modifier::isPublic(methods[i].accflags)) + break; + Constructor *cons = new Constructor (); + cons->offset = (char *) (&methods[i]) - (char *) methods; + cons->declaringClass = this; + return cons; + } + } + JvThrow (new java::lang::NoSuchMethodException); } JArray * -java::lang::Class::getConstructors (void) +java::lang::Class::_getConstructors (jboolean declared) { - JvFail ("java::lang::Class::getConstructors not implemented"); + // FIXME: this method needs access checks. + + int numConstructors = 0; + int max = isPrimitive () ? 0 : method_count; + int i; + for (i = max; --i >= 0; ) + { + _Jv_Method *method = &methods[i]; + if (method->name == NULL + && ! _Jv_equalUtf8Consts (method->name, init_name)) + continue; + if (declared + && ! java::lang::reflect::Modifier::isPublic(method->accflags)) + continue; + numConstructors++; + } + JArray *result + = (JArray *) + JvNewObjectArray (numConstructors, &ConstructorClass, NULL); + java::lang::reflect::Constructor** cptr = elements (result); + for (i = 0; i < max; i++) + { + _Jv_Method *method = &methods[i]; + if (method->name == NULL + && ! _Jv_equalUtf8Consts (method->name, init_name)) + continue; + if (declared + && ! java::lang::reflect::Modifier::isPublic(method->accflags)) + continue; + java::lang::reflect::Constructor *cons + = new java::lang::reflect::Constructor (); + cons->offset = (char *) method - (char *) methods; + cons->declaringClass = this; + *cptr++ = cons; + } + return result; } java::lang::reflect::Constructor * -java::lang::Class::getDeclaredConstructor (JArray *) +java::lang::Class::getDeclaredConstructor (JArray *param_types) { - JvFail ("java::lang::Class::getDeclaredConstructor not implemented"); -} + jstring partial_sig = getSignature (param_types); + jint hash = partial_sig->hashCode (); -JArray * -java::lang::Class::getDeclaredConstructors (void) -{ - JvFail ("java::lang::Class::getDeclaredConstructors not implemented"); + int i = isPrimitive () ? 0 : method_count; + while (--i >= 0) + { + // FIXME: access checks. + if (_Jv_equalUtf8Consts (methods[i].name, init_name) + && _Jv_equal (methods[i].signature, partial_sig, hash)) + { + // Found it. + using namespace java::lang::reflect; + Constructor *cons = new Constructor (); + cons->offset = (char *) (&methods[i]) - (char *) methods; + cons->declaringClass = this; + return cons; + } + } + JvThrow (new java::lang::NoSuchMethodException); } java::lang::reflect::Field * @@ -187,18 +258,67 @@ java::lang::Class::getDeclaredFields (void) return result; } -java::lang::reflect::Method * -java::lang::Class::getDeclaredMethod (jstring, JArray *) +void +java::lang::Class::getSignature (java::lang::StringBuffer *buffer) { - JvFail ("java::lang::Class::getDeclaredMethod not implemented"); + if (isPrimitive()) + buffer->append((jchar) method_count); + else + { + jstring name = getName(); + if (name->charAt(0) != '[') + buffer->append((jchar) 'L'); + buffer->append(name); + if (name->charAt(0) != '[') + buffer->append((jchar) ';'); + } +} + +// This doesn't have to be native. It is an implementation detail +// only called from the C++ code, though, so maybe this is clearer. +jstring +java::lang::Class::getSignature (JArray *param_types) +{ + java::lang::StringBuffer *buf = new java::lang::StringBuffer (); + buf->append((jchar) '('); + jclass *v = elements (param_types); + for (int i = 0; i < param_types->length; ++i) + v[i]->getSignature(buf); + buf->append((jchar) ')'); + return buf->toString(); +} + +java::lang::reflect::Method * +java::lang::Class::getDeclaredMethod (jstring name, + JArray *param_types) +{ + jstring partial_sig = getSignature (param_types); + jint p_len = partial_sig->length(); + _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name); + int i = isPrimitive () ? 0 : method_count; + while (--i >= 0) + { + // FIXME: access checks. + if (_Jv_equalUtf8Consts (methods[i].name, utf_name) + && _Jv_equaln (methods[i].signature, partial_sig, p_len)) + { + // Found it. + using namespace java::lang::reflect; + Method *rmethod = new Method (); + rmethod->offset = (char*) (&methods[i]) - (char*) methods; + rmethod->declaringClass = this; + } + } + JvThrow (new java::lang::NoSuchMethodException); } JArray * java::lang::Class::getDeclaredMethods (void) { int numMethods = 0; + int max = isPrimitive () ? 0 : method_count; int i; - for (i = method_count; --i >= 0; ) + for (i = max; --i >= 0; ) { _Jv_Method *method = &methods[i]; if (method->name == NULL @@ -211,15 +331,16 @@ java::lang::Class::getDeclaredMethods (void) = (JArray *) JvNewObjectArray (numMethods, &MethodClass, NULL); java::lang::reflect::Method** mptr = elements (result); - for (i = 0; i < method_count; i++) + for (i = 0; i < max; i++) { _Jv_Method *method = &methods[i]; if (method->name == NULL || _Jv_equalUtf8Consts (method->name, clinit_name) || _Jv_equalUtf8Consts (method->name, init_name)) continue; - java::lang::reflect::Method* rmethod = new java::lang::reflect::Method (); - rmethod->offset = (char*) mptr - (char*) elements (result); + java::lang::reflect::Method* rmethod + = new java::lang::reflect::Method (); + rmethod->offset = (char*) method - (char*) methods; rmethod->declaringClass = this; *mptr++ = rmethod; } @@ -258,10 +379,58 @@ java::lang::Class::getDeclaringClass (void) return NULL; // Placate compiler. } +jint +java::lang::Class::_getFields (JArray *result, + jint offset) +{ + int count = 0; + for (int i = 0; i < field_count; i++) + { + _Jv_Field *field = &fields[i]; + if (! (field->getModifiers() & java::lang::reflect::Modifier::PUBLIC)) + continue; + ++count; + + if (result != NULL) + { + java::lang::reflect::Field *rfield + = new java::lang::reflect::Field (); + rfield->offset = (char *) field - (char *) fields; + rfield->declaringClass = this; + rfield->name = _Jv_NewStringUtf8Const (field->name); + (elements (result))[offset + i] = rfield; + } + } + jclass superclass = getSuperclass(); + if (superclass != NULL) + { + int s_count = superclass->_getFields (result, offset); + count += s_count; + offset += s_count; + } + for (int i = 0; i < interface_count; ++i) + { + int f_count = interfaces[i]->_getFields (result, offset); + count += f_count; + offset += f_count; + } + return count; +} + JArray * java::lang::Class::getFields (void) { - JvFail ("java::lang::Class::getFields not implemented"); + using namespace java::lang::reflect; + + int count = _getFields (NULL, 0); + + JArray *result + = ((JArray *) + JvNewObjectArray (count, &FieldClass, NULL)); + + _getFields (result, 0); + + return result; } JArray * @@ -275,9 +444,30 @@ java::lang::Class::getInterfaces (void) } java::lang::reflect::Method * -java::lang::Class::getMethod (jstring, JArray *) +java::lang::Class::getMethod (jstring name, JArray *param_types) { - JvFail ("java::lang::Class::getMethod not implemented"); + jstring partial_sig = getSignature (param_types); + jint p_len = partial_sig->length(); + _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name); + for (Class *klass = this; klass; klass = klass->getSuperclass()) + { + int i = klass->isPrimitive () ? 0 : klass->method_count; + while (--i >= 0) + { + // FIXME: access checks. + if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name) + && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len)) + { + // Found it. + using namespace java::lang::reflect; + Method *rmethod = new Method (); + rmethod->offset = (char*) (&klass->methods[i]) - (char*) methods; + rmethod->declaringClass = klass; + return rmethod; + } + } + } + JvThrow (new java::lang::NoSuchMethodException); } JArray * @@ -494,6 +684,8 @@ java::lang::Class::initializeClass (void) // Some class-related convenience functions. // +// Find a method declared in the class. If it is not declared locally +// (or if it is inherited), return NULL. _Jv_Method * _Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name, _Jv_Utf8Const *signature) @@ -507,6 +699,21 @@ _Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name, return NULL; } +_Jv_Method * +_Jv_LookupDeclaredMethod (jclass klass, _Jv_Utf8Const *name, + _Jv_Utf8Const *signature) +{ + for (; klass; klass = klass->getSuperclass()) + { + _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature); + + if (meth) + return meth; + } + + return NULL; +} + // NOTE: MCACHE_SIZE should be a power of 2 minus one. #define MCACHE_SIZE 1023 @@ -553,16 +760,6 @@ void * _Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name, _Jv_Utf8Const *signature) { - // FIXME: can't do this until we have a working class loader. - // This probably isn't the right thing to do anyway, since we can't - // call a method of a class until the class is linked. But this - // captures the general idea. - // klass->getClassLoader()->resolveClass(klass); - // - // KKT: This is unnessecary, exactly for the reason you present: - // _Jv_LookupInterfaceMethod is only called on object instances, and - // such have already been initialized (which includes resolving). - void *ncode = _Jv_FindMethodInCache (klass, name, signature); if (ncode != 0) return ncode; diff --git a/libjava/java/lang/reflect/Constructor.java b/libjava/java/lang/reflect/Constructor.java index 466c1204bae1..7815d7cedc68 100644 --- a/libjava/java/lang/reflect/Constructor.java +++ b/libjava/java/lang/reflect/Constructor.java @@ -28,12 +28,12 @@ public final class Constructor extends AccessibleObject implements Member if (! (obj instanceof Constructor)) return false; Constructor c = (Constructor) obj; - return decl_class == c.decl_class && index == c.index; + return declaringClass == c.declaringClass && offset == c.offset; } public Class getDeclaringClass () { - return decl_class; + return declaringClass; } public Class[] getExceptionTypes () @@ -41,40 +41,39 @@ public final class Constructor extends AccessibleObject implements Member return (Class[]) exception_types.clone(); } - public int getModifiers () - { - return modifiers; - } + public native int getModifiers (); public String getName () - { - return decl_class.getName(); - } + { + return declaringClass.getName(); + } public Class[] getParameterTypes () { + if (parameter_types == null) + getType (); return (Class[]) parameter_types.clone(); } public int hashCode () { // FIXME. - return getName().hashCode(); + return getName().hashCode() + declaringClass.getName().hashCode(); } - // FIXME: this must be native. Should share implementation with - // Method.invoke. - public Object newInstance (Object[] args) + // Update cached values from method descriptor in class. + private native void getType (); + + public native Object newInstance (Object[] args) throws InstantiationException, IllegalAccessException, - IllegalArgumentException, InvocationTargetException - { - return null; - } + IllegalArgumentException, InvocationTargetException; public String toString () { + if (parameter_types == null) + getType (); StringBuffer b = new StringBuffer (); - b.append(Modifier.toString(modifiers)); + b.append(Modifier.toString(getModifiers())); b.append(" "); b.append(getName()); b.append("("); @@ -88,19 +87,19 @@ public final class Constructor extends AccessibleObject implements Member return b.toString(); } - // Can't create these. FIXME. + // Can't create these. private Constructor () { } // Declaring class. - private Class decl_class; + private Class declaringClass; + // Exception types. private Class[] exception_types; - // Modifiers. - private int modifiers; // Parameter types. private Class[] parameter_types; - // Index of this method in declaring class' method table. - private int index; + + // Offset in bytes from the start of declaringClass's methods array. + private int offset; } diff --git a/libjava/java/lang/reflect/Method.java b/libjava/java/lang/reflect/Method.java index e0571f8a1866..dd87816a40db 100644 --- a/libjava/java/lang/reflect/Method.java +++ b/libjava/java/lang/reflect/Method.java @@ -10,6 +10,8 @@ details. */ package java.lang.reflect; +import gnu.gcj.RawData; + /** * @author Tom Tromey * @date December 12, 1998 @@ -17,7 +19,7 @@ package java.lang.reflect; /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 * "The Java Language Specification", ISBN 0-201-63451-1 * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. - * Status: Incomplete: invoke() needs to be finished. + * Status: Complete, but not correct: access checks aren't done. */ public final class Method extends AccessibleObject implements Member @@ -66,6 +68,30 @@ public final class Method extends AccessibleObject implements Member return name.hashCode() + declaringClass.getName().hashCode(); } + // This is used to perform an actual method call via ffi. + private static final native void hack_call (RawData cif, + RawData method, + RawData ret_value, + RawData values); + + // Perform an ffi call while capturing exceptions. We have to do + // this because we can't catch Java exceptions from C++. + static final Throwable hack_trampoline (RawData cif, + RawData method, + RawData ret_value, + RawData values) + { + try + { + hack_call (cif, method, ret_value, values); + } + catch (Throwable x) + { + return x; + } + return null; + } + public native Object invoke (Object obj, Object[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException; diff --git a/libjava/java/lang/reflect/natConstructor.cc b/libjava/java/lang/reflect/natConstructor.cc new file mode 100644 index 000000000000..1197e68c90a1 --- /dev/null +++ b/libjava/java/lang/reflect/natConstructor.cc @@ -0,0 +1,53 @@ +// natConstructor.cc - Native code for Constructor class. + +/* Copyright (C) 1999, 2000 Cygnus Solutions + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +jint +java::lang::reflect::Constructor::getModifiers () +{ + return _Jv_FromReflectedConstructor (this)->accflags; +} + +void +java::lang::reflect::Constructor::getType () +{ + _Jv_GetTypesFromSignature (_Jv_FromReflectedConstructor (this), + declaringClass, + ¶meter_types, + NULL); +} + +jobject +java::lang::reflect::Constructor::newInstance (jobjectArray args) +{ + if (parameter_types == NULL) + getType (); + + using namespace java::lang::reflect; + if (Modifier::isAbstract (declaringClass->getModifiers())) + JvThrow (new InstantiationException); + + jmethodID meth = _Jv_FromReflectedConstructor (this); + // In the constructor case the return type is the type of the + // constructor. + return _Jv_CallNonvirtualMethodA (NULL, declaringClass, meth, true, + parameter_types, args); +} diff --git a/libjava/java/lang/reflect/natMethod.cc b/libjava/java/lang/reflect/natMethod.cc index 0130ac4243f7..5635b9fe33d1 100644 --- a/libjava/java/lang/reflect/natMethod.cc +++ b/libjava/java/lang/reflect/natMethod.cc @@ -1,6 +1,6 @@ // natMethod.cc - Native code for Method class. -/* Copyright (C) 1998, 1999 Cygnus Solutions +/* Copyright (C) 1998, 1999, 2000 Cygnus Solutions This file is part of libgcj. @@ -8,14 +8,13 @@ This software is copyrighted work licensed under the terms of the Libgcj License. Please consult the file "LIBGCJ_LICENSE" for details. */ -// This is about 90% done. Search for FIXME to see what remains. - #include #include #include #include +#include #include #include @@ -32,14 +31,15 @@ details. */ #include #include #include +#include +#define ObjectClass _CL_Q34java4lang6Object +extern java::lang::Class ObjectClass; #define ClassClass _CL_Q34java4lang5Class extern java::lang::Class ClassClass; #include -#if 0 - #include #define VoidClass _CL_Q34java4lang4Void @@ -145,147 +145,46 @@ get_ffi_type (jclass klass) return r; } -// FIXME: the body of this method should be a separate function so -// that Constructor can use it too. -jobject -java::lang::reflect::Method::invoke (jobject obj, - jobjectArray args) +// Actually perform an FFI call. +void +java::lang::reflect::Method::hack_call (gnu::gcj::RawData *rcif, + gnu::gcj::RawData *rmethod, + gnu::gcj::RawData *rret_value, + gnu::gcj::RawData *rvalues) { - // FIXME: we need to be a friend of Class here. - _Jv_Method *meth = decl_class->methods[index]; - if (! java::lang::reflect::Modifier::isStatic(modifiers)) + ffi_cif *cif = (ffi_cif *) rcif; + void (*method) (...) = (void (*) (...)) rmethod; + void *ret_value = (void *) rret_value; + void **values = (void **) rvalues; + + ffi_call (cif, method, ret_value, values); +} + +jobject +java::lang::reflect::Method::invoke (jobject obj, jobjectArray args) +{ + if (parameter_types == NULL) + getType (); + + jmethodID meth = _Jv_FromReflectedMethod (this); + if (! java::lang::reflect::Modifier::isStatic(meth->accflags)) { jclass k = obj ? obj->getClass() : NULL; - if (! obj || ! decl_class->isAssignableFrom(k)) + if (! obj) JvThrow (new java::lang::NullPointerException); + if (! declaringClass->isAssignableFrom(k)) + JvThrow (new java::lang::IllegalArgumentException); // FIXME: access checks. - meth = _Jv_LookupMethod (k, meth->name, meth->signature); + + // Find the possibly overloaded method based on the runtime type + // of the object. + meth = _Jv_LookupDeclaredMethod (k, meth->name, meth->signature); } - // FIXME: access checks. - - if (parameter_types->length != args->length) - JvThrow (new java::lang::IllegalArgumentException); - - ffi_type *rtype = get_ffi_type (return_type); - ffi_type **argtypes = (ffi_type **) alloca (parameter_types->length - * sizeof (ffi_type *)); - - jobject *paramelts = elements (parameter_types); - jobject *argelts = elements (args); - - int size = 0; - for (int i = 0; i < parameter_types->length; ++i) - { - jclass k = argelts[i] ? argelts[i]->getClass() : NULL; - argtypes[i] = get_ffi_type (k); - if (paramelts[i]->isPrimitive()) - { - if (! argelts[i] - || ! k->isPrimitive () - || ! can_widen (k, paramelts[i])) - JvThrow (new java::lang::IllegalArgumentException); - size += paramelts[i]->size(); - } - else - { - if (argelts[i] && ! paramelts[i]->isAssignableFrom (k)) - JvThrow (new java::lang::IllegalArgumentException); - size += sizeof (jobject); - } - } - - ffi_cif cif; - if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, parameter_types->length, - rtype, argtypes) != FFI_OK) - { - // FIXME: throw some kind of VirtualMachineError here. - } - - char *values = (char *) alloca (size); - char *p = values; - -#define COPY(Where, What, Type) \ - do { \ - Type val = (What); \ - memcpy ((Where), &val, sizeof (Type)); \ - Where += sizeof (Type); \ - } while (0) - - for (int i = 0; i < parameter_types->length; ++i) - { - java::lang::Number *num = (java::lang::Number *) paramelts[i]; - if (paramelts[i] == JvPrimClass (byte)) - COPY (p, num->byteValue(), jbyte); - else if (paramelts[i] == JvPrimClass (short)) - COPY (p, num->shortValue(), jshort); - else if (paramelts[i] == JvPrimClass (int)) - COPY (p, num->intValue(), jint); - else if (paramelts[i] == JvPrimClass (long)) - COPY (p, num->longValue(), jlong); - else if (paramelts[i] == JvPrimClass (float)) - COPY (p, num->floatValue(), jfloat); - else if (paramelts[i] == JvPrimClass (double)) - COPY (p, num->doubleValue(), jdouble); - else if (paramelts[i] == JvPrimClass (boolean)) - COPY (p, ((java::lang::Boolean *) argelts[i])->booleanValue(), jboolean); - else if (paramelts[i] == JvPrimClass (char)) - COPY (p, ((java::lang::Character *) argelts[i])->charValue(), jchar); - else - { - JvAssert (! paramelts[i]->isPrimitive()); - COPY (p, argelts[i], jobject); - } - } - - // FIXME: exception handling. - java::lang::Throwable *ex; - jdouble ret_value; // Largest possible value. Hopefully - // it is aligned! - ex = TRAMP_CALL (ffi_call (&cif, meth->ncode, &ret_value, (void *) values)); - - if (ex) - JvThrow (new InvocationTargetException (ex)); - - jobject r; -#define VAL(Wrapper, Type) (new Wrapper (* (Type *) &ret_value)) - if (return_type == JvPrimClass (byte)) - r = VAL (java::lang::Byte, jbyte); - else if (return_type == JvPrimClass (short)) - r = VAL (java::lang::Short, jshort); - else if (return_type == JvPrimClass (int)) - r = VAL (java::lang::Integer, jint); - else if (return_type == JvPrimClass (long)) - r = VAL (java::lang::Long, jlong); - else if (return_type == JvPrimClass (float)) - r = VAL (java::lang::Float, jfloat); - else if (return_type == JvPrimClass (double)) - r = VAL (java::lang::Double, jdouble); - else if (return_type == JvPrimClass (boolean)) - r = VAL (java::lang::Boolean, jboolean); - else if (return_type == JvPrimClass (char)) - r = VAL (java::lang::Character, jchar); - else if (return_type == JvPrimClass (void)) - r = NULL; - else - { - JvAssert (! return_type->isPrimitive()); - r = VAL (java::lang::Object, jobject); - } - - return r; + return _Jv_CallNonvirtualMethodA (obj, return_type, meth, false, + parameter_types, args); } -#else /* 0 */ - -jobject -java::lang::reflect::Method::invoke (jobject, jobjectArray) -{ - JvFail ("not enabled yet"); -} - -#endif /* 0 */ - jint java::lang::reflect::Method::getModifiers () { @@ -305,7 +204,20 @@ java::lang::reflect::Method::getName () void java::lang::reflect::Method::getType () { - _Jv_Utf8Const* sig = _Jv_FromReflectedMethod (this)->signature; + _Jv_GetTypesFromSignature (_Jv_FromReflectedMethod (this), + declaringClass, + ¶meter_types, + &return_type); +} + +void +_Jv_GetTypesFromSignature (jmethodID method, + jclass declaringClass, + JArray **arg_types_out, + jclass *return_type_out) +{ + + _Jv_Utf8Const* sig = method->signature; java::lang::ClassLoader *loader = declaringClass->getClassLoader(); char *ptr = sig->data; int numArgs = 0; @@ -355,7 +267,7 @@ java::lang::reflect::Method::getType () default: return; case ')': - argPtr = &return_type; + argPtr = return_type_out; continue; case '(': continue; @@ -381,7 +293,187 @@ java::lang::reflect::Method::getType () // FIXME: 2'nd argument should be "current loader" while (--num_arrays >= 0) type = _Jv_FindArrayClass (type, 0); - *argPtr++ = type; + // ARGPTR can be NULL if we are processing the return value of a + // call from Constructor. + if (argPtr) + *argPtr++ = type; } - parameter_types = args; + *arg_types_out = args; +} + +// This is a very rough analog of the JNI CallNonvirtualMethodA +// functions. It handles both Methods and Constructors, and it can +// handle any return type. In the Constructor case, the `obj' +// argument is unused and should be NULL; also, the `return_type' is +// the class that the constructor will construct. +jobject +_Jv_CallNonvirtualMethodA (jobject obj, + jclass return_type, + jmethodID meth, + jboolean is_constructor, + JArray *parameter_types, + jobjectArray args) +{ + JvAssert (! is_constructor || ! obj); + JvAssert (! is_constructor || ! return_type); + + // FIXME: access checks. + + if (parameter_types->length != args->length) + JvThrow (new java::lang::IllegalArgumentException); + + // See whether call needs an object as the first argument. A + // constructor does need a `this' argument, but it is one we create. + jboolean needs_this = false; + if (is_constructor + || ! java::lang::reflect::Modifier::isStatic(meth->accflags)) + needs_this = true; + + int param_count = parameter_types->length; + if (needs_this) + ++param_count; + + ffi_type *rtype = get_ffi_type (return_type); + ffi_type **argtypes = (ffi_type **) alloca (param_count + * sizeof (ffi_type *)); + + jclass *paramelts = elements (parameter_types); + jobject *argelts = elements (args); + + // FIXME: at some point the compiler is going to add extra arguments + // to some functions. In particular we are going to do this for + // handling access checks in reflection. We must add these hidden + // arguments here. + + // Special case for the `this' argument of a constructor. Note that + // the JDK 1.2 docs specify that the new object must be allocated + // before argument conversions are done. + if (is_constructor) + { + // FIXME: must special-case String, arrays, maybe others here. + obj = JvAllocObject (return_type); + } + + int i = 0; + int size = 0; + if (needs_this) + { + // The `NULL' type is `Object'. + argtypes[i++] = get_ffi_type (NULL); + size += sizeof (jobject); + } + + for (; i < param_count; ++i) + { + jclass k = argelts[i] ? argelts[i]->getClass() : NULL; + argtypes[i] = get_ffi_type (k); + if (paramelts[i]->isPrimitive()) + { + if (! argelts[i] + || ! k->isPrimitive () + || ! can_widen (k, paramelts[i])) + JvThrow (new java::lang::IllegalArgumentException); + size += paramelts[i]->size(); + } + else + { + if (argelts[i] && ! paramelts[i]->isAssignableFrom (k)) + JvThrow (new java::lang::IllegalArgumentException); + size += sizeof (jobject); + } + } + + ffi_cif cif; + if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, param_count, + rtype, argtypes) != FFI_OK) + { + // FIXME: throw some kind of VirtualMachineError here. + } + + char *values = (char *) alloca (size); + char *p = values; + +#define COPY(Where, What, Type) \ + do { \ + Type val = (What); \ + memcpy ((Where), &val, sizeof (Type)); \ + Where += sizeof (Type); \ + } while (0) + + i = 0; + if (needs_this) + { + COPY (p, obj, jobject); + ++i; + } + + for (; i < param_count; ++i) + { + java::lang::Number *num = (java::lang::Number *) paramelts[i]; + if (paramelts[i] == JvPrimClass (byte)) + COPY (p, num->byteValue(), jbyte); + else if (paramelts[i] == JvPrimClass (short)) + COPY (p, num->shortValue(), jshort); + else if (paramelts[i] == JvPrimClass (int)) + COPY (p, num->intValue(), jint); + else if (paramelts[i] == JvPrimClass (long)) + COPY (p, num->longValue(), jlong); + else if (paramelts[i] == JvPrimClass (float)) + COPY (p, num->floatValue(), jfloat); + else if (paramelts[i] == JvPrimClass (double)) + COPY (p, num->doubleValue(), jdouble); + else if (paramelts[i] == JvPrimClass (boolean)) + COPY (p, ((java::lang::Boolean *) argelts[i])->booleanValue(), + jboolean); + else if (paramelts[i] == JvPrimClass (char)) + COPY (p, ((java::lang::Character *) argelts[i])->charValue(), jchar); + else + { + JvAssert (! paramelts[i]->isPrimitive()); + COPY (p, argelts[i], jobject); + } + } + + // FIXME: initialize class here. + + // Largest possible value. Hopefully it is aligned! + jdouble ret_value; + java::lang::Throwable *ex; + using namespace java::lang; + using namespace java::lang::reflect; + ex = Method::hack_trampoline ((gnu::gcj::RawData *) &cif, + (gnu::gcj::RawData *) meth->ncode, + (gnu::gcj::RawData *) &ret_value, + (gnu::gcj::RawData *) values); + + if (ex) + JvThrow (new InvocationTargetException (ex)); + + jobject r; +#define VAL(Wrapper, Type) (new Wrapper (* (Type *) &ret_value)) + if (return_type == JvPrimClass (byte)) + r = VAL (java::lang::Byte, jbyte); + else if (return_type == JvPrimClass (short)) + r = VAL (java::lang::Short, jshort); + else if (return_type == JvPrimClass (int)) + r = VAL (java::lang::Integer, jint); + else if (return_type == JvPrimClass (long)) + r = VAL (java::lang::Long, jlong); + else if (return_type == JvPrimClass (float)) + r = VAL (java::lang::Float, jfloat); + else if (return_type == JvPrimClass (double)) + r = VAL (java::lang::Double, jdouble); + else if (return_type == JvPrimClass (boolean)) + r = VAL (java::lang::Boolean, jboolean); + else if (return_type == JvPrimClass (char)) + r = VAL (java::lang::Character, jchar); + else if (return_type == JvPrimClass (void)) + r = NULL; + else + { + JvAssert (return_type == NULL || ! return_type->isPrimitive()); + r = * (Object **) &ret_value; + } + + return r; } diff --git a/libjava/prims.cc b/libjava/prims.cc index 7f73047aa9d1..2a413ae34036 100644 --- a/libjava/prims.cc +++ b/libjava/prims.cc @@ -16,8 +16,6 @@ details. */ #include #include -#pragma implementation "gcj/array.h" - #include #include #include @@ -143,6 +141,26 @@ _Jv_equal (Utf8Const* a, jstring str, jint hash) return true; } +/* Like _Jv_equal, but stop after N characters. */ +jboolean +_Jv_equaln (Utf8Const *a, jstring str, jint n) +{ + jint len = str->length(); + jint i = 0; + jchar *sptr = _Jv_GetStringChars (str); + register unsigned char* ptr = (unsigned char*) a->data; + register unsigned char* limit = ptr + a->length; + for (; n-- > 0; i++, sptr++) + { + int ch = UTF8_GET (ptr, limit); + if (i == len) + return ch < 0; + if (ch != *sptr) + return false; + } + return true; +} + /* Count the number of Unicode chars encoded in a given Ut8 string. */ int _Jv_strLengthUtf8(char* str, int len) diff --git a/libjava/resolve.cc b/libjava/resolve.cc index 00a340d74547..e39cb9346a0a 100644 --- a/libjava/resolve.cc +++ b/libjava/resolve.cc @@ -321,21 +321,6 @@ _Jv_ResolveField (_Jv_Field *field, java::lang::ClassLoader *loader) } } -_Jv_Method* -_Jv_LookupDeclaredMethod (jclass klass, _Jv_Utf8Const *name, - _Jv_Utf8Const *signature) -{ - for (; klass; klass = klass->getSuperclass()) - { - _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature); - - if (meth) - return meth; - } - - return NULL; -} - /** FIXME: this is a terribly inefficient algorithm! It would improve things if compiled classes to know vtable offset, and _Jv_Method had a field for this. diff --git a/libjava/testsuite/Makefile.in b/libjava/testsuite/Makefile.in index 276c84cf5889..25d7a3de50e9 100644 --- a/libjava/testsuite/Makefile.in +++ b/libjava/testsuite/Makefile.in @@ -76,12 +76,14 @@ DLLTOOL = @DLLTOOL@ EH_COMMON_INCLUDE = @EH_COMMON_INCLUDE@ EXCEPTIONSPEC = @EXCEPTIONSPEC@ EXEEXT = @EXEEXT@ +FORCELIBGCCSPEC = @FORCELIBGCCSPEC@ GCDEPS = @GCDEPS@ GCINCS = @GCINCS@ GCLIBS = @GCLIBS@ GCOBJS = @GCOBJS@ GCSPEC = @GCSPEC@ LD = @LD@ +LIBDATASTARTSPEC = @LIBDATASTARTSPEC@ LIBGCJ_CFLAGS = @LIBGCJ_CFLAGS@ LIBGCJ_CXXFLAGS = @LIBGCJ_CXXFLAGS@ LIBGCJ_JAVAFLAGS = @LIBGCJ_JAVAFLAGS@ @@ -90,7 +92,6 @@ LN_S = @LN_S@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ NM = @NM@ -OBJDUMP = @OBJDUMP@ PACKAGE = @PACKAGE@ PERL = @PERL@ RANLIB = @RANLIB@ @@ -100,6 +101,7 @@ THREADINCS = @THREADINCS@ THREADLIBS = @THREADLIBS@ THREADOBJS = @THREADOBJS@ THREADSPEC = @THREADSPEC@ +USE_SYMBOL_UNDERSCORE = @USE_SYMBOL_UNDERSCORE@ VERSION = @VERSION@ ZDEPS = @ZDEPS@ ZINCS = @ZINCS@