diff options
author | Anthony Green <green@gcc.gnu.org> | 1999-08-08 14:06:23 +0000 |
---|---|---|
committer | Anthony Green <green@gcc.gnu.org> | 1999-08-08 14:06:23 +0000 |
commit | 58eb6e7cef1cea515f8da18d24341a4aa53ccb70 (patch) | |
tree | 277498eeeff558237a9cd88b0ea8b3788b31d645 /libjava | |
parent | 63e5e3e0dbb7207e95c0437499b980a304665589 (diff) | |
download | gcc-58eb6e7cef1cea515f8da18d24341a4aa53ccb70.zip gcc-58eb6e7cef1cea515f8da18d24341a4aa53ccb70.tar.gz gcc-58eb6e7cef1cea515f8da18d24341a4aa53ccb70.tar.bz2 |
[multiple changes]
1999-08-09 Anthony Green <green@cygnus.com>
* gij.cc: New file.
* include/config.h.in: Rebuilt.
* acconfig.h: Add INTERPRETER.
* configure: Rebuilt.
* Makefile.in: Rebuilt.
* Makefile.am (libffi_files): Identify the libffi object files for
inclusion in libgcj.
(LIBFFIINCS): Define.
* interpret.cc (gnu::gcj::runtime::MethodInvocation::continue1):
Dummy definition for configurations without an interpreter.
* java/net/natPlainSocketImpl.cc (getOption): Disamiguate call to
java::lang::Boolean constructor.
* include/java-interp.h: Always include java-cpool.h.
* java/lang/natClassLoader.cc (getVMClassLoader0): Always return 0
when INTERPRETER not defined.
* java/lang/Class.h (finalize): Define.
* gnu/gcj/util/path/DirectoryPathEntry.java (getURL): Catch
IOException from File.getCanonicalPath.
(getStream): Likewise.
* NEWS: More news.
* THANKS: More thanks.
1999-08-09 Kresten Krab Thorup <krab@gnu.org>
* resolve.cc (get_ffi_type_from_signature): Generate uint16 for
jchar type.
(_Jv_PrepareClass): Allow non-abstract classes to
have abstract subclasses.
(_Jv_ResolvePoolEntry): Revert subclass check for protected
fields and methods.
* interpret.cc (continue1/perform_invoke): Don't sign extend
uint16 return val.
(continue1/lshl,lshr): Push long, not int.
(continue1/ulshr): Use UINT64, not long long.
* defineclass.cc (handleFieldsEnd): Handle case when all fields
are static.
* java/lang/natClass.cc (forName): Add call to _Jv_InitClass.
* java/lang/FirstThread.java (run): Add top-level exception
handler.
(run0): Renamed from run.
1999-08-08 Kresten Krab Thorup <krab@gnu.org>
* configure.in (--with-interpreter): Added.
* include/config.h.in (INTERPRETER): Added.
* java/lang/ClassLoader.java: File replaced.
* java/lang/VMClassLoader.java: New file.
* java/lang/natClassLoader.cc: New file.
* gnu/gcj/runtime/MethodInvocation.java: New file.
* gnu/gcj/util/path/SearchPath.java: New file.
* gnu/gcj/util/path/PathEntry.java: New file.
* gnu/gcj/util/path/DirectoryPathEntry.java: New file.
* gnu/gcj/util/path/ZipPathEntry.java: New file.
* gnu/gcj/util/path/URLPathEntry.java: New file.
* gnu/gcj/util/path/CacheEntry.java: New file.
* include/java-interp.h: New file.
* include/java-cpool.h: New file.
* include/java-insns.h: New file.
* defineclass.cc: New file.
* interpret.cc: New file.
* resolve.cc: New file.
* java/lang/natClass.cc (loaded_classes, _Jv_RegisterClass,
_Jv_RegisterClasses, _Jv_FindClassInCache, _Jv_FindClass,
_Jv_NewClass, _Jv_FindArrayClass): Moved to natClassLoader.cc.
(finalize): New.
(STATE_NOTHING, STATE_RESOLVED, STATE_IN_PROGRESS, STATE_DONE,
STATE_ERROR): Moved to java/lang/Class.h and renamed with JV_
prefix.
(initializeClass): Use new JV_ prefixed names. Also, call
ClassLoader::resolveClass instead of _Jv_ResolveClass.
* java/lang/Class.h (JV_STATE_PRELOADING, JV_STATE_LOADING,
JV_STATE_LOADED, JV_STATE_COMPILED, JV_STATE_PREPARED,
JV_STATE_LINKED): New.
(_Jv_WaitForState, _Jv_RegisterInitiatingLoader,
_Jv_UnregisterClass, _Jv_InternClassStrings): New friends.
(_Jv_IsInterpretedClass, _Jv_InitField, _Jv_LookupDeclaredMethod,
_Jv_DetermineVTableIndex, _Jv_ResolvePoolEntry, _Jv_PrepareClass,
_Jv_ClassReader, _Jv_InterpClass, _Jv_InterpMethod,
_Jv_InterpMethodInvocation): New friends for interpreter.
(finalize): New.
(CONSTANT_Class, CONSTANT_String, etc.): Moved to
include/java-cpool.h and renamed with JV_ prefix.
* include/jvm.h (_Jv_makeUtf8Const, _Jv_makeUtf8TypeConst): New
decls.
(_Jv_UnregisterClass): New decl.
* java/lang/natClassLoader.cc (_Jv_FindArrayClass): Added
class loader argument.
(_Jv_FindClass): Use class loader.
* prims.cc (_Jv_makeUtf8Const): New function.
(_Jv_NewObjectArray): Change use of _Jv_FindArrayClass.
(_Jv_NewPrimArray): Ditto.
(_Jv_FindClassFromSignature): Ditto.
* java/lang/reflect/natArray.cc (newInstance): Ditto.
* java/lang/reflect/natMethod.cc (getType): Ditto.
* include/java-field.h (_Jv_Field::isRef): Make robust for
non-resolved contexts.
* boehm.cc (_Jv_MarkObj): Mark interpreter-related fields.
Also, don't mark class->next field.
* java/lang/VirtualMachineError.java: Added FIXME note.
* configure.in (INTERPSPEC): New spec.
* libgcj.spec.in: Added INTERPSPEC.
* Makefile.am: Added gcjh friends for java/lang/VMClassLoader and
gnu/gcj/runtime/MethodInvocation.
(libgcj_la_SOURCES): Added resolve.cc defineclass.cc interpret.cc.
(ordinary_java_source_files): Added above mentioned java classes.
* configure: Rebuilt.
* Makefile.in: Rebuilt.
From-SVN: r28597
Diffstat (limited to 'libjava')
42 files changed, 8335 insertions, 592 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 1954795..24051fc 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,132 @@ +1999-08-09 Anthony Green <green@cygnus.com> + + * gij.cc: New file. + + * include/config.h.in: Rebuilt. + * acconfig.h: Add INTERPRETER. + + * Makefile.in: Rebuilt. + * Makefile.am (libffi_files): Identify the libffi object files for + inclusion in libgcj. + (LIBFFIINCS): Define. + + * interpret.cc (gnu::gcj::runtime::MethodInvocation::continue1): + Dummy definition for configurations without an interpreter. + + * java/net/natPlainSocketImpl.cc (getOption): Disamiguate call to + java::lang::Boolean constructor. + + * include/java-interp.h: Always include java-cpool.h. + + * java/lang/natClassLoader.cc (getVMClassLoader0): Always return 0 + when INTERPRETER not defined. + + * java/lang/Class.h (finalize): Define. + + * gnu/gcj/util/path/DirectoryPathEntry.java (getURL): Catch + IOException from File.getCanonicalPath. + (getStream): Likewise. + + * NEWS: More news. + * THANKS: More thanks. + +1999-08-09 Kresten Krab Thorup <krab@gnu.org> + + * resolve.cc (get_ffi_type_from_signature): Generate uint16 for + jchar type. + (_Jv_PrepareClass): Allow non-abstract classes to + have abstract subclasses. + (_Jv_ResolvePoolEntry): Revert subclass check for protected + fields and methods. + * interpret.cc (continue1/perform_invoke): Don't sign extend + uint16 return val. + (continue1/lshl,lshr): Push long, not int. + (continue1/ulshr): Use UINT64, not long long. + * defineclass.cc (handleFieldsEnd): Handle case when all fields + are static. + * java/lang/natClass.cc (forName): Add call to _Jv_InitClass. + * java/lang/FirstThread.java (run): Add top-level exception + handler. + (run0): Renamed from run. + +1999-08-08 Kresten Krab Thorup <krab@gnu.org> + + * configure.in (--with-interpreter): Added. + * include/config.h.in (INTERPRETER): Added. + + * java/lang/ClassLoader.java: File replaced. + * java/lang/VMClassLoader.java: New file. + * java/lang/natClassLoader.cc: New file. + * gnu/gcj/runtime/MethodInvocation.java: New file. + * gnu/gcj/util/path/SearchPath.java: New file. + * gnu/gcj/util/path/PathEntry.java: New file. + * gnu/gcj/util/path/DirectoryPathEntry.java: New file. + * gnu/gcj/util/path/ZipPathEntry.java: New file. + * gnu/gcj/util/path/URLPathEntry.java: New file. + * gnu/gcj/util/path/CacheEntry.java: New file. + * include/java-interp.h: New file. + * include/java-cpool.h: New file. + * include/java-insns.h: New file. + * defineclass.cc: New file. + * interpret.cc: New file. + * resolve.cc: New file. + + * java/lang/natClass.cc (loaded_classes, _Jv_RegisterClass, + _Jv_RegisterClasses, _Jv_FindClassInCache, _Jv_FindClass, + _Jv_NewClass, _Jv_FindArrayClass): Moved to natClassLoader.cc. + (finalize): New. + (STATE_NOTHING, STATE_RESOLVED, STATE_IN_PROGRESS, STATE_DONE, + STATE_ERROR): Moved to java/lang/Class.h and renamed with JV_ + prefix. + (initializeClass): Use new JV_ prefixed names. Also, call + ClassLoader::resolveClass instead of _Jv_ResolveClass. + + * java/lang/Class.h (JV_STATE_PRELOADING, JV_STATE_LOADING, + JV_STATE_LOADED, JV_STATE_COMPILED, JV_STATE_PREPARED, + JV_STATE_LINKED): New. + (_Jv_WaitForState, _Jv_RegisterInitiatingLoader, + _Jv_UnregisterClass, _Jv_InternClassStrings): New friends. + (_Jv_IsInterpretedClass, _Jv_InitField, _Jv_LookupDeclaredMethod, + _Jv_DetermineVTableIndex, _Jv_ResolvePoolEntry, _Jv_PrepareClass, + _Jv_ClassReader, _Jv_InterpClass, _Jv_InterpMethod, + _Jv_InterpMethodInvocation): New friends for interpreter. + (finalize): New. + (CONSTANT_Class, CONSTANT_String, etc.): Moved to + include/java-cpool.h and renamed with JV_ prefix. + + * include/jvm.h (_Jv_makeUtf8Const, _Jv_makeUtf8TypeConst): New + decls. + (_Jv_UnregisterClass): New decl. + + * java/lang/natClassLoader.cc (_Jv_FindArrayClass): Added + class loader argument. + (_Jv_FindClass): Use class loader. + + * prims.cc (_Jv_makeUtf8Const): New function. + (_Jv_NewObjectArray): Change use of _Jv_FindArrayClass. + (_Jv_NewPrimArray): Ditto. + (_Jv_FindClassFromSignature): Ditto. + * java/lang/reflect/natArray.cc (newInstance): Ditto. + * java/lang/reflect/natMethod.cc (getType): Ditto. + + * include/java-field.h (_Jv_Field::isRef): Make robust for + non-resolved contexts. + + * boehm.cc (_Jv_MarkObj): Mark interpreter-related fields. + Also, don't mark class->next field. + + * java/lang/VirtualMachineError.java: Added FIXME note. + + * configure.in (INTERPSPEC): New spec. + * libgcj.spec.in: Added INTERPSPEC. + * Makefile.am: Added gcjh friends for java/lang/VMClassLoader and + gnu/gcj/runtime/MethodInvocation. + (libgcj_la_SOURCES): Added resolve.cc defineclass.cc interpret.cc. + (ordinary_java_source_files): Added above mentioned java classes. + + * configure: Rebuilt. + * Makefile.in: Rebuilt. + 1999-08-06 Tom Tromey <tromey@cygnus.com> * configure: Rebuilt. diff --git a/libjava/Makefile.am b/libjava/Makefile.am index c9cc9b9..83217c8 100644 --- a/libjava/Makefile.am +++ b/libjava/Makefile.am @@ -27,7 +27,7 @@ data_DATA = libgcj.zip ## For now, only on native systems. if NATIVE -bin_PROGRAMS = jv-convert +bin_PROGRAMS = jv-convert gij endif ## ################################################################ @@ -77,8 +77,10 @@ endif JCFLAGS = -g JC1FLAGS = -g @LIBGCJ_JAVAFLAGS@ +LIBFFIINCS = -I$(top_srcdir)/../libffi/include -I../libffi/include + INCLUDES = -Iinclude -I$(top_srcdir)/include $(GCINCS) $(THREADINCS) \ - $(EH_COMMON_INCLUDE) $(ZINCS) + $(EH_COMMON_INCLUDE) $(ZINCS) $(LIBFFIINCS) DIVIDESPEC = @DIVIDESPEC@ @@ -97,13 +99,17 @@ c_files = $(c_source_files:.c=.lo) javao_files = $(java_source_files:.java=.lo) \ $(built_java_source_files:.java=.lo) -libgcj_la_SOURCES = prims.cc jni.cc exception.cc +## Extract the libffi object file names. +libffi_files = `$(AR) t ../libffi/.libs/libffi.a 2>/dev/null | sed 's/\.o/\.lo/g' | sed 's/^/..\/libffi\//g'` + +libgcj_la_SOURCES = prims.cc jni.cc exception.cc \ + resolve.cc defineclass.cc interpret.cc EXTRA_libgcj_la_SOURCES = boehm.cc nogc.cc posix-threads.cc no-threads.cc \ $(c_source_files) $(java_source_files) $(built_java_source_files) libgcj_la_DEPENDENCIES = libgcj.zip $(javao_files) $(nat_files) \ $(c_files) $(GCOBJS) $(THREADOBJS) libgcj_la_LIBADD = $(javao_files) $(nat_files) $(c_files) $(GCOBJS) \ - $(THREADOBJS) + $(THREADOBJS) $(libffi_files) libgcj_la_LDFLAGS = -rpath $(toolexeclibdir) \ ## The mysterious backslash is consumed by make. -version-info `grep -v '^\#' $(srcdir)/libtool-version` @@ -230,6 +236,16 @@ java/lang/reflect/Method.h: java/lang/reflect/Method.class libgcj.zip -friend 'java::lang::Class;' \ $(basename $<) +java/lang/VMClassLoader.h: java/lang/VMClassLoader.class libgcj.zip + $(GCJH) -classpath $(top_builddir) \ + -friend 'java::lang::ClassLoader;' \ + $(basename $<) + +gnu/gcj/runtime/MethodInvocation.h: gnu/gcj/runtime/MethodInvocation.class libgcj.zip + $(GCJH) -classpath $(top_builddir) \ + -friend 'class _Jv_InterpMethod;' \ + $(basename $<) + ## ################################################################ @@ -299,6 +315,26 @@ jv_convert_LDADD = $(convert_source_files:.java=.lo) libgcj.la \ jv_convert_DEPENDENCIES = $(convert_source_files:.java=.lo) \ $(GCDEPS) $(THREADDEPS) $(ZDEPS) libgcj.la libgcj.spec +gij_SOURCES = +EXTRA_gij_SOURCES = gij.cc +## We need -nodefaultlibs because we want to avoid gcj's `-lgcj'. We +## need this because we are explicitly using libtool to link using the +## `.la' file. +gij_LDFLAGS = -rpath $(toolexeclibdir) +gij_LINK = $(LIBTOOL) --mode=link $(GCJ) $(JC1FLAGS) $(LDFLAGS) \ + -o gij +## We explicitly link in the libraries we need. This way we don't +## need -nodefaultlibs, so we can still rely on gcj picking up the +## system libraries we need (via the specs file). +## We need the -L so that gcj can find libgcj with `-lgcj'. +## FIXME: should be _libs on some systems. +gij_LDADD = gij.lo libgcj.la \ + $(GCLIBS) $(THREADLIBS) $(ZLIBS) -L$(here)/.libs +## Depend on the spec file to make sure it is up to date before +## linking this program. +gij_DEPENDENCIES = gij.lo \ + $(GCDEPS) $(THREADDEPS) $(ZDEPS) libgcj.la libgcj.spec + # The Unicode consortium does not permit re-distributing the file JIS0201.TXT. # You can get it from ftp://ftp.unicode.org/Public/MAPPINGS/EASTASIA/JIS/. @@ -444,6 +480,13 @@ built_java_source_files = java/lang/ConcreteProcess.java ## convert_source_files. If the .java file has a hand-maintained ## header, please list it in special_java_source_files. ordinary_java_source_files = $(convert_source_files) \ +gnu/gcj/runtime/MethodInvocation.java \ +gnu/gcj/util/path/SearchPath.java \ +gnu/gcj/util/path/PathEntry.java \ +gnu/gcj/util/path/DirectoryPathEntry.java \ +gnu/gcj/util/path/ZipPathEntry.java \ +gnu/gcj/util/path/URLPathEntry.java \ +gnu/gcj/util/path/CacheEntry.java \ gnu/gcj/text/BaseBreakIterator.java \ gnu/gcj/text/CharacterBreakIterator.java \ gnu/gcj/text/LineBreakIterator.java \ @@ -522,6 +565,7 @@ java/lang/ClassCastException.java \ java/lang/ClassCircularityError.java \ java/lang/ClassFormatError.java \ java/lang/ClassLoader.java \ +java/lang/VMClassLoader.java \ java/lang/ClassNotFoundException.java \ java/lang/CloneNotSupportedException.java \ java/lang/Cloneable.java \ @@ -719,6 +763,7 @@ java/io/natFile.cc \ java/io/natFileDescriptor.cc \ java/lang/natCharacter.cc \ java/lang/natClass.cc \ +java/lang/natClassLoader.cc \ java/lang/natConcreteProcess.cc \ java/lang/natDouble.cc \ java/lang/natFirstThread.cc \ diff --git a/libjava/Makefile.in b/libjava/Makefile.in index 94e4189..c03c3223 100644 --- a/libjava/Makefile.in +++ b/libjava/Makefile.in @@ -78,6 +78,7 @@ GCINCS = @GCINCS@ GCLIBS = @GCLIBS@ GCOBJS = @GCOBJS@ GCSPEC = @GCSPEC@ +INTERPSPEC = @INTERPSPEC@ LD = @LD@ LIBGCJ_CFLAGS = @LIBGCJ_CFLAGS@ LIBGCJ_CXXFLAGS = @LIBGCJ_CXXFLAGS@ @@ -120,7 +121,7 @@ toolexeclib_DATA = libgcj.spec data_DATA = libgcj.zip @NATIVE_TRUE@bin_PROGRAMS = \ -@NATIVE_TRUE@jv-convert +@NATIVE_TRUE@jv-convert gij @CANADIAN_TRUE@@NULL_TARGET_TRUE@GCJ = \ @CANADIAN_TRUE@@NULL_TARGET_TRUE@gcj @CANADIAN_TRUE@@NULL_TARGET_FALSE@GCJ = \ @@ -156,8 +157,10 @@ AM_CXXFLAGS = -fno-rtti -fvtable-thunks @LIBGCJ_CXXFLAGS@ $(WARNINGS) JCFLAGS = -g JC1FLAGS = -g @LIBGCJ_JAVAFLAGS@ +LIBFFIINCS = -I$(top_srcdir)/../libffi/include -I../libffi/include + INCLUDES = -Iinclude -I$(top_srcdir)/include $(GCINCS) $(THREADINCS) \ - $(EH_COMMON_INCLUDE) $(ZINCS) + $(EH_COMMON_INCLUDE) $(ZINCS) $(LIBFFIINCS) DIVIDESPEC = @DIVIDESPEC@ @@ -168,7 +171,11 @@ javao_files = $(java_source_files:.java=.lo) \ $(built_java_source_files:.java=.lo) -libgcj_la_SOURCES = prims.cc jni.cc exception.cc +libffi_files = `$(AR) t ../libffi/.libs/libffi.a 2>/dev/null | sed 's/\.o/\.lo/g' | sed 's/^/..\/libffi\//g'` + +libgcj_la_SOURCES = prims.cc jni.cc exception.cc \ + resolve.cc defineclass.cc interpret.cc + EXTRA_libgcj_la_SOURCES = boehm.cc nogc.cc posix-threads.cc no-threads.cc \ $(c_source_files) $(java_source_files) $(built_java_source_files) @@ -176,7 +183,7 @@ libgcj_la_DEPENDENCIES = libgcj.zip $(javao_files) $(nat_files) \ $(c_files) $(GCOBJS) $(THREADOBJS) libgcj_la_LIBADD = $(javao_files) $(nat_files) $(c_files) $(GCOBJS) \ - $(THREADOBJS) + $(THREADOBJS) $(libffi_files) libgcj_la_LDFLAGS = -rpath $(toolexeclibdir) \ -version-info `grep -v '^\#' $(srcdir)/libtool-version` @@ -217,6 +224,19 @@ jv_convert_DEPENDENCIES = $(convert_source_files:.java=.lo) \ $(GCDEPS) $(THREADDEPS) $(ZDEPS) libgcj.la libgcj.spec +gij_SOURCES = +EXTRA_gij_SOURCES = gij.cc +gij_LDFLAGS = -rpath $(toolexeclibdir) +gij_LINK = $(LIBTOOL) --mode=link $(GCJ) $(JC1FLAGS) $(LDFLAGS) \ + -o gij + +gij_LDADD = gij.lo libgcj.la \ + $(GCLIBS) $(THREADLIBS) $(ZLIBS) -L$(here)/.libs + +gij_DEPENDENCIES = gij.lo \ + $(GCDEPS) $(THREADDEPS) $(ZDEPS) libgcj.la libgcj.spec + + gen_from_JIS_SOURCES = EXTRA_gen_from_JIS_SOURCES = $(srcdir)/$(CONVERT_DIR)/gen-from-JIS.c \ $(srcdir)/$(CONVERT_DIR)/make-trie.c \ @@ -294,6 +314,13 @@ java/awt/peer/WindowPeer.java built_java_source_files = java/lang/ConcreteProcess.java ordinary_java_source_files = $(convert_source_files) \ +gnu/gcj/runtime/MethodInvocation.java \ +gnu/gcj/util/path/SearchPath.java \ +gnu/gcj/util/path/PathEntry.java \ +gnu/gcj/util/path/DirectoryPathEntry.java \ +gnu/gcj/util/path/ZipPathEntry.java \ +gnu/gcj/util/path/URLPathEntry.java \ +gnu/gcj/util/path/CacheEntry.java \ gnu/gcj/text/BaseBreakIterator.java \ gnu/gcj/text/CharacterBreakIterator.java \ gnu/gcj/text/LineBreakIterator.java \ @@ -372,6 +399,7 @@ java/lang/ClassCastException.java \ java/lang/ClassCircularityError.java \ java/lang/ClassFormatError.java \ java/lang/ClassLoader.java \ +java/lang/VMClassLoader.java \ java/lang/ClassNotFoundException.java \ java/lang/CloneNotSupportedException.java \ java/lang/Cloneable.java \ @@ -569,6 +597,7 @@ java/io/natFile.cc \ java/io/natFileDescriptor.cc \ java/lang/natCharacter.cc \ java/lang/natClass.cc \ +java/lang/natClassLoader.cc \ java/lang/natConcreteProcess.cc \ java/lang/natDouble.cc \ java/lang/natFirstThread.cc \ @@ -655,13 +684,15 @@ DEFS = @DEFS@ -I. -I$(srcdir) -I./include CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ -libgcj_la_OBJECTS = prims.lo jni.lo exception.lo -@NATIVE_TRUE@bin_PROGRAMS = jv-convert$(EXEEXT) +libgcj_la_OBJECTS = prims.lo jni.lo exception.lo resolve.lo \ +defineclass.lo interpret.lo +@NATIVE_TRUE@bin_PROGRAMS = jv-convert$(EXEEXT) gij$(EXEEXT) @NATIVE_TRUE@@MAINTAINER_MODE_TRUE@noinst_PROGRAMS = \ @NATIVE_TRUE@@MAINTAINER_MODE_TRUE@gen-from-JIS$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) jv_convert_OBJECTS = +gij_OBJECTS = gen_from_JIS_OBJECTS = gen_from_JIS_LDFLAGS = CXXFLAGS = @CXXFLAGS@ @@ -688,9 +719,9 @@ GZIP_ENV = --best DIST_SUBDIRS = testsuite DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \ .deps/$(srcdir)/$(CONVERT_DIR)/make-trie.P .deps/boehm.P \ -.deps/exception.P .deps/gnu/gcj/RawData.P \ -.deps/gnu/gcj/convert/BytesToUnicode.P .deps/gnu/gcj/convert/Convert.P \ -.deps/gnu/gcj/convert/Input_8859_1.P \ +.deps/defineclass.P .deps/exception.P .deps/gij.P \ +.deps/gnu/gcj/RawData.P .deps/gnu/gcj/convert/BytesToUnicode.P \ +.deps/gnu/gcj/convert/Convert.P .deps/gnu/gcj/convert/Input_8859_1.P \ .deps/gnu/gcj/convert/Input_EUCJIS.P \ .deps/gnu/gcj/convert/Input_JavaSrc.P \ .deps/gnu/gcj/convert/Input_SJIS.P .deps/gnu/gcj/convert/Input_UTF8.P \ @@ -703,6 +734,7 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \ .deps/gnu/gcj/protocol/file/Handler.P \ .deps/gnu/gcj/protocol/http/Connection.P \ .deps/gnu/gcj/protocol/http/Handler.P \ +.deps/gnu/gcj/runtime/MethodInvocation.P \ .deps/gnu/gcj/text/BaseBreakIterator.P \ .deps/gnu/gcj/text/CharacterBreakIterator.P \ .deps/gnu/gcj/text/LineBreakIterator.P \ @@ -711,6 +743,12 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \ .deps/gnu/gcj/text/SentenceBreakIterator.P \ .deps/gnu/gcj/text/WordBreakIterator.P \ .deps/gnu/gcj/util/EnumerationChain.P \ +.deps/gnu/gcj/util/path/CacheEntry.P \ +.deps/gnu/gcj/util/path/DirectoryPathEntry.P \ +.deps/gnu/gcj/util/path/PathEntry.P \ +.deps/gnu/gcj/util/path/SearchPath.P \ +.deps/gnu/gcj/util/path/URLPathEntry.P \ +.deps/gnu/gcj/util/path/ZipPathEntry.P .deps/interpret.P \ .deps/java/io/BufferedInputStream.P \ .deps/java/io/BufferedOutputStream.P .deps/java/io/BufferedReader.P \ .deps/java/io/BufferedWriter.P .deps/java/io/ByteArrayInputStream.P \ @@ -788,8 +826,9 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \ .deps/java/lang/Throwable.P .deps/java/lang/UnknownError.P \ .deps/java/lang/UnsatisfiedLinkError.P \ .deps/java/lang/UnsupportedOperationException.P \ -.deps/java/lang/VerifyError.P .deps/java/lang/VirtualMachineError.P \ -.deps/java/lang/Void.P .deps/java/lang/dtoa.P .deps/java/lang/e_acos.P \ +.deps/java/lang/VMClassLoader.P .deps/java/lang/VerifyError.P \ +.deps/java/lang/VirtualMachineError.P .deps/java/lang/Void.P \ +.deps/java/lang/dtoa.P .deps/java/lang/e_acos.P \ .deps/java/lang/e_asin.P .deps/java/lang/e_atan2.P \ .deps/java/lang/e_exp.P .deps/java/lang/e_fmod.P \ .deps/java/lang/e_log.P .deps/java/lang/e_pow.P \ @@ -872,9 +911,9 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \ .deps/java/util/zip/ZipException.P .deps/java/util/zip/ZipFile.P \ .deps/java/util/zip/ZipInputStream.P \ .deps/java/util/zip/ZipOutputStream.P .deps/jni.P .deps/no-threads.P \ -.deps/nogc.P .deps/posix-threads.P .deps/prims.P -SOURCES = $(libgcj_la_SOURCES) $(EXTRA_libgcj_la_SOURCES) $(jv_convert_SOURCES) $(EXTRA_jv_convert_SOURCES) $(gen_from_JIS_SOURCES) $(EXTRA_gen_from_JIS_SOURCES) -OBJECTS = $(libgcj_la_OBJECTS) $(jv_convert_OBJECTS) $(gen_from_JIS_OBJECTS) +.deps/nogc.P .deps/posix-threads.P .deps/prims.P .deps/resolve.P +SOURCES = $(libgcj_la_SOURCES) $(EXTRA_libgcj_la_SOURCES) $(jv_convert_SOURCES) $(EXTRA_jv_convert_SOURCES) $(gij_SOURCES) $(EXTRA_gij_SOURCES) $(gen_from_JIS_SOURCES) $(EXTRA_gen_from_JIS_SOURCES) +OBJECTS = $(libgcj_la_OBJECTS) $(jv_convert_OBJECTS) $(gij_OBJECTS) $(gen_from_JIS_OBJECTS) all: all-redirect .SUFFIXES: @@ -1022,6 +1061,10 @@ jv-convert$(EXEEXT): $(jv_convert_OBJECTS) $(jv_convert_DEPENDENCIES) @rm -f jv-convert$(EXEEXT) $(jv_convert_LINK) $(jv_convert_LDFLAGS) $(jv_convert_OBJECTS) $(jv_convert_LDADD) $(LIBS) +gij$(EXEEXT): $(gij_OBJECTS) $(gij_DEPENDENCIES) + @rm -f gij$(EXEEXT) + $(gij_LINK) $(gij_LDFLAGS) $(gij_OBJECTS) $(gij_LDADD) $(LIBS) + gen-from-JIS$(EXEEXT): $(gen_from_JIS_OBJECTS) $(gen_from_JIS_DEPENDENCIES) @rm -f gen-from-JIS$(EXEEXT) $(LINK) $(gen_from_JIS_LDFLAGS) $(gen_from_JIS_OBJECTS) $(gen_from_JIS_LDADD) $(LIBS) @@ -1451,6 +1494,16 @@ java/lang/reflect/Method.h: java/lang/reflect/Method.class libgcj.zip -friend 'java::lang::Class;' \ $(basename $<) +java/lang/VMClassLoader.h: java/lang/VMClassLoader.class libgcj.zip + $(GCJH) -classpath $(top_builddir) \ + -friend 'java::lang::ClassLoader;' \ + $(basename $<) + +gnu/gcj/runtime/MethodInvocation.h: gnu/gcj/runtime/MethodInvocation.class libgcj.zip + $(GCJH) -classpath $(top_builddir) \ + -friend 'class _Jv_InterpMethod;' \ + $(basename $<) + maintainer-check: libgcj.la $(NM) .libs/libgcj.a | grep ' T ' \ | grep -v '4java' \ diff --git a/libjava/NEWS b/libjava/NEWS index 114e48a..e83836d 100644 --- a/libjava/NEWS +++ b/libjava/NEWS @@ -1,3 +1,7 @@ +New in libgcj X.XX: + +* libgcj now includes a bytecode interpreter. + New in libgcj 2.95: * First public release diff --git a/libjava/THANKS b/libjava/THANKS index 93b24a8..5b9b9f8 100644 --- a/libjava/THANKS +++ b/libjava/THANKS @@ -10,9 +10,10 @@ Eric Christopher echristo@cygnus.com Franz Sirl Franz.Sirl-kernel@lauterbach.com Geoff Berry gcb@gnu.org Gilles Zunino Gilles.Zunino@hei.fr -Per Bothner per@bother.com +Kresten Krab Thorup krab@gnu.org +Per Bothner per@bothner.com Rainer Orth ro@TechFak.Uni-Bielefeld.DE -Stu Grossman grossman@cygnus.com +Stu Grossman grossman@juniper.com Tom Tromey tromey@cygnus.com Urban Widmark urban@svenskatest.se Warren Levy warrenl@cygnus.com diff --git a/libjava/acconfig.h b/libjava/acconfig.h index daddbb1..1bd5025 100644 --- a/libjava/acconfig.h +++ b/libjava/acconfig.h @@ -93,3 +93,6 @@ #undef HAVE_READDIR_R #undef HAVE_GETHOSTBYNAME_R #undef HAVE_GETHOSTBYADDR_R + +/* Define if you want a bytecode interpreter. */ +#undef INTERPRETER diff --git a/libjava/boehm.cc b/libjava/boehm.cc index f9e72ba..2e1b5f2 100644 --- a/libjava/boehm.cc +++ b/libjava/boehm.cc @@ -16,6 +16,7 @@ details. */ #include <java/lang/Class.h> #include <jvm.h> #include <java-field.h> +#include <java-interp.h> // We need to include gc_priv.h. However, it tries to include // config.h if it hasn't already been included. So we force the @@ -97,8 +98,14 @@ _Jv_MarkObj (void *addr, void *msp, void *msl, void * /*env*/) { jclass c = (jclass) addr; +#if 0 + // The next field should probably not be marked, since this is + // only used in the class hash table. Marking this field + // basically prohibits class unloading. --Kresten w = (word) c->next; MAYBE_MARK (w, mark_stack_ptr, mark_stack_limit, c, c2label); +#endif + w = (word) c->name; MAYBE_MARK (w, mark_stack_ptr, mark_stack_limit, c, c3label); w = (word) c->superclass; @@ -109,12 +116,23 @@ _Jv_MarkObj (void *addr, void *msp, void *msl, void * /*env*/) MAYBE_MARK (w, mark_stack_ptr, mark_stack_limit, c, c5label); } +#ifdef INTERPRETER + if (_Jv_IsInterpretedClass (c)) + { + w = (word) c->constants.tags; + MAYBE_MARK (w, mark_stack_ptr, mark_stack_limit, c, c5alabel); + w = (word) c->constants.data; + MAYBE_MARK (w, mark_stack_ptr, mark_stack_limit, c, c5blabel); + } +#endif + // If the class is an array, then the methods field holds a // pointer to the element class. If the class is primitive, // then the methods field holds a pointer to the array class. w = (word) c->methods; MAYBE_MARK (w, mark_stack_ptr, mark_stack_limit, c, c6label); + if (! c->isArray() && ! c->isPrimitive()) { // Scan each method in the cases where `methods' really @@ -127,7 +145,19 @@ _Jv_MarkObj (void *addr, void *msp, void *msl, void * /*env*/) w = (word) c->methods[i].signature; MAYBE_MARK (w, mark_stack_ptr, mark_stack_limit, c, cm2label); + // FIXME: `ncode' entry? + +#ifdef INTERPRETER + // The interpreter installs a heap-allocated + // trampoline here, so we'll mark it. + if (_Jv_IsInterpretedClass (c)) + { + w = (word) c->methods[i].ncode; + MAYBE_MARK (w, mark_stack_ptr, mark_stack_limit, c, + cm3label); + } +#endif } } @@ -136,12 +166,34 @@ _Jv_MarkObj (void *addr, void *msp, void *msl, void * /*env*/) MAYBE_MARK (w, mark_stack_ptr, mark_stack_limit, c, c8label); for (int i = 0; i < c->field_count; ++i) { + _Jv_Field* field = &c->fields[i]; + #ifndef COMPACT_FIELDS - w = (word) c->fields[i].name; + w = (word) field->name; MAYBE_MARK (w, mark_stack_ptr, mark_stack_limit, c, c8alabel); #endif - w = (word) c->fields[i].type; + w = (word) field->type; MAYBE_MARK (w, mark_stack_ptr, mark_stack_limit, c, c8blabel); + + // For the interpreter, we also need to mark the memory + // containing static members + if (field->flags & 0x0008) + { + w = (word) field->u.addr; + MAYBE_MARK (w, mark_stack_ptr, mark_stack_limit, c, c8clabel); + + // also, if the static member is a reference, + // mark also the value pointed to. We check for isResolved + // since marking can happen before memory is allocated for + // static members. + if (JvFieldIsRef (field) && field->isResolved()) + { + jobject val = *(jobject*) field->u.addr; + w = (word) val; + MAYBE_MARK (w, mark_stack_ptr, mark_stack_limit, + c, c8elabel); + } + } } w = (word) c->vtable; @@ -155,6 +207,28 @@ _Jv_MarkObj (void *addr, void *msp, void *msl, void * /*env*/) } w = (word) c->loader; MAYBE_MARK (w, mark_stack_ptr, mark_stack_limit, c, cBlabel); + +#ifdef INTERPRETER + if (_Jv_IsInterpretedClass (c)) + { + _Jv_InterpClass* ic = (_Jv_InterpClass*)c; + + w = (word) ic->interpreted_methods; + MAYBE_MARK (w, mark_stack_ptr, mark_stack_limit, ic, cElabel); + + for (int i = 0; i < c->method_count; i++) + { + w = (word) ic->interpreted_methods[i]; + MAYBE_MARK (w, mark_stack_ptr, mark_stack_limit, ic, \ + cFlabel); + } + + w = (word) ic->field_initializers; + MAYBE_MARK (w, mark_stack_ptr, mark_stack_limit, ic, cGlabel); + + } +#endif + } else { diff --git a/libjava/configure b/libjava/configure index a08e388..eac0e54 100755 --- a/libjava/configure +++ b/libjava/configure @@ -35,6 +35,8 @@ ac_help="$ac_help ac_help="$ac_help --enable-libgcj-debug Enable runtime debugging code" ac_help="$ac_help + --enable-interpreter Enable interpreter" +ac_help="$ac_help --with-ecos Enable runtime eCos target support." ac_help="$ac_help --with-system-zlib Use installed libz" @@ -59,6 +61,7 @@ program_suffix=NONE program_transform_name=s,x,x, silent= site= +sitefile= srcdir= target=NONE verbose= @@ -173,6 +176,7 @@ Configuration: --help print this message --no-create do not create output files --quiet, --silent do not print \`checking...' messages + --site-file=FILE use FILE as the site file --version print the version of autoconf that created configure Directory and file names: --prefix=PREFIX install architecture-independent files in PREFIX @@ -343,6 +347,11 @@ EOF -site=* | --site=* | --sit=*) site="$ac_optarg" ;; + -site-file | --site-file | --site-fil | --site-fi | --site-f) + ac_prev=sitefile ;; + -site-file=* | --site-file=* | --site-fil=* | --site-fi=* | --site-f=*) + sitefile="$ac_optarg" ;; + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) @@ -508,12 +517,16 @@ fi srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` # Prefer explicitly selected file to automatically selected ones. -if test -z "$CONFIG_SITE"; then - if test "x$prefix" != xNONE; then - CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" - else - CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" +if test -z "$sitefile"; then + if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi fi +else + CONFIG_SITE="$sitefile" fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then @@ -601,7 +614,7 @@ else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } fi echo $ac_n "checking host system type""... $ac_c" 1>&6 -echo "configure:605: checking host system type" >&5 +echo "configure:618: checking host system type" >&5 host_alias=$host case "$host_alias" in @@ -622,7 +635,7 @@ host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` echo "$ac_t""$host" 1>&6 echo $ac_n "checking target system type""... $ac_c" 1>&6 -echo "configure:626: checking target system type" >&5 +echo "configure:639: checking target system type" >&5 target_alias=$target case "$target_alias" in @@ -640,7 +653,7 @@ target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` echo "$ac_t""$target" 1>&6 echo $ac_n "checking build system type""... $ac_c" 1>&6 -echo "configure:644: checking build system type" >&5 +echo "configure:657: checking build system type" >&5 build_alias=$build case "$build_alias" in @@ -688,7 +701,7 @@ fi # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 -echo "configure:692: checking for a BSD compatible install" >&5 +echo "configure:705: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -741,7 +754,7 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6 -echo "configure:745: checking whether build environment is sane" >&5 +echo "configure:758: checking whether build environment is sane" >&5 # Just in case sleep 1 echo timestamp > conftestfile @@ -798,7 +811,7 @@ test "$program_suffix" != NONE && test "$program_transform_name" = "" && program_transform_name="s,x,x," echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 -echo "configure:802: checking whether ${MAKE-make} sets \${MAKE}" >&5 +echo "configure:815: checking whether ${MAKE-make} sets \${MAKE}" >&5 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -831,12 +844,12 @@ else fi echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6 -echo "configure:835: checking for Cygwin environment" >&5 +echo "configure:848: checking for Cygwin environment" >&5 if eval "test \"`echo '$''{'ac_cv_cygwin'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 840 "configure" +#line 853 "configure" #include "confdefs.h" int main() { @@ -847,7 +860,7 @@ int main() { return __CYGWIN__; ; return 0; } EOF -if { (eval echo configure:851: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:864: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_cygwin=yes else @@ -864,19 +877,19 @@ echo "$ac_t""$ac_cv_cygwin" 1>&6 CYGWIN= test "$ac_cv_cygwin" = yes && CYGWIN=yes echo $ac_n "checking for mingw32 environment""... $ac_c" 1>&6 -echo "configure:868: checking for mingw32 environment" >&5 +echo "configure:881: checking for mingw32 environment" >&5 if eval "test \"`echo '$''{'ac_cv_mingw32'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 873 "configure" +#line 886 "configure" #include "confdefs.h" int main() { return __MINGW32__; ; return 0; } EOF -if { (eval echo configure:880: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:893: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_mingw32=yes else @@ -924,7 +937,7 @@ else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } fi echo $ac_n "checking host system type""... $ac_c" 1>&6 -echo "configure:928: checking host system type" >&5 +echo "configure:941: checking host system type" >&5 host_alias=$host case "$host_alias" in @@ -966,7 +979,7 @@ EOF missing_dir=`cd $ac_aux_dir && pwd` echo $ac_n "checking for working aclocal""... $ac_c" 1>&6 -echo "configure:970: checking for working aclocal" >&5 +echo "configure:983: checking for working aclocal" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -979,7 +992,7 @@ else fi echo $ac_n "checking for working autoconf""... $ac_c" 1>&6 -echo "configure:983: checking for working autoconf" >&5 +echo "configure:996: checking for working autoconf" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -992,7 +1005,7 @@ else fi echo $ac_n "checking for working automake""... $ac_c" 1>&6 -echo "configure:996: checking for working automake" >&5 +echo "configure:1009: checking for working automake" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -1005,7 +1018,7 @@ else fi echo $ac_n "checking for working autoheader""... $ac_c" 1>&6 -echo "configure:1009: checking for working autoheader" >&5 +echo "configure:1022: checking for working autoheader" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -1018,7 +1031,7 @@ else fi echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6 -echo "configure:1022: checking for working makeinfo" >&5 +echo "configure:1035: checking for working makeinfo" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -1043,7 +1056,7 @@ fi # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1047: checking for $ac_word" >&5 +echo "configure:1060: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1073,7 +1086,7 @@ if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1077: checking for $ac_word" >&5 +echo "configure:1090: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1122,7 +1135,7 @@ fi fi echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 -echo "configure:1126: checking whether we are using GNU C" >&5 +echo "configure:1139: checking whether we are using GNU C" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1131,7 +1144,7 @@ else yes; #endif EOF -if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1135: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1148: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no @@ -1146,7 +1159,7 @@ if test $ac_cv_prog_gcc = yes; then ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 -echo "configure:1150: checking whether ${CC-cc} accepts -g" >&5 +echo "configure:1163: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1182,7 +1195,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1186: checking for $ac_word" >&5 +echo "configure:1199: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1215,7 +1228,7 @@ test -n "$CXX" || CXX="gcc" test -z "$CXX" && { echo "configure: error: no acceptable c++ found in \$PATH" 1>&2; exit 1; } echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6 -echo "configure:1219: checking whether we are using GNU C++" >&5 +echo "configure:1232: checking whether we are using GNU C++" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1224,7 +1237,7 @@ else yes; #endif EOF -if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:1228: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:1241: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gxx=yes else ac_cv_prog_gxx=no @@ -1239,7 +1252,7 @@ if test $ac_cv_prog_gxx = yes; then ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS= echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6 -echo "configure:1243: checking whether ${CXX-g++} accepts -g" >&5 +echo "configure:1256: checking whether ${CXX-g++} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1272,7 +1285,7 @@ fi # LIBGCJ_CONFIGURE, which doesn't work because that means that it will # be run before AC_CANONICAL_HOST. echo $ac_n "checking build system type""... $ac_c" 1>&6 -echo "configure:1276: checking build system type" >&5 +echo "configure:1289: checking build system type" >&5 build_alias=$build case "$build_alias" in @@ -1293,7 +1306,7 @@ echo "$ac_t""$build" 1>&6 # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. set dummy ${ac_tool_prefix}as; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1297: checking for $ac_word" >&5 +echo "configure:1310: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AS'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1325,7 +1338,7 @@ fi # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1329: checking for $ac_word" >&5 +echo "configure:1342: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1357,7 +1370,7 @@ fi # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1361: checking for $ac_word" >&5 +echo "configure:1374: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1389,7 +1402,7 @@ if test -n "$ac_tool_prefix"; then # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1393: checking for $ac_word" >&5 +echo "configure:1406: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1434,7 +1447,7 @@ fi # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 -echo "configure:1438: checking for a BSD compatible install" >&5 +echo "configure:1451: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1488,7 +1501,7 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6 -echo "configure:1492: checking whether to enable maintainer-specific portions of Makefiles" >&5 +echo "configure:1505: checking whether to enable maintainer-specific portions of Makefiles" >&5 # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given. if test "${enable_maintainer_mode+set}" = set; then enableval="$enable_maintainer_mode" @@ -1522,7 +1535,7 @@ if false; then echo $ac_n "checking for executable suffix""... $ac_c" 1>&6 -echo "configure:1526: checking for executable suffix" >&5 +echo "configure:1539: checking for executable suffix" >&5 if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1532,7 +1545,7 @@ else rm -f conftest* echo 'int main () { return 0; }' > conftest.$ac_ext ac_cv_exeext= - if { (eval echo configure:1536: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then + if { (eval echo configure:1549: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then for file in conftest.*; do case $file in *.c | *.o | *.obj | *.ilk | *.pdb) ;; @@ -1654,7 +1667,7 @@ fi # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1658: checking for $ac_word" >&5 +echo "configure:1671: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1684,7 +1697,7 @@ fi # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1688: checking for $ac_word" >&5 +echo "configure:1701: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1714,7 +1727,7 @@ if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1718: checking for $ac_word" >&5 +echo "configure:1731: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1765,7 +1778,7 @@ fi # Extract the first word of "cl", so it can be a program name with args. set dummy cl; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1769: checking for $ac_word" >&5 +echo "configure:1782: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1797,7 +1810,7 @@ fi fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 -echo "configure:1801: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 +echo "configure:1814: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. @@ -1808,12 +1821,12 @@ cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext << EOF -#line 1812 "configure" +#line 1825 "configure" #include "confdefs.h" main(){return(0);} EOF -if { (eval echo configure:1817: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1830: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then ac_cv_prog_cc_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then @@ -1839,12 +1852,12 @@ if test $ac_cv_prog_cc_works = no; then { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 -echo "configure:1843: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "configure:1856: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 cross_compiling=$ac_cv_prog_cc_cross echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 -echo "configure:1848: checking whether we are using GNU C" >&5 +echo "configure:1861: checking whether we are using GNU C" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1853,7 +1866,7 @@ else yes; #endif EOF -if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1857: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1870: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no @@ -1872,7 +1885,7 @@ ac_test_CFLAGS="${CFLAGS+set}" ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 -echo "configure:1876: checking whether ${CC-cc} accepts -g" >&5 +echo "configure:1889: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1915,7 +1928,7 @@ ac_prog=ld if test "$ac_cv_prog_gcc" = yes; then # Check if gcc -print-prog-name=ld gives a path. echo $ac_n "checking for ld used by GCC""... $ac_c" 1>&6 -echo "configure:1919: checking for ld used by GCC" >&5 +echo "configure:1932: checking for ld used by GCC" >&5 ac_prog=`($CC -print-prog-name=ld) 2>&5` case "$ac_prog" in # Accept absolute paths. @@ -1939,10 +1952,10 @@ echo "configure:1919: checking for ld used by GCC" >&5 esac elif test "$with_gnu_ld" = yes; then echo $ac_n "checking for GNU ld""... $ac_c" 1>&6 -echo "configure:1943: checking for GNU ld" >&5 +echo "configure:1956: checking for GNU ld" >&5 else echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6 -echo "configure:1946: checking for non-GNU ld" >&5 +echo "configure:1959: checking for non-GNU ld" >&5 fi if eval "test \"`echo '$''{'ac_cv_path_LD'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1978,7 +1991,7 @@ fi test -z "$LD" && { echo "configure: error: no acceptable ld found in \$PATH" 1>&2; exit 1; } echo $ac_n "checking if the linker ($LD) is GNU ld""... $ac_c" 1>&6 -echo "configure:1982: checking if the linker ($LD) is GNU ld" >&5 +echo "configure:1995: checking if the linker ($LD) is GNU ld" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gnu_ld'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1994,7 +2007,7 @@ echo "$ac_t""$ac_cv_prog_gnu_ld" 1>&6 echo $ac_n "checking for BSD-compatible nm""... $ac_c" 1>&6 -echo "configure:1998: checking for BSD-compatible nm" >&5 +echo "configure:2011: checking for BSD-compatible nm" >&5 if eval "test \"`echo '$''{'ac_cv_path_NM'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2031,7 +2044,7 @@ echo "$ac_t""$NM" 1>&6 echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 -echo "configure:2035: checking whether ln -s works" >&5 +echo "configure:2048: checking whether ln -s works" >&5 if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2075,8 +2088,8 @@ test x"$silent" = xyes && libtool_flags="$libtool_flags --silent" case "$host" in *-*-irix6*) # Find out which ABI we are using. - echo '#line 2079 "configure"' > conftest.$ac_ext - if { (eval echo configure:2080: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + echo '#line 2092 "configure"' > conftest.$ac_ext + if { (eval echo configure:2093: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then case "`/usr/bin/file conftest.o`" in *32-bit*) LD="${LD-ld} -32" @@ -2097,19 +2110,19 @@ case "$host" in SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" echo $ac_n "checking whether the C compiler needs -belf""... $ac_c" 1>&6 -echo "configure:2101: checking whether the C compiler needs -belf" >&5 +echo "configure:2114: checking whether the C compiler needs -belf" >&5 if eval "test \"`echo '$''{'lt_cv_cc_needs_belf'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2106 "configure" +#line 2119 "configure" #include "confdefs.h" int main() { ; return 0; } EOF -if { (eval echo configure:2113: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2126: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* lt_cv_cc_needs_belf=yes else @@ -2253,6 +2266,21 @@ EOF fi +# Check whether --enable-interpreter or --disable-interpreter was given. +if test "${enable_interpreter+set}" = set; then + enableval="$enable_interpreter" + if test "$enable_interpreter" = yes; then + cat >> confdefs.h <<\EOF +#define INTERPRETER 1 +EOF + + fi +fi + + +INTERPSPEC= + + TARGET_ECOS="no" # Check whether --with-ecos or --without-ecos was given. if test "${with_ecos+set}" = set; then @@ -2278,7 +2306,7 @@ EOF esac echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 -echo "configure:2282: checking how to run the C preprocessor" >&5 +echo "configure:2310: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= @@ -2293,13 +2321,13 @@ else # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext <<EOF -#line 2297 "configure" +#line 2325 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2303: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2331: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -2310,13 +2338,13 @@ else rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext <<EOF -#line 2314 "configure" +#line 2342 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2320: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2348: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -2327,13 +2355,13 @@ else rm -rf conftest* CPP="${CC-cc} -nologo -E" cat > conftest.$ac_ext <<EOF -#line 2331 "configure" +#line 2359 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2337: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2365: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -2358,7 +2386,7 @@ fi echo "$ac_t""$CPP" 1>&6 cat > conftest.$ac_ext <<EOF -#line 2362 "configure" +#line 2390 "configure" #include "confdefs.h" #include <stdint.h> EOF @@ -2373,7 +2401,7 @@ fi rm -f conftest* cat > conftest.$ac_ext <<EOF -#line 2377 "configure" +#line 2405 "configure" #include "confdefs.h" #include <inttypes.h> EOF @@ -2388,7 +2416,7 @@ fi rm -f conftest* cat > conftest.$ac_ext <<EOF -#line 2392 "configure" +#line 2420 "configure" #include "confdefs.h" #include <sys/types.h> EOF @@ -2403,7 +2431,7 @@ fi rm -f conftest* cat > conftest.$ac_ext <<EOF -#line 2407 "configure" +#line 2435 "configure" #include "confdefs.h" #include <sys/config.h> EOF @@ -2420,7 +2448,7 @@ rm -f conftest* cat > conftest.$ac_ext <<EOF -#line 2424 "configure" +#line 2452 "configure" #include "confdefs.h" #include <time.h> EOF @@ -2435,7 +2463,7 @@ fi rm -f conftest* cat > conftest.$ac_ext <<EOF -#line 2439 "configure" +#line 2467 "configure" #include "confdefs.h" #include <time.h> EOF @@ -2473,7 +2501,7 @@ ZLIBSPEC= libsubdir=.libs echo $ac_n "checking for garbage collector to use""... $ac_c" 1>&6 -echo "configure:2477: checking for garbage collector to use" >&5 +echo "configure:2505: checking for garbage collector to use" >&5 # Check whether --enable-java-gc or --disable-java-gc was given. if test "${enable_java_gc+set}" = set; then enableval="$enable_java_gc" @@ -2523,7 +2551,7 @@ esac echo $ac_n "checking for threads package to use""... $ac_c" 1>&6 -echo "configure:2527: checking for threads package to use" >&5 +echo "configure:2555: checking for threads package to use" >&5 # Check whether --enable-threads or --disable-threads was given. if test "${enable_threads+set}" = set; then enableval="$enable_threads" @@ -2715,12 +2743,12 @@ else for ac_func in strerror ioctl select open fsync sleep do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2719: checking for $ac_func" >&5 +echo "configure:2747: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2724 "configure" +#line 2752 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -2743,7 +2771,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:2747: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2775: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -2770,12 +2798,12 @@ done for ac_func in ctime_r ctime do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2774: checking for $ac_func" >&5 +echo "configure:2802: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2779 "configure" +#line 2807 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -2798,7 +2826,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:2802: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2830: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -2825,12 +2853,12 @@ done for ac_func in gmtime_r localtime_r readdir_r getpwuid_r do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2829: checking for $ac_func" >&5 +echo "configure:2857: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2834 "configure" +#line 2862 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -2853,7 +2881,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:2857: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2885: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -2880,12 +2908,12 @@ done for ac_func in access stat mkdir rename rmdir unlink realpath do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2884: checking for $ac_func" >&5 +echo "configure:2912: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2889 "configure" +#line 2917 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -2908,7 +2936,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:2912: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2940: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -2935,12 +2963,12 @@ done for ac_func in inet_aton inet_addr do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2939: checking for $ac_func" >&5 +echo "configure:2967: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2944 "configure" +#line 2972 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -2963,7 +2991,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:2967: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2995: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -2990,12 +3018,12 @@ done for ac_func in inet_pton uname inet_ntoa do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2994: checking for $ac_func" >&5 +echo "configure:3022: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2999 "configure" +#line 3027 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -3018,7 +3046,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:3022: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3050: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -3046,12 +3074,12 @@ done for ac_func in gethostbyname_r do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:3050: checking for $ac_func" >&5 +echo "configure:3078: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3055 "configure" +#line 3083 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -3074,7 +3102,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:3078: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3106: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -3101,7 +3129,7 @@ EOF # We look for the one that returns `int'. # Hopefully this check is robust enough. cat > conftest.$ac_ext <<EOF -#line 3105 "configure" +#line 3133 "configure" #include "confdefs.h" #include <netdb.h> EOF @@ -3121,7 +3149,7 @@ rm -f conftest* *" -D_REENTRANT "*) ;; *) echo $ac_n "checking whether gethostbyname_r declaration requires -D_REENTRANT""... $ac_c" 1>&6 -echo "configure:3125: checking whether gethostbyname_r declaration requires -D_REENTRANT" >&5 +echo "configure:3153: checking whether gethostbyname_r declaration requires -D_REENTRANT" >&5 if eval "test \"`echo '$''{'libjava_cv_gethostbyname_r_needs_reentrant'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3134,14 +3162,14 @@ ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftes cross_compiling=$ac_cv_prog_cxx_cross cat > conftest.$ac_ext <<EOF -#line 3138 "configure" +#line 3166 "configure" #include "confdefs.h" #include <netdb.h> int main() { gethostbyname_r("", 0, 0); ; return 0; } EOF -if { (eval echo configure:3145: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3173: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* libjava_cv_gethostbyname_r_needs_reentrant=no else @@ -3151,14 +3179,14 @@ else CPPFLAGS_SAVE="$CPPFLAGS" CPPFLAGS="$CPPFLAGS -D_REENTRANT" cat > conftest.$ac_ext <<EOF -#line 3155 "configure" +#line 3183 "configure" #include "confdefs.h" #include <netdb.h> int main() { gethostbyname_r("", 0, 0); ; return 0; } EOF -if { (eval echo configure:3162: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3190: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* libjava_cv_gethostbyname_r_needs_reentrant=yes else @@ -3193,12 +3221,12 @@ EOF esac echo $ac_n "checking for struct hostent_data""... $ac_c" 1>&6 -echo "configure:3197: checking for struct hostent_data" >&5 +echo "configure:3225: checking for struct hostent_data" >&5 if eval "test \"`echo '$''{'libjava_cv_struct_hostent_data'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3202 "configure" +#line 3230 "configure" #include "confdefs.h" #if GETHOSTBYNAME_R_NEEDS_REENTRANT && !defined(_REENTRANT) @@ -3209,7 +3237,7 @@ int main() { struct hostent_data data; ; return 0; } EOF -if { (eval echo configure:3213: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3241: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* libjava_cv_struct_hostent_data=yes else @@ -3238,12 +3266,12 @@ done for ac_func in gethostbyaddr_r do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:3242: checking for $ac_func" >&5 +echo "configure:3270: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3247 "configure" +#line 3275 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -3266,7 +3294,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:3270: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3298: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -3293,7 +3321,7 @@ EOF # We look for the one that returns `int'. # Hopefully this check is robust enough. cat > conftest.$ac_ext <<EOF -#line 3297 "configure" +#line 3325 "configure" #include "confdefs.h" #include <netdb.h> EOF @@ -3317,12 +3345,12 @@ done for ac_func in gethostname do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:3321: checking for $ac_func" >&5 +echo "configure:3349: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3326 "configure" +#line 3354 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -3345,7 +3373,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:3349: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3377: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -3369,7 +3397,7 @@ EOF EOF cat > conftest.$ac_ext <<EOF -#line 3373 "configure" +#line 3401 "configure" #include "confdefs.h" #include <unistd.h> EOF @@ -3396,12 +3424,12 @@ done for ac_func in pthread_mutexattr_settype pthread_mutexattr_setkind_np do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:3400: checking for $ac_func" >&5 +echo "configure:3428: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3405 "configure" +#line 3433 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -3424,7 +3452,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:3428: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3456: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -3454,12 +3482,12 @@ done for ac_func in sched_yield do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:3458: checking for $ac_func" >&5 +echo "configure:3486: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3463 "configure" +#line 3491 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -3482,7 +3510,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:3486: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3514: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -3504,7 +3532,7 @@ EOF else echo "$ac_t""no" 1>&6 echo $ac_n "checking for sched_yield in -lposix4""... $ac_c" 1>&6 -echo "configure:3508: checking for sched_yield in -lposix4" >&5 +echo "configure:3536: checking for sched_yield in -lposix4" >&5 ac_lib_var=`echo posix4'_'sched_yield | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -3512,7 +3540,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lposix4 $LIBS" cat > conftest.$ac_ext <<EOF -#line 3516 "configure" +#line 3544 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -3523,7 +3551,7 @@ int main() { sched_yield() ; return 0; } EOF -if { (eval echo configure:3527: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3555: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -3548,7 +3576,7 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for sched_yield in -lrt""... $ac_c" 1>&6 -echo "configure:3552: checking for sched_yield in -lrt" >&5 +echo "configure:3580: checking for sched_yield in -lrt" >&5 ac_lib_var=`echo rt'_'sched_yield | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -3556,7 +3584,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lrt $LIBS" cat > conftest.$ac_ext <<EOF -#line 3560 "configure" +#line 3588 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -3567,7 +3595,7 @@ int main() { sched_yield() ; return 0; } EOF -if { (eval echo configure:3571: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3599: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -3604,12 +3632,12 @@ done for ac_func in gettimeofday time ftime do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:3608: checking for $ac_func" >&5 +echo "configure:3636: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3613 "configure" +#line 3641 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -3632,7 +3660,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:3636: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3664: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -3663,12 +3691,12 @@ done for ac_func in memmove do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:3667: checking for $ac_func" >&5 +echo "configure:3695: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3672 "configure" +#line 3700 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -3691,7 +3719,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:3695: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3723: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -3721,12 +3749,12 @@ done for ac_func in memcpy do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:3725: checking for $ac_func" >&5 +echo "configure:3753: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3730 "configure" +#line 3758 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -3749,7 +3777,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:3753: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3781: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -3797,7 +3825,7 @@ done #-------------------------------------------------------------------- echo $ac_n "checking for socket libraries""... $ac_c" 1>&6 -echo "configure:3801: checking for socket libraries" >&5 +echo "configure:3829: checking for socket libraries" >&5 if eval "test \"`echo '$''{'gcj_cv_lib_sockets'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3805,12 +3833,12 @@ else gcj_checkBoth=0 unset ac_cv_func_connect echo $ac_n "checking for connect""... $ac_c" 1>&6 -echo "configure:3809: checking for connect" >&5 +echo "configure:3837: checking for connect" >&5 if eval "test \"`echo '$''{'ac_cv_func_connect'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3814 "configure" +#line 3842 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char connect(); below. */ @@ -3833,7 +3861,7 @@ connect(); ; return 0; } EOF -if { (eval echo configure:3837: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3865: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_connect=yes" else @@ -3856,7 +3884,7 @@ fi if test "$gcj_checkSocket" = 1; then unset ac_cv_func_connect echo $ac_n "checking for main in -lsocket""... $ac_c" 1>&6 -echo "configure:3860: checking for main in -lsocket" >&5 +echo "configure:3888: checking for main in -lsocket" >&5 ac_lib_var=`echo socket'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -3864,14 +3892,14 @@ else ac_save_LIBS="$LIBS" LIBS="-lsocket $LIBS" cat > conftest.$ac_ext <<EOF -#line 3868 "configure" +#line 3896 "configure" #include "confdefs.h" int main() { main() ; return 0; } EOF -if { (eval echo configure:3875: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3903: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -3898,12 +3926,12 @@ fi LIBS="$LIBS -lsocket -lnsl" unset ac_cv_func_accept echo $ac_n "checking for accept""... $ac_c" 1>&6 -echo "configure:3902: checking for accept" >&5 +echo "configure:3930: checking for accept" >&5 if eval "test \"`echo '$''{'ac_cv_func_accept'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3907 "configure" +#line 3935 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char accept(); below. */ @@ -3926,7 +3954,7 @@ accept(); ; return 0; } EOF -if { (eval echo configure:3930: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:3958: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_accept=yes" else @@ -3953,12 +3981,12 @@ fi gcj_oldLibs=$LIBS LIBS="$LIBS $gcj_cv_lib_sockets" echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6 -echo "configure:3957: checking for gethostbyname" >&5 +echo "configure:3985: checking for gethostbyname" >&5 if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 3962 "configure" +#line 3990 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char gethostbyname(); below. */ @@ -3981,7 +4009,7 @@ gethostbyname(); ; return 0; } EOF -if { (eval echo configure:3985: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4013: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gethostbyname=yes" else @@ -3999,7 +4027,7 @@ if eval "test \"`echo '$ac_cv_func_'gethostbyname`\" = yes"; then else echo "$ac_t""no" 1>&6 echo $ac_n "checking for main in -lnsl""... $ac_c" 1>&6 -echo "configure:4003: checking for main in -lnsl" >&5 +echo "configure:4031: checking for main in -lnsl" >&5 ac_lib_var=`echo nsl'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -4007,14 +4035,14 @@ else ac_save_LIBS="$LIBS" LIBS="-lnsl $LIBS" cat > conftest.$ac_ext <<EOF -#line 4011 "configure" +#line 4039 "configure" #include "confdefs.h" int main() { main() ; return 0; } EOF -if { (eval echo configure:4018: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4046: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -4044,9 +4072,13 @@ fi echo "$ac_t""$gcj_cv_lib_sockets" 1>&6 SYSTEMSPEC="$SYSTEMSPEC $gcj_cv_lib_sockets" + if test "$enable_interpreter" = yes; then + INTERPSPEC= + fi + if test "$with_system_zlib" = yes; then echo $ac_n "checking for deflate in -lz""... $ac_c" 1>&6 -echo "configure:4050: checking for deflate in -lz" >&5 +echo "configure:4082: checking for deflate in -lz" >&5 ac_lib_var=`echo z'_'deflate | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -4054,7 +4086,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lz $LIBS" cat > conftest.$ac_ext <<EOF -#line 4058 "configure" +#line 4090 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -4065,7 +4097,7 @@ int main() { deflate() ; return 0; } EOF -if { (eval echo configure:4069: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4101: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -4094,7 +4126,7 @@ fi # requires -ldl. if test "$GC" = boehm; then echo $ac_n "checking for main in -ldl""... $ac_c" 1>&6 -echo "configure:4098: checking for main in -ldl" >&5 +echo "configure:4130: checking for main in -ldl" >&5 ac_lib_var=`echo dl'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -4102,14 +4134,14 @@ else ac_save_LIBS="$LIBS" LIBS="-ldl $LIBS" cat > conftest.$ac_ext <<EOF -#line 4106 "configure" +#line 4138 "configure" #include "confdefs.h" int main() { main() ; return 0; } EOF -if { (eval echo configure:4113: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4145: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -4219,17 +4251,17 @@ for ac_hdr in unistd.h bstring.h sys/time.h sys/types.h fcntl.h sys/ioctl.h sys/ do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:4223: checking for $ac_hdr" >&5 +echo "configure:4255: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4228 "configure" +#line 4260 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:4233: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:4265: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -4259,17 +4291,17 @@ for ac_hdr in dirent.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:4263: checking for $ac_hdr" >&5 +echo "configure:4295: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4268 "configure" +#line 4300 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:4273: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:4305: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -4297,16 +4329,16 @@ done echo $ac_n "checking whether struct sockaddr_in6 is in netinet/in.h""... $ac_c" 1>&6 -echo "configure:4301: checking whether struct sockaddr_in6 is in netinet/in.h" >&5 +echo "configure:4333: checking whether struct sockaddr_in6 is in netinet/in.h" >&5 cat > conftest.$ac_ext <<EOF -#line 4303 "configure" +#line 4335 "configure" #include "confdefs.h" #include <netinet/in.h> int main() { struct sockaddr_in6 addr6; ; return 0; } EOF -if { (eval echo configure:4310: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:4342: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define HAVE_INET6 1 @@ -4322,16 +4354,16 @@ fi rm -f conftest* echo $ac_n "checking for socklen_t in sys/socket.h""... $ac_c" 1>&6 -echo "configure:4326: checking for socklen_t in sys/socket.h" >&5 +echo "configure:4358: checking for socklen_t in sys/socket.h" >&5 cat > conftest.$ac_ext <<EOF -#line 4328 "configure" +#line 4360 "configure" #include "confdefs.h" #include <sys/socket.h> int main() { socklen_t x = 5; ; return 0; } EOF -if { (eval echo configure:4335: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:4367: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define HAVE_SOCKLEN_T 1 @@ -4347,16 +4379,16 @@ fi rm -f conftest* echo $ac_n "checking for tm_gmtoff in struct tm""... $ac_c" 1>&6 -echo "configure:4351: checking for tm_gmtoff in struct tm" >&5 +echo "configure:4383: checking for tm_gmtoff in struct tm" >&5 cat > conftest.$ac_ext <<EOF -#line 4353 "configure" +#line 4385 "configure" #include "confdefs.h" #include <time.h> int main() { struct tm tim; tim.tm_gmtoff = 0; ; return 0; } EOF -if { (eval echo configure:4360: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:4392: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define STRUCT_TM_HAS_GMTOFF 1 @@ -4369,16 +4401,16 @@ else rm -rf conftest* echo "$ac_t""no" 1>&6 echo $ac_n "checking for global timezone variable""... $ac_c" 1>&6 -echo "configure:4373: checking for global timezone variable" >&5 +echo "configure:4405: checking for global timezone variable" >&5 cat > conftest.$ac_ext <<EOF -#line 4375 "configure" +#line 4407 "configure" #include "confdefs.h" #include <time.h> int main() { long z2 = timezone; ; return 0; } EOF -if { (eval echo configure:4382: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:4414: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define HAVE_TIMEZONE 1 @@ -4398,19 +4430,19 @@ rm -f conftest* # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works # for constant arguments. Useless! echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6 -echo "configure:4402: checking for working alloca.h" >&5 +echo "configure:4434: checking for working alloca.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4407 "configure" +#line 4439 "configure" #include "confdefs.h" #include <alloca.h> int main() { char *p = alloca(2 * sizeof(int)); ; return 0; } EOF -if { (eval echo configure:4414: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4446: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_header_alloca_h=yes else @@ -4431,12 +4463,12 @@ EOF fi echo $ac_n "checking for alloca""... $ac_c" 1>&6 -echo "configure:4435: checking for alloca" >&5 +echo "configure:4467: checking for alloca" >&5 if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4440 "configure" +#line 4472 "configure" #include "confdefs.h" #ifdef __GNUC__ @@ -4464,7 +4496,7 @@ int main() { char *p = (char *) alloca(1); ; return 0; } EOF -if { (eval echo configure:4468: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4500: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_func_alloca_works=yes else @@ -4496,12 +4528,12 @@ EOF echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6 -echo "configure:4500: checking whether alloca needs Cray hooks" >&5 +echo "configure:4532: checking whether alloca needs Cray hooks" >&5 if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4505 "configure" +#line 4537 "configure" #include "confdefs.h" #if defined(CRAY) && ! defined(CRAY2) webecray @@ -4526,12 +4558,12 @@ echo "$ac_t""$ac_cv_os_cray" 1>&6 if test $ac_cv_os_cray = yes; then for ac_func in _getb67 GETB67 getb67; do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:4530: checking for $ac_func" >&5 +echo "configure:4562: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 4535 "configure" +#line 4567 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -4554,7 +4586,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:4558: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:4590: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -4581,7 +4613,7 @@ done fi echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6 -echo "configure:4585: checking stack direction for C alloca" >&5 +echo "configure:4617: checking stack direction for C alloca" >&5 if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4589,7 +4621,7 @@ else ac_cv_c_stack_direction=0 else cat > conftest.$ac_ext <<EOF -#line 4593 "configure" +#line 4625 "configure" #include "confdefs.h" find_stack_direction () { @@ -4608,7 +4640,7 @@ main () exit (find_stack_direction() < 0); } EOF -if { (eval echo configure:4612: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:4644: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_stack_direction=1 else @@ -4635,7 +4667,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4639: checking for $ac_word" >&5 +echo "configure:4671: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_PERL'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4868,6 +4900,7 @@ s%@LIBTOOL@%$LIBTOOL%g s%@COMPPATH@%$COMPPATH%g s%@TESTSUBDIR_TRUE@%$TESTSUBDIR_TRUE%g s%@TESTSUBDIR_FALSE@%$TESTSUBDIR_FALSE%g +s%@INTERPSPEC@%$INTERPSPEC%g s%@CPP@%$CPP%g s%@SYSTEMSPEC@%$SYSTEMSPEC%g s%@ZLIBSPEC@%$ZLIBSPEC%g diff --git a/libjava/configure.in b/libjava/configure.in index 4549889..861530a 100644 --- a/libjava/configure.in +++ b/libjava/configure.in @@ -42,6 +42,17 @@ AC_ARG_ENABLE(libgcj-debug, AC_DEFINE(DEBUG) fi) +dnl See if the user has the enterpreter included. +AC_ARG_ENABLE(interpreter, +[ --enable-interpreter Enable interpreter], + if test "$enable_interpreter" = yes; then + AC_DEFINE(INTERPRETER) + fi) + +dnl This becomes -lffi if the interpreter is enables +INTERPSPEC= +AC_SUBST(INTERPSPEC) + dnl If the target is an eCos system, use the appropriate eCos dnl I/O routines. dnl FIXME: this should not be a local option but a global target @@ -447,6 +458,10 @@ else ]) SYSTEMSPEC="$SYSTEMSPEC $gcj_cv_lib_sockets" + if test "$enable_interpreter" = yes; then + INTERPSPEC= + fi + if test "$with_system_zlib" = yes; then AC_CHECK_LIB(z, deflate, ZLIBSPEC=-lz, ZLIBSPEC=-lzgcj) else diff --git a/libjava/defineclass.cc b/libjava/defineclass.cc new file mode 100644 index 0000000..09f8f47 --- /dev/null +++ b/libjava/defineclass.cc @@ -0,0 +1,1556 @@ +// defineclass.cc - defining a class from .class format. + +/* Copyright (C) 1999 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. */ + +/* + Author: Kresten Krab Thorup <krab@gnu.org> + + Written using the online versions of Java Language Specification (1st + ed.) and The Java Virtual Machine Specification (2nd ed.). + + Future work may include reading (and handling) attributes which are + currently being ignored ("InnerClasses", "LineNumber", etc...). +*/ + +#include <java-interp.h> + +#ifdef INTERPRETER + +#include <java-cpool.h> +#include <cni.h> + +#include <java/lang/Class.h> +#include <java/lang/Float.h> +#include <java/lang/Double.h> +#include <java/lang/Character.h> +#include <java/lang/LinkageError.h> +#include <java/lang/InternalError.h> +#include <java/lang/ClassFormatError.h> +#include <java/lang/NoClassDefFoundError.h> +#include <java/lang/ClassCircularityError.h> +#include <java/lang/ClassNotFoundException.h> +#include <java/lang/IncompatibleClassChangeError.h> + +#define ClassClass _CL_Q34java4lang5Class +extern java::lang::Class ClassClass; +#define StringClass _CL_Q34java4lang6String +extern java::lang::Class StringClass; +#define ClassObject _CL_Q34java4lang6Object +extern java::lang::Class ClassObject; + +// we don't verify method names that match these. +static _Jv_Utf8Const *clinit_name = _Jv_makeUtf8Const ("<clinit>", 8); +static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6); + + +// these go in some seperate functions, to avoid having _Jv_InitClass +// inserted all over the place. +static void throw_internal_error (char *msg) + __attribute__ ((__noreturn__)); +static void throw_no_class_def_found_error (jstring msg) + __attribute__ ((__noreturn__)); +static void throw_no_class_def_found_error (char *msg) + __attribute__ ((__noreturn__)); +static void throw_class_format_error (jstring msg) + __attribute__ ((__noreturn__)); +static void throw_class_format_error (char *msg) + __attribute__ ((__noreturn__)); +static void throw_incompatible_class_change_error (jstring msg) + __attribute__ ((__noreturn__)); +static void throw_class_circularity_error (jstring msg) + __attribute__ ((__noreturn__)); + +static jdouble long_bits_to_double (jlong); +static jfloat int_bits_to_float (jint); + +/** + * We define class reading using a class. It is practical, since then + * the entire class-reader can be a friend of class Class (it needs to + * write all it's different structures); but also because this makes it + * easy to make class definition reentrant, and thus two threads can be + * defining classes at the same time. This class (_Jv_ClassReader) is + * never exposed outside this file, so we don't have to worry about + * public or private members here. + */ + +struct _Jv_ClassReader { + + // do verification? Currently, there is no option to disable this. + // This flag just controls the verificaiton done by the class loader; + // i.e., checking the integrity of the constant pool; and it is + // allways on. You always want this as far as I can see, but it also + // controls weither identifiers and type descriptors/signatures are + // verified as legal. This could be somewhat more expensive since it + // will call Characher.isJavaIdentifier{Start,Part} for each character + // in any identifier (field name or method name) it comes by. Thus, + // it might be useful to turn off this verification for classes that + // come from a trusted source. However, for GCJ, trusted classes are + // most likely to be linked in. + + bool verify; + + // input data. + unsigned char *bytes; + int len; + + // current input position + int pos; + + // the constant pool data + int pool_count; + unsigned char *tags; + unsigned int *offsets; + + // the class to define (see java-interp.h) + _Jv_InterpClass *def; + + /* check that the given number of input bytes are available */ + inline void check (int num) + { + if (pos + num > len) + throw_class_format_error ("Premature end of data"); + } + + /* skip a given number of bytes in input */ + inline void skip (int num) + { + check (num); + pos += num; + } + + /* read an unsignend 1-byte unit */ + inline static jint get1u (unsigned char* bytes) + { + return bytes[0]; + } + + /* read an unsigned 1-byte unit */ + inline jint read1u () + { + skip (1); + return get1u (bytes+pos-1); + } + + /* read an unsigned 2-byte unit */ + inline static jint get2u (unsigned char *bytes) + { + return (((jint)bytes[0]) << 8) | ((jint)bytes[1]); + } + + /* read an unsigned 2-byte unit */ + inline jint read2u () + { + skip (2); + return get2u (bytes+pos-2); + } + + /* read a 4-byte unit */ + static jint get4 (unsigned char *bytes) + { + return (((jint)bytes[0]) << 24) + | (((jint)bytes[1]) << 16) + | (((jint)bytes[2]) << 8) + | (((jint)bytes[3]) << 0); + } + + /* read a 4-byte unit, (we don't do that quite so often) */ + inline jint read4 () + { + skip (4); + return get4 (bytes+pos-4); + } + + /* read a 8-byte unit */ + static jlong get8 (unsigned char* bytes) + { + return (((jlong)bytes[0]) << 56) + | (((jlong)bytes[1]) << 48) + | (((jlong)bytes[2]) << 40) + | (((jlong)bytes[3]) << 32) + | (((jlong)bytes[4]) << 24) + | (((jlong)bytes[5]) << 16) + | (((jlong)bytes[6]) << 8) + | (((jlong)bytes[7]) << 0); + } + + /* read a 8-byte unit */ + inline jlong read8 () + { + skip (8); + return get8 (bytes+pos-8); + } + + inline void check_tag (int index, char expected_tag) + { + if (index < 0 + || index > pool_count + || tags[index] != expected_tag) + throw_class_format_error ("erroneous constant pool tag"); + } + + _Jv_ClassReader (jclass klass, jbyteArray data, jint offset, jint length) + { + if (klass == 0 || length < 0 || offset+length > data->length) + throw_internal_error ("arguments to _Jv_DefineClass"); + + verify = true; + bytes = (unsigned char*) (elements (data)+offset); + len = length; + pos = 0; + def = (_Jv_InterpClass*) klass; + } + + /** and here goes the parser members defined out-of-line */ + void parse (); + void read_constpool (); + void prepare_pool_entry (int index, unsigned char tag); + void read_fields (); + void read_methods (); + void read_one_class_attribute (); + void read_one_method_attribute (int method); + void read_one_code_attribute (int method); + void read_one_field_attribute (int field); + + /** check an utf8 entry, without creating a Utf8Const object */ + bool is_attribute_name (int index, char *name); + + /** here goes the class-loader members defined out-of-line */ + void handleConstantPool (); + void handleClassBegin (int, int, int); + void handleInterfacesBegin (int); + void handleInterface (int, int); + void handleFieldsBegin (int); + void handleField (int, int, int, int); + void handleFieldsEnd (); + void handleConstantValueAttribute (int,int); + void handleMethodsBegin (int); + void handleMethod (int, int, int, int); + void handleMethodsEnd (); + void handleCodeAttribute (int, int, int, int, int, int); + void handleExceptionTableEntry (int, int, int, int, int, int); + + void checkExtends (jclass sub, jclass super); + void checkImplements (jclass sub, jclass super); + + /* + * FIXME: we should keep a hash table of utf8-strings, since many will + * be the same. It's a little tricky, however, because the hash table + * needs to interact gracefully with the garbage collector. Much + * memory is to be saved by this, however! perhaps the improvement + * could be implemented in prims.cc (_Jv_makeUtf8Const), since it + * computes the hash value anyway. + */ + + static const int PUBLIC = 0x001; + static const int PRIVATE = 0x002; + static const int PROTECTED = 0x004; + static const int STATIC = 0x008; + static const int FINAL = 0x010; + static const int SYNCHRONIZED = 0x020; + static const int VOLATILE = 0x040; + static const int TRANSIENT = 0x080; + static const int NATIVE = 0x100; + static const int INTERFACE = 0x200; + static const int ABSTRACT = 0x400; + static const int ALL_FLAGS = 0x7FF; + +}; + +/* This is used for the isJavaIdentifierStart & isJavaIdentifierPart + methods, so we avoid doing _Jv_InitClass all the time */ + +static const java::lang::Character *character = 0; +static void prepare_character (); + +void +_Jv_DefineClass (jclass klass, jbyteArray data, jint offset, jint length) +{ + if (character == 0) + prepare_character (); + + _Jv_ClassReader reader (klass, data, offset, length); + reader.parse(); + + /* that's it! */ +} + +/** put it after _Jv_DefineClass, so it doesn't get inlined */ +static void prepare_character () +{ + character = new java::lang::Character ('!'); +} + + +/** This section defines the parsing/scanning of the class data */ + +void +_Jv_ClassReader::parse () +{ + int magic = read4 (); + + /* FIXME: Decide which range of version numbers to allow */ + + /* int minor_version = */ read2u (); + /* int major_verson = */ read2u (); + + if (magic != (int) 0xCAFEBABE) + throw_class_format_error ("bad magic number"); + + pool_count = read2u (); + + read_constpool (); + + int access_flags = read2u (); + int this_class = read2u (); + int super_class = read2u (); + + check_tag (this_class, JV_CONSTANT_Class); + if (super_class != 0) + check_tag (super_class, JV_CONSTANT_Class); + + handleClassBegin (access_flags, this_class, super_class); + + int interfaces_count = read2u (); + + handleInterfacesBegin (interfaces_count); + + for (int i = 0; i < interfaces_count; i++) + { + int iface = read2u (); + check_tag (iface, JV_CONSTANT_Class); + handleInterface (i, iface); + } + + read_fields (); + read_methods (); + + int attributes_count = read2u (); + + for (int i = 0; i < attributes_count; i++) + { + read_one_class_attribute (); + } + + if (pos != len) + throw_class_format_error ("unused data before end of file"); + + // tell everyone we're done. + def->state = JV_STATE_LOADED; + def->notifyAll (); + +} + +void _Jv_ClassReader::read_constpool () +{ + tags = (unsigned char*) _Jv_AllocBytesChecked (pool_count); + offsets = (unsigned int *) _Jv_AllocBytesChecked (sizeof (int) + * pool_count) ; + + /** first, we scan the constant pool, collecting tags and offsets */ + tags[0] = JV_CONSTANT_Undefined; + offsets[0] = pos; + for (int c = 1; c < pool_count; c++) + { + tags[c] = read1u (); + offsets[c] = pos; + + switch (tags[c]) + { + case JV_CONSTANT_String: + case JV_CONSTANT_Class: + skip (2); + break; + + case JV_CONSTANT_Fieldref: + case JV_CONSTANT_Methodref: + case JV_CONSTANT_InterfaceMethodref: + case JV_CONSTANT_NameAndType: + case JV_CONSTANT_Integer: + case JV_CONSTANT_Float: + skip (4); + break; + + case JV_CONSTANT_Double: + case JV_CONSTANT_Long: + skip (8); + tags[++c] = JV_CONSTANT_Undefined; + break; + + case JV_CONSTANT_Utf8: + { + int len = read2u (); + skip (len); + } + break; + + case JV_CONSTANT_Unicode: + throw_class_format_error ("unicode not supported"); + break; + + default: + throw_class_format_error ("erroneous constant pool tag"); + } + } + + handleConstantPool (); +} + + +void _Jv_ClassReader::read_fields () +{ + int fields_count = read2u (); + handleFieldsBegin (fields_count); + + for (int i = 0; i < fields_count; i++) + { + int access_flags = read2u (); + int name_index = read2u (); + int descriptor_index = read2u (); + int attributes_count = read2u (); + + check_tag (name_index, JV_CONSTANT_Utf8); + prepare_pool_entry (name_index, JV_CONSTANT_Utf8); + + check_tag (descriptor_index, JV_CONSTANT_Utf8); + prepare_pool_entry (descriptor_index, JV_CONSTANT_Utf8); + + handleField (i, access_flags, name_index, descriptor_index); + + for (int j = 0; j < attributes_count; j++) + { + read_one_field_attribute (i); + } + } + + handleFieldsEnd (); +} + +bool +_Jv_ClassReader::is_attribute_name (int index, char *name) +{ + check_tag (index, JV_CONSTANT_Utf8); + int len = get2u (bytes+offsets[index]); + if (len != (int) strlen (name)) + return false; + else + return !memcmp (bytes+offsets[index]+2, name, len); +} + +void _Jv_ClassReader::read_one_field_attribute (int field_index) +{ + int name = read2u (); + int length = read4 (); + + if (is_attribute_name (name, "ConstantValue")) + { + int cv = read2u (); + + if (cv < pool_count + && cv > 0 + && (tags[cv] == JV_CONSTANT_Integer + || tags[cv] == JV_CONSTANT_Float + || tags[cv] == JV_CONSTANT_Long + || tags[cv] == JV_CONSTANT_Double + || tags[cv] == JV_CONSTANT_String)) + { + handleConstantValueAttribute (field_index, cv); + } + else + { + throw_class_format_error ("erroneous ConstantValue attribute"); + } + + if (length != 2) + throw_class_format_error ("erroneous ConstantValue attribute"); + } + + else + { + skip (length); + } +} + +void _Jv_ClassReader::read_methods () +{ + int methods_count = read2u (); + + handleMethodsBegin (methods_count); + + for (int i = 0; i < methods_count; i++) + { + int access_flags = read2u (); + int name_index = read2u (); + int descriptor_index = read2u (); + int attributes_count = read2u (); + + check_tag (name_index, JV_CONSTANT_Utf8); + prepare_pool_entry (descriptor_index, JV_CONSTANT_Utf8); + + check_tag (name_index, JV_CONSTANT_Utf8); + prepare_pool_entry (descriptor_index, JV_CONSTANT_Utf8); + + handleMethod (i, access_flags, name_index, + descriptor_index); + + for (int j = 0; j < attributes_count; j++) + { + read_one_method_attribute (i); + } + } + + handleMethodsEnd (); +} + +void _Jv_ClassReader::read_one_method_attribute (int method_index) +{ + int name = read2u (); + int length = read4 (); + + if (is_attribute_name (name, "Exceptions")) + { + /* we ignore this for now */ + skip (length); + } + + else if (is_attribute_name (name, "Code")) + { + int start_off = pos; + int max_stack = read2u (); + int max_locals = read2u (); + int code_length = read4 (); + + int code_start = pos; + skip (code_length); + int exception_table_length = read2u (); + + handleCodeAttribute (method_index, + max_stack, max_locals, + code_start, code_length, + exception_table_length); + + + for (int i = 0; i < exception_table_length; i++) + { + int start_pc = read2u (); + int end_pc = read2u (); + int handler_pc = read2u (); + int catch_type = read2u (); + + if (start_pc > end_pc + || start_pc < 0 + || end_pc >= code_length + || handler_pc >= code_length) + throw_class_format_error ("erroneous exception handler info"); + + if (! (tags[catch_type] == JV_CONSTANT_Class + || tags[catch_type] == 0)) + { + throw_class_format_error ("erroneous exception handler info"); + } + + handleExceptionTableEntry (method_index, + i, + start_pc, + end_pc, + handler_pc, + catch_type); + + } + + int attributes_count = read2u (); + + for (int i = 0; i < attributes_count; i++) + { + read_one_code_attribute (method_index); + } + + if ((pos - start_off) != length) + throw_class_format_error ("code attribute too short"); + } + + else + { + /* ignore unknown attributes */ + skip (length); + } +} + +void _Jv_ClassReader::read_one_code_attribute (int /*method*/) +{ + /* ignore for now, ... later we may want to pick up + line number information, for debugging purposes; + in fact, the whole debugger issue is open! */ + + /* int name = */ read2u (); + int length = read4 (); + skip (length); + +} + +void _Jv_ClassReader::read_one_class_attribute () +{ + /* we also ignore the class attributes, ... + some day we'll add inner-classes support. */ + + /* int name = */ read2u (); + int length = read4 (); + skip (length); +} + + + + +/* this section defines the semantic actions of the parser */ + +void _Jv_ClassReader::handleConstantPool () +{ + /** now, we actually define the class' constant pool */ + + // the pool is scanned explicitly by the collector + jbyte *pool_tags = (jbyte*) _Jv_AllocBytesChecked (pool_count); + void **pool_data = (void**) _Jv_AllocBytesChecked (pool_count * sizeof (void*)); + + def->constants.tags = pool_tags; + def->constants.data = pool_data; + def->constants.size = pool_count; + + // Here we make a pass to collect the strings! We do this, because + // internally in the GCJ runtime, classes are encoded with .'s not /'s. + // Therefore, we first collect the strings, and then translate the rest + // of the utf8-entries (thus not representing strings) from /-notation + // to .-notation. + for (int i = 1; i < pool_count; i++) + { + if (tags[i] == JV_CONSTANT_String) + { + unsigned char* str_data = bytes + offsets [i]; + int utf_index = get2u (str_data); + check_tag (utf_index, JV_CONSTANT_Utf8); + unsigned char *utf_data = bytes + offsets[utf_index]; + int len = get2u (utf_data); + pool_data[i] = (void*)_Jv_makeUtf8Const ((char*)(utf_data+2), len); + pool_tags[i] = JV_CONSTANT_String; + } + else + { + pool_tags[i] = JV_CONSTANT_Undefined; + } + } + + // and now, we scan everything else but strings & utf8-entries. This + // leaves out those utf8-entries which are not used; which will be left + // with a tag of JV_CONSTANT_Undefined in the class definition. + for (int index = 1; index < pool_count; index++) + { + switch (tags[index]) + { + case JV_CONSTANT_Undefined: + case JV_CONSTANT_String: + case JV_CONSTANT_Utf8: + continue; + + default: + prepare_pool_entry (index, tags[index]); + } + } + +} + +/* this is a recursive procedure, which will prepare pool entries as needed. + Which is how we avoid initializing those entries which go unused. */ +void +_Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag) +{ + /* these two, pool_data and pool_tags, point into the class + structure we are currently defining */ + + unsigned char *pool_tags = (unsigned char*) def->constants.tags; + void **pool_data = (void**) def->constants.data; + + /* this entry was already prepared */ + if (pool_tags[index] == this_tag) + return; + + /* this_data points to the constant-pool information for the current + constant-pool entry */ + + unsigned char *this_data = bytes + offsets[index]; + + switch (this_tag) + { + case JV_CONSTANT_Utf8: + { + // If we came here, it is because some other tag needs this + // utf8-entry for type information! Thus, we translate /'s to .'s in + // order to accomondate gcj's internal representation. + + int len = get2u (this_data); + char *buffer = (char*) alloca (len); + char *s = ((char*) this_data)+2; + + /* FIXME: avoid using a buffer here */ + for (int i = 0; i < len; i++) + { + if (s[i] == '/') + buffer[i] = '.'; + else + buffer[i] = (char) s[i]; + } + + pool_data[index] = (void*)_Jv_makeUtf8Const (buffer, len); + pool_tags[index] = JV_CONSTANT_Utf8; + } + break; + + case JV_CONSTANT_Class: + { + int utf_index = get2u (this_data); + check_tag (utf_index, JV_CONSTANT_Utf8); + prepare_pool_entry (utf_index, JV_CONSTANT_Utf8); + + if (verify) + _Jv_VerifyClassName ((_Jv_Utf8Const*)pool_data[utf_index]); + + pool_data[index] = pool_data[utf_index]; + pool_tags[index] = JV_CONSTANT_Class; + } + break; + + case JV_CONSTANT_String: + // already handled before... + break; + + case JV_CONSTANT_Fieldref: + case JV_CONSTANT_Methodref: + case JV_CONSTANT_InterfaceMethodref: + { + int class_index = get2u (this_data); + int nat_index = get2u (this_data+2); + + check_tag (class_index, JV_CONSTANT_Class); + prepare_pool_entry (class_index, JV_CONSTANT_Class); + + check_tag (nat_index, JV_CONSTANT_NameAndType); + prepare_pool_entry (nat_index, JV_CONSTANT_NameAndType); + + // here, verify the signature and identifier name + if (verify) + { + _Jv_ushort name_index, type_index; + _Jv_loadIndexes ((const void**)&pool_data[nat_index], + name_index, type_index); + + if (this_tag == JV_CONSTANT_Fieldref) + _Jv_VerifyFieldSignature + ((_Jv_Utf8Const*)pool_data[type_index]); + else + _Jv_VerifyMethodSignature + ((_Jv_Utf8Const*)pool_data[type_index]); + + _Jv_Utf8Const* name = (_Jv_Utf8Const*)pool_data[name_index]; + + if (this_tag != JV_CONSTANT_Fieldref + && ( _Jv_equalUtf8Consts (name, clinit_name) + || _Jv_equalUtf8Consts (name, init_name))) + /* ignore */; + else + _Jv_VerifyIdentifier ((_Jv_Utf8Const*)pool_data[name_index]); + } + + _Jv_storeIndexes (&pool_data[index], class_index, nat_index); + pool_tags[index] = this_tag; + } + break; + + case JV_CONSTANT_NameAndType: + { + _Jv_ushort name_index = get2u (this_data); + _Jv_ushort type_index = get2u (this_data+2); + + check_tag (name_index, JV_CONSTANT_Utf8); + prepare_pool_entry (name_index, JV_CONSTANT_Utf8); + + check_tag (type_index, JV_CONSTANT_Utf8); + prepare_pool_entry (type_index, JV_CONSTANT_Utf8); + + _Jv_storeIndexes (&pool_data[index], name_index, type_index); + pool_tags[index] = JV_CONSTANT_NameAndType; + } + break; + + case JV_CONSTANT_Float: + { + jfloat f = int_bits_to_float ((jint) get4 (this_data)); + _Jv_storeFloat (&pool_data[index], f); + pool_tags[index] = JV_CONSTANT_Float; + } + break; + + case JV_CONSTANT_Integer: + { + int i = get4 (this_data); + _Jv_storeInt (&pool_data[index], i); + pool_tags[index] = JV_CONSTANT_Integer; + } + break; + + case JV_CONSTANT_Double: + { + jdouble d = long_bits_to_double ((jlong) get8 (this_data)); + _Jv_storeDouble (&pool_data[index], d); + pool_tags[index] = JV_CONSTANT_Double; + } + break; + + case JV_CONSTANT_Long: + { + jlong i = get8 (this_data); + _Jv_storeLong (&pool_data[index], i); + pool_tags[index] = JV_CONSTANT_Long; + } + break; + + default: + throw_class_format_error ("erroneous constant pool tag"); + } +} + + +void +_Jv_ClassReader::handleClassBegin + (int access_flags, int this_class, int super_class) +{ + unsigned char *pool_tags = (unsigned char*) def->constants.tags; + void **pool_data = (void**) def->constants.data; + + check_tag (this_class, JV_CONSTANT_Class); + _Jv_Utf8Const *loadedName = (_Jv_Utf8Const*)pool_data[this_class]; + + // was ClassLoader.defineClass called with an expected class name? + if (def->name == 0) + { + jclass orig = _Jv_FindClassInCache (loadedName, def->loader); + + if (orig == 0) + { + def->name = loadedName; + } + else + { + jstring msg = JvNewStringUTF ("anonymous " + "class data denotes " + "existing class "); + msg = msg->concat (orig->getName ()); + + throw_no_class_def_found_error (msg); + } + } + + // assert that the loaded class has the expected name, 5.3.5 + else if (! _Jv_equalUtf8Consts (loadedName, def->name)) + { + jstring msg = JvNewStringUTF ("loaded class "); + msg = msg->concat (def->getName ()); + msg = msg->concat (_Jv_NewStringUTF (" was in fact named ")); + jstring klass_name = _Jv_NewStringUTF (loadedName->data); + msg = msg->concat (klass_name); + + throw_no_class_def_found_error (msg); + } + + def->accflags = access_flags; + pool_data[this_class] = (void*)def; + pool_tags[this_class] = JV_CONSTANT_ResolvedClass; + + if (super_class == 0) + { + // interfaces have java.lang.Object as super. + if (access_flags & INTERFACE) + { + def->superclass = (jclass)&ClassObject; + } + + // FIXME: Consider this carefully! + else if (!_Jv_equalUtf8Consts (def->name, ClassObject.name)) + { + throw_no_class_def_found_error ("loading java.lang.Object"); + } + } + + // In the pre-loading state, it can be looked up in the + // cache only by this thread! This allows the super-class + // to include references to this class. + + def->state = JV_STATE_PRELOADING; + _Jv_RegisterClass (def); + + if (super_class != 0) + { + // load the super class + check_tag (super_class, JV_CONSTANT_Class); + _Jv_Utf8Const* super_name = + (_Jv_Utf8Const*)pool_data[super_class]; + + // load the super class using our defining loader + jclass the_super = _Jv_FindClass (super_name, + def->loader); + + // This will establish that we are allowed to be a subclass, + // and check for class circularity error + checkExtends (def, the_super); + + def->superclass = the_super; + pool_data[super_class] = (void*) the_super; + pool_tags[super_class] = JV_CONSTANT_ResolvedClass; + } + + // now we've come past the circularity problem, we can + // now say that we're loading... + + def->state = JV_STATE_LOADING; + def->notifyAll (); +} + +///// implements the checks described in sect. 5.3.5.3 +void +_Jv_ClassReader::checkExtends (jclass sub, jclass super) +{ + // having an interface or a final class as a superclass is no good + if ((super->accflags & (INTERFACE | FINAL)) != 0) + { + throw_incompatible_class_change_error (sub->getName ()); + } + + // if the super class is not public, we need to check some more + if ((super->accflags & PUBLIC) == 0) + { + // With package scope, the classes must have the same + // class loader. + if ( sub->loader != super->loader + || !_Jv_ClassNameSamePackage (sub->name, super->name)) + { + throw_incompatible_class_change_error (sub->getName ()); + } + } + + for (; super != 0; super = super->superclass) + { + if (super == sub) + throw_class_circularity_error (sub->getName ()); + } +} + + + +void _Jv_ClassReader::handleInterfacesBegin (int count) +{ + def->interfaces = (jclass*) _Jv_AllocBytesChecked (count*sizeof (jclass)); + def->interface_count = count; +} + +void _Jv_ClassReader::handleInterface (int if_number, int offset) +{ + void ** pool_data = def->constants.data; + unsigned char * pool_tags = (unsigned char*) def->constants.tags; + + jclass the_interface; + + if (pool_tags[offset] == JV_CONSTANT_Class) + { + _Jv_Utf8Const* name = (_Jv_Utf8Const*) pool_data[offset]; + the_interface = _Jv_FindClass (name, def->loader); + } + else if (pool_tags[offset] == JV_CONSTANT_ResolvedClass) + { + the_interface = (jclass)pool_data[offset]; + } + else + { + throw_no_class_def_found_error ("erroneous constant pool tag"); + } + + // checks the validity of the_interface, and that we are in fact + // allowed to implement that interface. + checkImplements (def, the_interface); + + pool_data[offset] = (void*)the_interface; + pool_tags[offset] = JV_CONSTANT_ResolvedClass; + + def->interfaces[if_number] = the_interface; +} + +void +_Jv_ClassReader::checkImplements (jclass sub, jclass super) +{ + // well, it *must* be an interface + if ((super->accflags & INTERFACE) == 0) + { + throw_incompatible_class_change_error (sub->getName ()); + } + + // if it has package scope, it must also be defined by the + // same loader. + if ((super->accflags & PUBLIC) == 0) + { + if ( sub->loader != super->loader + || !_Jv_ClassNameSamePackage (sub->name, super->name)) + { + throw_incompatible_class_change_error (sub->getName ()); + } + } + + // FIXME: add interface circularity check here + if (sub == super) + { + throw_class_circularity_error (sub->getName ()); + } +} + +void _Jv_ClassReader::handleFieldsBegin (int count) +{ + def->fields = (_Jv_Field*) + _Jv_AllocBytesChecked (count * sizeof (_Jv_Field)); + def->field_count = count; + def->field_initializers = (_Jv_ushort*) + _Jv_AllocBytesChecked (count * sizeof (_Jv_ushort)); + for (int i = 0; i < count; i++) + def->field_initializers[i] = (_Jv_ushort) 0; +} + +void _Jv_ClassReader::handleField (int field_no, + int flags, + int name, + int desc) +{ + void **const pool_data = def->constants.data; + + _Jv_Field *field = &def->fields[field_no]; + _Jv_Utf8Const *field_name = (_Jv_Utf8Const*) pool_data[name]; + +#ifndef COMPACT_FIELDS + field->name = field_name; +#else + field->nameIndex = name; +#endif + + if (verify) + _Jv_VerifyIdentifier (field_name); + + // ignore flags we don't know about. + field->flags = flags & ALL_FLAGS; + + if (verify) + { + if (field->flags & (SYNCHRONIZED|NATIVE|INTERFACE|ABSTRACT)) + throw_class_format_error ("erroneous field access flags"); + + if (1 < ( ((field->flags & PUBLIC) ? 1 : 0) + +((field->flags & PRIVATE) ? 1 : 0) + +((field->flags & PROTECTED) ? 1 : 0))) + throw_class_format_error ("erroneous field access flags"); + } + + _Jv_Utf8Const* sig = (_Jv_Utf8Const*) pool_data[desc]; + + if (verify) + _Jv_VerifyFieldSignature (sig); + + // field->type is really a jclass, but while it is still + // unresolved we keep an _Jv_Utf8Const* instead. + field->type = (jclass) sig; + field->flags |= _Jv_FIELD_UNRESOLVED_FLAG; + field->u.boffset = 0; +} + + +void _Jv_ClassReader::handleConstantValueAttribute (int field_index, + int value) +{ + _Jv_Field *field = &def->fields[field_index]; + + if ((field->flags & (STATIC|FINAL|PRIVATE)) == 0) + { + // Ignore, as per vmspec #4.7.2 + return; + } + + // do not allow multiple constant fields! + if (field->flags & _Jv_FIELD_CONSTANT_VALUE) + throw_class_format_error ("field has multiple ConstantValue attributes"); + + field->flags |= _Jv_FIELD_CONSTANT_VALUE; + def->field_initializers[field_index] = value; + + /* type check the initializer */ + + if (value <= 0 || value >= pool_count) + throw_class_format_error ("erroneous ConstantValue attribute"); + + /* FIXME: do the rest */ +} + +void _Jv_ClassReader::handleFieldsEnd () +{ + // We need to reorganize the fields so that the static ones are first, + // to conform to GCJ class layout. + + int low = 0; + int high = def->field_count-1; + _Jv_Field *fields = def->fields; + _Jv_ushort *inits = def->field_initializers; + + // this is kind of a raw version of quicksort. + while (low < high) + { + // go forward on low, while it's a static + while (low < high && (fields[low].flags & STATIC) != 0) + low++; + + // go backwards on high, while it's a non-static + while (low < high && (fields[high].flags & STATIC) == 0) + high--; + + if (low==high) + break; + + _Jv_Field tmp = fields[low]; + _Jv_ushort itmp = inits[low]; + + fields[low] = fields[high]; + inits[low] = inits[high]; + + fields[high] = tmp; + inits[high] = itmp; + + high -= 1; + low += 1; + } + + if ((fields[low].flags & STATIC) != 0) + low += 1; + + def->static_field_count = low; +} + + + +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); + + for (int i = 0; i < count; i++) + def->interpreted_methods[i] = 0; + + def->method_count = count; +} + + +void _Jv_ClassReader::handleMethod + (int mth_index, int accflags, int name, int desc) +{ + void **const pool_data = def->constants.data; + _Jv_Method *method = &def->methods[mth_index]; + + check_tag (name, JV_CONSTANT_Utf8); + prepare_pool_entry (name, JV_CONSTANT_Utf8); + method->name = (_Jv_Utf8Const*)pool_data[name]; + + check_tag (desc, JV_CONSTANT_Utf8); + prepare_pool_entry (desc, JV_CONSTANT_Utf8); + method->signature = (_Jv_Utf8Const*)pool_data[desc]; + + // ignore unknown flags + method->accflags = accflags & ALL_FLAGS; + + // intialize... + method->ncode = 0; + + if (verify) + { + if (_Jv_equalUtf8Consts (method->name, clinit_name) + || _Jv_equalUtf8Consts (method->name, init_name)) + /* ignore */; + else + _Jv_VerifyIdentifier (method->name); + + _Jv_VerifyMethodSignature (method->signature); + + if (method->accflags & (VOLATILE|TRANSIENT|INTERFACE)) + throw_class_format_error ("erroneous method access flags"); + + if (1 < ( ((method->accflags & PUBLIC) ? 1 : 0) + +((method->accflags & PRIVATE) ? 1 : 0) + +((method->accflags & PROTECTED) ? 1 : 0))) + throw_class_format_error ("erroneous method access flags"); + } +} + +void _Jv_ClassReader::handleCodeAttribute + (int method_index, int max_stack, int max_locals, + int code_start, int code_length, int exc_table_length) +{ + int size = _Jv_InterpMethod::size (exc_table_length, code_length); + _Jv_InterpMethod *method = + (_Jv_InterpMethod*) (_Jv_AllocBytesChecked (size)); + + method->max_stack = max_stack; + method->max_locals = max_locals; + method->code_length = code_length; + method->exc_count = exc_table_length; + method->defining_class = def; + method->self = &def->methods[method_index]; + + // grab the byte code! + memcpy ((void*) method->bytecode (), + (void*) (bytes+code_start), + code_length); + + def->interpreted_methods[method_index] = method; + + /* that's all we do for now */ +} + +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_InterpException *exc = method->exceptions (); + + exc[exc_index].start_pc = start_pc; + exc[exc_index].end_pc = end_pc; + exc[exc_index].handler_pc = handler_pc; + exc[exc_index].handler_type = catch_type; +} + +void _Jv_ClassReader::handleMethodsEnd () +{ + for (int i = 0; i < def->method_count; i++) + { + _Jv_Method *method = &def->methods[i]; + if (method->accflags & (NATIVE|ABSTRACT)) + { + if (def->interpreted_methods[i] != 0) + throw_class_format_error ("code provided " + "for abstract or native method"); + } + else + { + if (def->interpreted_methods[i] == 0) + throw_class_format_error ("abstract or native method " + "with no code"); + } + } + +} + + +/** This section takes care of verifying integrity of identifiers, + signatures, field ddescriptors, and class names */ + +#define UTF8_PEEK(PTR, LIMIT) \ + ({ unsigned char* xxkeep = (PTR); \ + int xxch = UTF8_GET(PTR,LIMIT); \ + PTR = xxkeep; xxch; }) + +/* verify one element of a type descriptor or signature */ +static unsigned char* +_Jv_VerifyOne (unsigned char* ptr, unsigned char* limit, bool void_ok) +{ + if (ptr >= limit) + return 0; + + int ch = UTF8_GET (ptr, limit); + + switch (ch) + { + case 'V': + if (! void_ok) return 0; + + case 'S': case 'B': case 'I': case 'J': + case 'Z': case 'C': case 'F': case 'D': + break; + + case 'L': + { + unsigned char *start = ptr, *end; + do { + if (ptr > limit) + return 0; + + end = ptr; + + if ((ch = UTF8_GET (ptr, limit)) == -1) + return 0; + + } while (ch != ';'); + _Jv_VerifyClassName (start, (unsigned short) (end-start)); + } + break; + + case '[': + return _Jv_VerifyOne (ptr, limit, false); + break; + + default: + return 0; + } + + return ptr; + +} + + +/** verification and loading procedures **/ + +void +_Jv_VerifyFieldSignature (_Jv_Utf8Const*sig) +{ + unsigned char* ptr = (unsigned char*) sig->data; + unsigned char* limit = ptr + sig->length; + + ptr = _Jv_VerifyOne (ptr, limit, false); + + if (ptr != limit) + throw_class_format_error ("erroneous type descriptor"); +} + +void +_Jv_VerifyMethodSignature (_Jv_Utf8Const*sig) +{ + unsigned char* ptr = (unsigned char*) sig->data; + unsigned char* limit = ptr + sig->length; + + if (ptr == limit) + throw_class_format_error ("erroneous type descriptor"); + + if (UTF8_GET(ptr,limit) != '(') + throw_class_format_error ("erroneous type descriptor"); + + while (ptr && UTF8_PEEK (ptr, limit) != ')') + ptr = _Jv_VerifyOne (ptr, limit, false); + + if (UTF8_GET (ptr, limit) != ')') + throw_class_format_error ("erroneous type descriptor"); + + // get the return type + ptr = _Jv_VerifyOne (ptr, limit, true); + + if (ptr != limit) + throw_class_format_error ("erroneous type descriptor"); + + return; + +} + +/* we try to avoid calling the Character methods all the time, + in fact, they will only be called for non-standard things */ + +static __inline__ int +is_identifier_start (int c) +{ + unsigned int ch = (unsigned)c; + + if ((ch - 0x41U) < 29U) /* A ... Z */ + return 1; + if ((ch - 0x61U) < 29U) /* a ... z */ + return 1; + if (ch == 0x5FU) /* _ */ + return 1; + + return character->isJavaIdentifierStart ((jchar) ch); +} + +static __inline__ int +is_identifier_part (int c) +{ + unsigned int ch = (unsigned)c; + + if ((ch - 0x41U) < 29U) /* A ... Z */ + return 1; + if ((ch - 0x61U) < 29U) /* a ... z */ + return 1; + if ((ch - 0x30) < 10U) /* 0 .. 9 */ + return 1; + if (ch == 0x5FU || ch == 0x24U) /* _ $ */ + return 1; + + return character->isJavaIdentifierStart ((jchar) ch); +} + +void +_Jv_VerifyIdentifier (_Jv_Utf8Const* name) +{ + unsigned char *ptr = (unsigned char*) name->data; + unsigned char *limit = ptr + name->length; + int ch; + + if ((ch = UTF8_GET (ptr, limit))==-1 + || ! is_identifier_start (ch)) + throw_class_format_error ("erroneous identifier"); + + while (ptr != limit) + { + if ((ch = UTF8_GET (ptr, limit))==-1 + || ! is_identifier_part (ch)) + throw_class_format_error ("erroneous identifier"); + } +} + + +void +_Jv_VerifyClassName (unsigned char* ptr, _Jv_ushort length) +{ + unsigned char *limit = ptr+length; + int ch; + + next_level: + do { + if ((ch = UTF8_GET (ptr, limit))==-1) + throw_class_format_error ("erroneous class name"); + if (! is_identifier_start (ch)) + throw_class_format_error ("erroneous class name"); + do { + if (ptr == limit) + return; + else if ((ch = UTF8_GET (ptr, limit))==-1) + throw_class_format_error ("erroneous class name"); + else if (ch == '.') + goto next_level; + else if (! is_identifier_part (ch)) + throw_class_format_error ("erroneous class name"); + } while (true); + } while (true); + +} + +void +_Jv_VerifyClassName (_Jv_Utf8Const *name) +{ + _Jv_VerifyClassName ((unsigned char*)&name->data[0], + (_Jv_ushort) name->length); +} + + +/** returns true, if name1 and name2 represents classes in the same + package. */ + +bool +_Jv_ClassNameSamePackage (_Jv_Utf8Const *name1, _Jv_Utf8Const *name2) +{ + unsigned char* ptr1 = (unsigned char*) name1->data; + unsigned char* limit1 = ptr1 + name1->length; + + unsigned char* last1 = ptr1; + + // scan name1, and find the last occurrence of '.' + while (ptr1 < limit1) { + int ch1 = UTF8_GET (ptr1, limit1); + + if (ch1 == '.') + last1 = ptr1; + + else if (ch1 == -1) + return false; + } + + // now the length of name1's package name is len + int len = last1 - (unsigned char*) name1->data; + + // if this is longer than name2, then we're off + if (len > name2->length) + return false; + + // then compare the first len bytes for equality + if (memcmp ((void*) name1->data, (void*) name2->data, len) == 0) + { + // check that there are no .'s after position len in name2 + + unsigned char* ptr2 = (unsigned char*) name2->data + len; + unsigned char* limit2 = + (unsigned char*) name2->data + name2->length; + + while (ptr2 < limit2) + { + int ch2 = UTF8_GET (ptr2, limit2); + if (ch2 == -1 || ch2 == '.') + return false; + } + return true; + } + return false; +} + + + +/** Here we define the exceptions that can be thrown */ + +static void +throw_no_class_def_found_error (jstring msg) +{ + if (msg == 0) + JvThrow (new java::lang::NoClassDefFoundError); + else + JvThrow (new java::lang::NoClassDefFoundError (msg)); +} + +static void +throw_no_class_def_found_error (char *msg) +{ + throw_no_class_def_found_error (JvNewStringLatin1 (msg)); +} + +static void +throw_class_format_error (jstring msg) +{ + if (msg == 0) + JvThrow (new java::lang::ClassFormatError); + else + JvThrow (new java::lang::ClassFormatError (msg)); +} + +static void +throw_class_format_error (char *msg) +{ + throw_class_format_error (JvNewStringLatin1 (msg)); +} + +static void +throw_internal_error (char *msg) +{ + JvThrow + (new java::lang::InternalError (JvNewStringLatin1 (msg))); +} + +static jfloat int_bits_to_float (jint value) +{ + return java::lang::Float::intBitsToFloat (value); +} + +static jdouble long_bits_to_double (jlong value) +{ + return java::lang::Double::longBitsToDouble (value); +} + +static void throw_incompatible_class_change_error (jstring msg) +{ + JvThrow (new java::lang::IncompatibleClassChangeError (msg)); +} + +static void throw_class_circularity_error (jstring msg) +{ + JvThrow (new java::lang::ClassCircularityError (msg)); +} + +#endif /* INTERPRETER */ + diff --git a/libjava/gij.cc b/libjava/gij.cc new file mode 100644 index 0000000..f29e825 --- /dev/null +++ b/libjava/gij.cc @@ -0,0 +1,27 @@ +/* Copyright (C) 1999 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. */ + +/* Author: Kresten Krab Thorup <krab@gnu.org> */ + +#include <jvm.h> +#include <cni.h> +#include <stdio.h> + +#include <java/lang/System.h> +#include <java/util/Properties.h> + +int main (int argc, const char **argv) +{ + if (argc < 2) + { + printf ("usage: %s <class name> args\n", argv[0]); + exit (1); + } + + JvRunMain (0, argc, argv); +} diff --git a/libjava/gnu/gcj/runtime/MethodInvocation.java b/libjava/gnu/gcj/runtime/MethodInvocation.java new file mode 100644 index 0000000..d1664ba --- /dev/null +++ b/libjava/gnu/gcj/runtime/MethodInvocation.java @@ -0,0 +1,32 @@ +// MethodInvocation.java - wrapper used by the interpreter. +// (the native method is implemented in interpret.cc) + +/* Copyright (C) 1999 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. */ + +/* Author: Kresten Krab Thorup <krab@gnu.org> */ + +package gnu.gcj.runtime; + +import gnu.gcj.RawData; + +final class MethodInvocation { + + private static Throwable continue0 (RawData meth, RawData inv) + { + try { + continue1 (meth, inv); + } catch (Throwable ex) { + return ex; + } + return null; + } + + private static native void continue1 (RawData meth, RawData inv); + +} diff --git a/libjava/gnu/gcj/util/path/CacheEntry.java b/libjava/gnu/gcj/util/path/CacheEntry.java new file mode 100644 index 0000000..949200b --- /dev/null +++ b/libjava/gnu/gcj/util/path/CacheEntry.java @@ -0,0 +1,65 @@ +// CacheEntry.java -- directory cache + +/* Copyright (C) 1999 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. */ + +/* Author: Kresten Krab Thorup <krab@gnu.org> */ + +package gnu.gcj.util.path; + +import java.util.*; +import java.util.zip.*; +import java.io.*; +import java.net.*; + + +final class CacheEntry { + String dir; + String[] files; + long time; + + CacheEntry (String d) + { + dir = d; + files = new File(dir).list(); + time = System.currentTimeMillis (); + } + + void touch () + { + time = System.currentTimeMillis (); + } + + final long EXPIRATION_TIME_MS = 1000; + + boolean is_old () { + return (System.currentTimeMillis () - time) > EXPIRATION_TIME_MS; + } + + public int hashCode () { return dir.hashCode(); } + boolean contains (String file) { + if (files == null) + return false; + + int index = file.lastIndexOf(SearchPath.file_seperator_char); + String f; + + if (index == -1) + f = file; + else + f = file.substring (index+1); + + for (int i = 0; i < files.length; i++) + { + if (f.equals (files[i])) return true; + } + + return false; + } +} + diff --git a/libjava/gnu/gcj/util/path/DirectoryPathEntry.java b/libjava/gnu/gcj/util/path/DirectoryPathEntry.java new file mode 100644 index 0000000..a9ca602 --- /dev/null +++ b/libjava/gnu/gcj/util/path/DirectoryPathEntry.java @@ -0,0 +1,136 @@ +// DirectoryPathEntry.java -- search path element for directories + +/* Copyright (C) 1999 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. */ + +/* Author: Kresten Krab Thorup <krab@gnu.org> */ + +package gnu.gcj.util.path; + +import java.util.*; +import java.util.zip.*; +import java.io.*; +import java.net.*; + +final class DirectoryPathEntry extends PathEntry +{ + final File dir; + final String base_canon; + + public String toString () { return base_canon; } + + DirectoryPathEntry (File f) + throws java.io.IOException + { + if (!f.isAbsolute ()) + throw new IllegalArgumentException (); + + dir = f; + base_canon = dir.getCanonicalPath (); + } + + /* + * We maintain a cache of files, so that we + * can avoid many calls to stat(), which are + * very expensive. + * + * seen_cache contains (as keys) the directories + * which we have visited so far. The values are + * instances of CacheEntry, containing a time stamp, + * and a list of files in that directory. + * + */ + + private Hashtable seen_cache = new Hashtable (); + + private boolean in_cache (File f) + { + String rel_dir = f.getParent (); + CacheEntry ent; + + if (rel_dir == null) + throw new IllegalArgumentException (); + + ent = (CacheEntry) seen_cache.get (rel_dir); + if (ent == null) + { + ent = new CacheEntry (rel_dir); + seen_cache.put (rel_dir, ent); + } + + if (ent.contains (f.getPath ())) + { + return true; + } + + if ( ent.is_old () ) + { + if (f.exists ()) + { + seen_cache.remove (rel_dir); + return true; + } + else + { + ent.touch (); + } + } + + return false; + } + + URL getURL (String file) { + try { + File f = new File((new File (dir, file).getCanonicalPath ())); + + if (! f.getCanonicalPath ().startsWith (base_canon)) + throw new IllegalArgumentException (file); + + + if (in_cache (f)) + return new URL ("file", "", f.getPath ()); + else + return null; + + } catch (IOException x) { + return null; + } + } + + InputStream getStream (String file) { + try { + File f = new File((new File (dir, file)).getCanonicalPath ()); + + if (! f.getCanonicalPath ().startsWith (base_canon)) + throw new IllegalArgumentException (file); + + if (in_cache (f)) + return new FileInputStream (f); + else + return null; + } catch (IOException x) { + return null; + } + } + + byte[] getBytes (String file) { + File f = new File (dir, file); + + try { + if (in_cache (f)) + return readbytes (new FileInputStream (f), + (int) f.length ()); + else + return null; + } catch (IOException x) { + return null; + } + } + +} + diff --git a/libjava/gnu/gcj/util/path/PathEntry.java b/libjava/gnu/gcj/util/path/PathEntry.java new file mode 100644 index 0000000..f83fc17 --- /dev/null +++ b/libjava/gnu/gcj/util/path/PathEntry.java @@ -0,0 +1,55 @@ +// PathEntry.java -- abstract element of search paths + +/* Copyright (C) 1999 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. */ + +/* Author: Kresten Krab Thorup <krab@gnu.org> */ + +package gnu.gcj.util.path; + +import java.util.*; +import java.util.zip.*; +import java.io.*; +import java.net.*; + +abstract class PathEntry { + abstract URL getURL (String file); + abstract InputStream getStream (String file); + abstract byte[] getBytes (String file); + + /** + * Utility routine like InputStream.read(byte[], 0, len), but will + * read fully, even if all the data is not available at once. + */ + protected static byte[] readbytes (InputStream is, int length) + { + try { + + byte[] data = new byte[length]; + int read; + int off = 0; + + while (off != length) + { + read = is.read (data, off, (int) (length-off)); + + if (read == -1) + return null; + + off += read; + } + + return data; + } catch (IOException x) { + return null; + } + } + +} + + diff --git a/libjava/gnu/gcj/util/path/SearchPath.java b/libjava/gnu/gcj/util/path/SearchPath.java new file mode 100644 index 0000000..ffc2ca8 --- /dev/null +++ b/libjava/gnu/gcj/util/path/SearchPath.java @@ -0,0 +1,205 @@ +// SearchPath.java -- generic search path utility + +/* Copyright (C) 1999 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. */ + +/* Author: Kresten Krab Thorup <krab@gnu.org> */ + + +package gnu.gcj.util.path; + +import java.util.*; +import java.util.zip.*; +import java.io.*; +import java.net.*; + +final public class SearchPath { + + final static String path_seperator + = System.getProperty ("path.separator"); + final static char path_seperator_char + = path_seperator.charAt (0); + final static String file_seperator + = System.getProperty ("file.separator"); + final static char file_seperator_char + = file_seperator.charAt (0); + + private Vector path; + + /** + * Constructs a SearchPath object, given a system path. + * The system path is expected to be seperated by the string + * defined by the <code>path.seperator</code> property. + * (<code>":"</code> on unix, <code>;</code> on Windows, etc.). + * The path may contain names of directories, or names of + * .zip or .jar files. Elements that are neither of these + * are ignored. + * @param sys_path the search path + */ + + SearchPath (String sys_path) + { + StringTokenizer st = new StringTokenizer (sys_path, path_seperator); + init (st); + } + + /** + * Constructs a SearchPath object, given a Vector of + * <code>String</code>, <code>File</code> or <code>URL</code> + * objects. + * The path may contain names of directories, or names of + * .zip or .jar files. Elements that are neither of these + * are ignored. + * @param p the vector of search path elements + */ + + SearchPath (Vector p) + { + init (p.elements ()); + } + + public URL getURL (String element) + { + URL result; + + Enumeration e = path.elements (); + while (e.hasMoreElements ()) + { + PathEntry ent = (PathEntry) e.nextElement (); + + result = ent.getURL (element); + + if (result != null) + { + return result; + } + } + + return null; + } + + + public InputStream getStream (String element) + { + InputStream result; + + Enumeration e = path.elements (); + while (e.hasMoreElements ()) + { + PathEntry ent = (PathEntry) e.nextElement (); + + result = ent.getStream (element); + + if (result != null) + { + return result; + } + } + + return null; + } + + + public byte[] getBytes (String element) + { + byte[] result; + + Enumeration e = path.elements (); + while (e.hasMoreElements ()) + { + PathEntry ent = (PathEntry) e.nextElement (); + result = ent.getBytes (element); + if (result != null) + { + System.out.println ("loading " + ent + + "(" + element + ")"); + return result; + } + } + + return null; + } + + + + private void init (Enumeration st) + { + path = new Vector (); + while (st.hasMoreElements ()) + { + Object e = st.nextElement (); + + String elem; + File efile; + + if (e instanceof URL) + { + path.addElement (new URLPathEntry ((URL) e)); + continue; + } + + if (e instanceof File) + { + efile = (File) e; + elem = efile.getPath (); + } + + else if (e instanceof String) + { + elem = (String) e; + efile = new File (elem); + } + + else + throw new IllegalArgumentException (); + + // make sure it is absolute, so we won't get + // trouble if the cwd is changed... + if (! efile.isAbsolute ()) + efile = new File (efile.getAbsolutePath ()); + + if (efile.isDirectory ()) + { + try { + path.addElement(new DirectoryPathEntry (efile)); + } catch (IOException x) { + /* ignore for now */ + } + } + + else if (efile.isFile ()) + { + int ext = elem.lastIndexOf ('.'); + if (ext == -1) + continue; + + if (!elem.substring(ext+1).equalsIgnoreCase("zip")) + continue; + + ZipPathEntry zpe = null; + try { + zpe = new ZipPathEntry (efile); + } catch (ZipException zx) { + System.err.println ("SearchPath::ZipException"); + zpe = null; + } catch (MalformedURLException mx) { + System.err.println ("SearchPath::URLException"); + zpe = null; + } catch (IOException iox) { + System.err.println ("SearchPath::IOException"); + zpe = null; + } + if (zpe != null) path.addElement (zpe); + } + } + + } + + +} + diff --git a/libjava/gnu/gcj/util/path/URLPathEntry.java b/libjava/gnu/gcj/util/path/URLPathEntry.java new file mode 100644 index 0000000..68f9200 --- /dev/null +++ b/libjava/gnu/gcj/util/path/URLPathEntry.java @@ -0,0 +1,67 @@ +// URLPathEntry.java -- search path element for URL's + +/* Copyright (C) 1999 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. */ + +/* Author: Kresten Krab Thorup <krab@gnu.org> */ + +package gnu.gcj.util.path; + +import java.util.*; +import java.util.zip.*; +import java.io.*; +import java.net.*; + +final class URLPathEntry extends PathEntry { + final URL base; + + URLPathEntry (URL f) { + base = f; + } + + public String toString () { return base.toString (); } + + URL getURL (String file) { + + try { + URL res = new URL (base, file); + InputStream is = res.openStream (); // exc if not found + is.close (); + return res; + } catch (java.io.IOException x) { + return null; + } + } + + InputStream getStream (String file) { + + try { + URL res = new URL (base, file); + return res.openStream (); + } catch (java.io.IOException x) { + return null; + } + + } + + byte[] getBytes (String file) { + + try { + URL res = new URL (base, file); + URLConnection conn = res.openConnection (); + int len = conn.getContentLength (); + if (len == -1) return null; + return readbytes (conn.getInputStream (), len); + } catch (java.io.IOException x) { + return null; + } + + } + +} + diff --git a/libjava/gnu/gcj/util/path/ZipPathEntry.java b/libjava/gnu/gcj/util/path/ZipPathEntry.java new file mode 100644 index 0000000..ac02262 --- /dev/null +++ b/libjava/gnu/gcj/util/path/ZipPathEntry.java @@ -0,0 +1,86 @@ +// ZipPathEntry.java -- search path element for directories + +/* Copyright (C) 1999 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. */ + +/* Author: Kresten Krab Thorup <krab@gnu.org> */ + +package gnu.gcj.util.path; + +import java.util.*; +import java.util.zip.*; +import java.io.*; +import java.net.*; + + +final class ZipPathEntry extends PathEntry { + final ZipFile zip; + final URL file; + + public String toString () { return zip.getName (); } + + ZipPathEntry (File f) + throws MalformedURLException, ZipException, IOException + { + file = new URL ("file", "", f.getPath ()); + zip = new ZipFile (f); + zip.readDirectory (); + } + + /* + The url for a zip-file resource is, + + <code>file:///path/file.zip#name</code> + + Then, it is URLConnection's problem to handle that. + */ + + URL getURL (String f) { + + ZipEntry ent = zip.getEntry (f); + + try { + if (ent != null) + return new URL (file, "#"+f); + else + return null; + } catch (IOException x) { + return null; + } + } + + InputStream getStream (String f) { + + ZipEntry ent = zip.getEntry (f); + + try { + if (ent != null) + return zip.getInputStream (ent); + else + return null; + } catch (IOException x) { + return null; + } + } + + byte[] getBytes (String f) { + ZipEntry ent = zip.getEntry (f); + + try { + if (ent != null) + return readbytes (zip.getInputStream (ent), + (int) ent.getSize ()); + else + return null; + } catch (IOException x) { + return null; + } + + } +} + diff --git a/libjava/include/config.h.in b/libjava/include/config.h.in index d9b9a0a..03f51ba 100644 --- a/libjava/include/config.h.in +++ b/libjava/include/config.h.in @@ -106,6 +106,9 @@ #undef HAVE_GETHOSTBYNAME_R #undef HAVE_GETHOSTBYADDR_R +/* Define if you want a bytecode interpreter. */ +#undef INTERPRETER + /* Define if you have the access function. */ #undef HAVE_ACCESS diff --git a/libjava/include/java-cpool.h b/libjava/include/java-cpool.h new file mode 100644 index 0000000..f4d7ef99 --- /dev/null +++ b/libjava/include/java-cpool.h @@ -0,0 +1,173 @@ +// java-cpool.h - Constant pool parsing header. -*- c++ -*- + +/* Copyright (C) 1999 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. */ + +#ifndef __JAVA_CPOOL_H__ +#define __JAVA_CPOOL_H__ + +#include <javaprims.h> + +// we rename these, to avoid polluting the name space +#define JV_CONSTANT_Undefined (0L) +#define JV_CONSTANT_Utf8 (1L) +#define JV_CONSTANT_Unicode (2L) +#define JV_CONSTANT_Integer (3L) +#define JV_CONSTANT_Float (4L) +#define JV_CONSTANT_Long (5L) +#define JV_CONSTANT_Double (6L) +#define JV_CONSTANT_Class (7L) +#define JV_CONSTANT_String (8L) +#define JV_CONSTANT_Fieldref (9L) +#define JV_CONSTANT_Methodref (10L) +#define JV_CONSTANT_InterfaceMethodref (11L) +#define JV_CONSTANT_NameAndType (12L) +#define JV_CONSTANT_ResolvedFlag (16L) +#define JV_CONSTANT_ResolvedString (16L | 8L) +#define JV_CONSTANT_ResolvedClass (16L | 7L) + +/* We use the following two operations uniformly for all put/get operations + * in the runtime system (constant pool & stack), to assure that we keep + * everything in the same format. The idea is, that these should be inlined + * away, into just a simple store (for small data types, and a pair of stores + * if double or long has alignment greater than void *. On an 64-bit + * architecture, all operations should be simple stores; on a 32-bit + * architecture it depends on the alignment requirement for the specific + * type. */ + +template <class T> +static inline void _Jv_put (void *dst, T value) +{ +#if 0 + if (sizeof (T) == 8 && __alignof__ (T) > __alignof__ (void*)) + { + jint *v_dst = (jint*)(dst); + jint *v_src = (jint*)&value; + + v_dst[0] = v_src[0]; + v_dst[1] = v_src[1]; + } + else +#endif + { + *((T*) (dst)) = value; + } +} + +template <class T> +static inline T _Jv_get (void *src) +{ +#if 0 + if (sizeof (T) == 8 && __alignof__ (T) > __alignof__ (void*)) + { + T value; + jint *v_dst = (jint*)&value; + jint *v_src = (jint*)src; + + v_dst[0] = v_src[0]; + v_dst[1] = v_src[1]; + + return value; + } + else +#endif + { + return *((T*) (src)); + } +} + +/** needed to keep the CONSTANT_XXXRef & CONSTANT_NameAndType entries */ +extern inline void +_Jv_storeIndexes (void **data, + _Jv_ushort index0, + _Jv_ushort index1) +{ + // accomodate 64bit machines... + if (sizeof (void*) == (2 * sizeof (jint))) + { + ((jint*)data)[0] = index0; + ((jint*)data)[1] = index0; + } + else + { + _Jv_put<jint>(data, ((jint)index0 << 16) | (jint)index1); + } +} + +extern inline void +_Jv_loadIndexes (const void **data, + _Jv_ushort& index0, + _Jv_ushort& index1) +{ + if (sizeof (void*) == (2*sizeof (jint))) + { + index0 = ((jint*)data)[0]; + index0 = ((jint*)data)[1]; + } + else + { + jint udata = _Jv_get<jint>(data); + + _Jv_uint uindex0 = ((udata >> 16) & 0xffff); + _Jv_uint uindex1 = udata & 0xffff; + + index0 = uindex0; + index1 = uindex1; + } +} + +extern inline void +_Jv_storeFloat (void **data, jfloat f) +{ + _Jv_put<jfloat>(data, f); +} + +extern inline jfloat +_Jv_loadFloat (void **data) +{ + return _Jv_get<jfloat>(data); +} + +extern inline void +_Jv_storeInt (void **data, jint i) +{ + _Jv_put<jint>(data, i); +} + +extern inline jint +_Jv_loadInt (void **data) +{ + return _Jv_get<jint>(data); +} + +extern inline void +_Jv_storeLong (void **data, jlong l) +{ + return _Jv_put<jlong>(data, l); +} + +extern inline jlong +_Jv_loadLong (void **data) +{ + return _Jv_get<jlong>(data); +} + +extern inline void +_Jv_storeDouble (void **data, jdouble d) +{ + _Jv_put<jdouble>(data, d); +} + +extern inline jdouble +_Jv_loadDouble (void **data) +{ + return _Jv_get<jdouble> (data); +} + + +#endif /* __JAVA_CPOOL_H__ */ diff --git a/libjava/include/java-field.h b/libjava/include/java-field.h index b4529fc..d00d9ce 100644 --- a/libjava/include/java-field.h +++ b/libjava/include/java-field.h @@ -53,7 +53,18 @@ struct _Jv_Field jfieldID getNextInstanceField () { return this + 1; } - jboolean isRef () { return ! isResolved () || ! type->isPrimitive (); } + jboolean isRef () + { + if (!isResolved ()) + { + char first = ((_Jv_Utf8Const*)type)->data[0]; + return first == '[' || first == 'L'; + } + else + { + return ! type->isPrimitive (); + } + } // FIXME - may need to mask off internal flags. int getModifiers() { return flags; } diff --git a/libjava/include/java-insns.h b/libjava/include/java-insns.h new file mode 100644 index 0000000..8b19abd --- /dev/null +++ b/libjava/include/java-insns.h @@ -0,0 +1,247 @@ +// java-insns.h - Instruction encodings. This is -*- c++ -*- + +/* Copyright (C) 1999 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. */ + +static const int op_nop = 0x00; +static const int op_aconst_null = 0x01; +static const int op_iconst_m1 = 0x02; +static const int op_iconst_0 = 0x03; +static const int op_iconst_1 = 0x04; +static const int op_iconst_2 = 0x05; +static const int op_iconst_3 = 0x06; +static const int op_iconst_4 = 0x07; +static const int op_iconst_5 = 0x08; +static const int op_lconst_0 = 0x09; +static const int op_lconst_1 = 0x0a; +static const int op_fconst_0 = 0x0b; +static const int op_fconst_1 = 0x0c; +static const int op_fconst_2 = 0x0d; +static const int op_dconst_0 = 0x0e; +static const int op_dconst_1 = 0x0f; +static const int op_bipush = 0x10; +static const int op_sipush = 0x11; +static const int op_ldc = 0x12; +static const int op_ldc_w = 0x13; +static const int op_ldc2_w = 0x14; +static const int op_iload = 0x15; +static const int op_lload = 0x16; +static const int op_fload = 0x17; +static const int op_dload = 0x18; +static const int op_aload = 0x19; +static const int op_iload_0 = 0x1a; +static const int op_iload_1 = 0x1b; +static const int op_iload_2 = 0x1c; +static const int op_iload_3 = 0x1d; +static const int op_lload_0 = 0x1e; +static const int op_lload_1 = 0x1f; +static const int op_lload_2 = 0x20; +static const int op_lload_3 = 0x21; +static const int op_fload_0 = 0x22; +static const int op_fload_1 = 0x23; +static const int op_fload_2 = 0x24; +static const int op_fload_3 = 0x25; +static const int op_dload_0 = 0x26; +static const int op_dload_1 = 0x27; +static const int op_dload_2 = 0x28; +static const int op_dload_3 = 0x29; +static const int op_aload_0 = 0x2a; +static const int op_aload_1 = 0x2b; +static const int op_aload_2 = 0x2c; +static const int op_aload_3 = 0x2d; +static const int op_iaload = 0x2e; +static const int op_laload = 0x2f; +static const int op_faload = 0x30; +static const int op_daload = 0x31; +static const int op_aaload = 0x32; +static const int op_baload = 0x33; +static const int op_caload = 0x34; +static const int op_saload = 0x35; +static const int op_istore = 0x36; +static const int op_lstore = 0x37; +static const int op_fstore = 0x38; +static const int op_dstore = 0x39; +static const int op_astore = 0x3a; +static const int op_istore_0 = 0x3b; +static const int op_istore_1 = 0x3c; +static const int op_istore_2 = 0x3d; +static const int op_istore_3 = 0x3e; +static const int op_lstore_0 = 0x3f; +static const int op_lstore_1 = 0x40; +static const int op_lstore_2 = 0x41; +static const int op_lstore_3 = 0x42; +static const int op_fstore_0 = 0x43; +static const int op_fstore_1 = 0x44; +static const int op_fstore_2 = 0x45; +static const int op_fstore_3 = 0x46; +static const int op_dstore_0 = 0x47; +static const int op_dstore_1 = 0x48; +static const int op_dstore_2 = 0x49; +static const int op_dstore_3 = 0x4a; +static const int op_astore_0 = 0x4b; +static const int op_astore_1 = 0x4c; +static const int op_astore_2 = 0x4d; +static const int op_astore_3 = 0x4e; +static const int op_iastore = 0x4f; +static const int op_lastore = 0x50; +static const int op_fastore = 0x51; +static const int op_dastore = 0x52; +static const int op_aastore = 0x53; +static const int op_bastore = 0x54; +static const int op_castore = 0x55; +static const int op_sastore = 0x56; +static const int op_pop = 0x57; +static const int op_pop2 = 0x58; +static const int op_dup = 0x59; +static const int op_dup_x1 = 0x5a; +static const int op_dup_x2 = 0x5b; +static const int op_dup2 = 0x5c; +static const int op_dup2_x1 = 0x5d; +static const int op_dup2_x2 = 0x5e; +static const int op_swap = 0x5f; +static const int op_iadd = 0x60; +static const int op_ladd = 0x61; +static const int op_fadd = 0x62; +static const int op_dadd = 0x63; +static const int op_isub = 0x64; +static const int op_lsub = 0x65; +static const int op_fsub = 0x66; +static const int op_dsub = 0x67; +static const int op_imul = 0x68; +static const int op_lmul = 0x69; +static const int op_fmul = 0x6a; +static const int op_dmul = 0x6b; +static const int op_idiv = 0x6c; +static const int op_ldiv = 0x6d; +static const int op_fdiv = 0x6e; +static const int op_ddiv = 0x6f; +static const int op_irem = 0x70; +static const int op_lrem = 0x71; +static const int op_frem = 0x72; +static const int op_drem = 0x73; +static const int op_ineg = 0x74; +static const int op_lneg = 0x75; +static const int op_fneg = 0x76; +static const int op_dneg = 0x77; +static const int op_ishl = 0x78; +static const int op_lshl = 0x79; +static const int op_ishr = 0x7a; +static const int op_lshr = 0x7b; +static const int op_iushr = 0x7c; +static const int op_lushr = 0x7d; +static const int op_iand = 0x7e; +static const int op_land = 0x7f; +static const int op_ior = 0x80; +static const int op_lor = 0x81; +static const int op_ixor = 0x82; +static const int op_lxor = 0x83; +static const int op_iinc = 0x84; +static const int op_i2l = 0x85; +static const int op_i2f = 0x86; +static const int op_i2d = 0x87; +static const int op_l2i = 0x88; +static const int op_l2f = 0x89; +static const int op_l2d = 0x8a; +static const int op_f2i = 0x8b; +static const int op_f2l = 0x8c; +static const int op_f2d = 0x8d; +static const int op_d2i = 0x8e; +static const int op_d2l = 0x8f; +static const int op_d2f = 0x90; +static const int op_i2b = 0x91; +static const int op_i2c = 0x92; +static const int op_i2s = 0x93; +static const int op_lcmp = 0x94; +static const int op_fcmpl = 0x95; +static const int op_fcmpg = 0x96; +static const int op_dcmpl = 0x97; +static const int op_dcmpg = 0x98; +static const int op_ifeq = 0x99; +static const int op_ifne = 0x9a; +static const int op_iflt = 0x9b; +static const int op_ifge = 0x9c; +static const int op_ifgt = 0x9d; +static const int op_ifle = 0x9e; +static const int op_if_icmpeq = 0x9f; +static const int op_if_icmpne = 0xa0; +static const int op_if_icmplt = 0xa1; +static const int op_if_icmpge = 0xa2; +static const int op_if_icmpgt = 0xa3; +static const int op_if_icmple = 0xa4; +static const int op_if_acmpeq = 0xa5; +static const int op_if_acmpne = 0xa6; +static const int op_goto = 0xa7; +static const int op_jsr = 0xa8; +static const int op_ret = 0xa9; +static const int op_tableswitch = 0xaa; +static const int op_lookupswitch = 0xab; +static const int op_ireturn = 0xac; +static const int op_lreturn = 0xad; +static const int op_freturn = 0xae; +static const int op_dreturn = 0xaf; +static const int op_areturn = 0xb0; +static const int op_return = 0xb1; +static const int op_getstatic = 0xb2; +static const int op_putstatic = 0xb3; +static const int op_getfield = 0xb4; +static const int op_putfield = 0xb5; +static const int op_invokevirtual = 0xb6; +static const int op_invokespecial = 0xb7; +static const int op_invokestatic = 0xb8; +static const int op_invokeinterface = 0xb9; +static const int op_xxxunusedxxx1 = 0xba; +static const int op_new = 0xbb; +static const int op_newarray = 0xbc; +static const int op_anewarray = 0xbd; +static const int op_arraylength = 0xbe; +static const int op_athrow = 0xbf; +static const int op_checkcast = 0xc0; +static const int op_instanceof = 0xc1; +static const int op_monitorenter = 0xc2; +static const int op_monitorexit = 0xc3; +static const int op_wide = 0xc4; +static const int op_multianewarray = 0xc5; +static const int op_ifnull = 0xc6; +static const int op_ifnonnull = 0xc7; +static const int op_goto_w = 0xc8; +static const int op_jsr_w = 0xc9; + +// new opcodes + +static const int op_putfield_1 = 0xca; +static const int op_putfield_2 = 0xcb; +static const int op_putfield_4 = 0xcd; +static const int op_putfield_8 = 0xce; +static const int op_putfield_a = 0xcf; + +static const int op_putstatic_1 = 0xd0; +static const int op_putstatic_2 = 0xd1; +static const int op_putstatic_4 = 0xd2; +static const int op_putstatic_8 = 0xd3; +static const int op_putstatic_a = 0xd4; + +static const int op_getfield_1 = 0xd5; +static const int op_getfield_2s = 0xd6; +static const int op_getfield_2u = 0xd7; +static const int op_getfield_4 = 0xd8; +static const int op_getfield_8 = 0xd9; +static const int op_getfield_a = 0xda; + +static const int op_getstatic_1 = 0xdb; +static const int op_getstatic_2s = 0xdc; +static const int op_getstatic_2u = 0xdd; +static const int op_getstatic_4 = 0xde; +static const int op_getstatic_8 = 0xdf; +static const int op_getstatic_a = 0xe0; + +static const int op_invokefinal = 0xe1; +static const int op_invokevtable = 0xe2; + + + + diff --git a/libjava/include/java-interp.h b/libjava/include/java-interp.h new file mode 100644 index 0000000..70feec1 --- /dev/null +++ b/libjava/include/java-interp.h @@ -0,0 +1,172 @@ +// java-interp.h - Header file for the bytecode interpreter. -*- c++ -*- + +/* Copyright (C) 1999 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. */ + +#ifndef __JAVA_INTERP_H__ +#define __JAVA_INTERP_H__ + +#include <config.h> + +#include <jvm.h> +#include <java-cpool.h> + +#ifdef INTERPRETER + +#pragma interface + +#include <java/lang/Class.h> +#include <java/lang/ClassLoader.h> +#include <gnu/gcj/runtime/MethodInvocation.h> + +extern "C" { +#include <ffi.h> +} + +extern inline jboolean +_Jv_IsInterpretedClass (jclass c) +{ + return (c->loader != 0); +} + +struct _Jv_ResolvedMethod; + +void _Jv_VerifyFieldSignature (_Jv_Utf8Const*sig); +void _Jv_VerifyMethodSignature (_Jv_Utf8Const*sig); +void _Jv_VerifyClassName (unsigned char* ptr, _Jv_ushort length); +void _Jv_VerifyClassName (_Jv_Utf8Const *name); +void _Jv_VerifyIdentifier (_Jv_Utf8Const *); +bool _Jv_ClassNameSamePackage (_Jv_Utf8Const *name1, _Jv_Utf8Const *name2); +void _Jv_DefineClass (jclass, jbyteArray, jint, jint); +void _Jv_ResolveField (_Jv_Field *, java::lang::ClassLoader*); + +void _Jv_InitField (jobject, jclass, int); +void * _Jv_AllocMethodInvocation (jsize size); + +/* FIXME: this should really be defined in some more generic place */ +#define ROUND(V, A) (((((unsigned) (V))-1) | ((A)-1))+1) + +/* the interpreter is written in C++, primarily because it makes it easy for + * the entire thing to be "friend" with class Class. */ + +class _Jv_InterpClass; +class _Jv_InterpMethod; +class _Jv_InterpMethodInvocation; + +class _Jv_InterpException { + int start_pc; + int end_pc; + int handler_pc; + int handler_type; + + friend class _Jv_ClassReader; + friend class _Jv_InterpMethod; +}; + +class _Jv_InterpMethod { + + _Jv_ushort max_stack; + _Jv_ushort max_locals; + int code_length; + + _Jv_ushort exc_count; + _Jv_ushort args_raw_size; + + _Jv_InterpClass *defining_class; + _Jv_Method *self; + + unsigned char* bytecode () + { + return + ((unsigned char*)this) + + ROUND((sizeof (_Jv_InterpMethod) + + exc_count*sizeof (_Jv_InterpException)), 4); + } + + _Jv_InterpException * exceptions () + { + return (_Jv_InterpException*) (this+1); + } + + static size_t size (int exc_count, int code_length) + { + return + ROUND ((sizeof (_Jv_InterpMethod) + + (exc_count * sizeof (_Jv_InterpException))), 4) + + code_length; + } + + // return the method's invocation pointer (a stub). + void *ncode (); + void continue1 (_Jv_InterpMethodInvocation *inv); + + static void run_normal (ffi_cif*, void*, void**, void*); + static void run_synch_object (ffi_cif*, void*, void**, void*); + static void run_synch_class (ffi_cif*, void*, void**, void*); + + inline jobject run (ffi_cif*, void*, void**, + _Jv_InterpMethodInvocation*); + + bool find_exception (jobject ex, + _Jv_InterpMethodInvocation *inv); + + public: + static void dump_object(jobject o); + + friend class _Jv_ClassReader; + friend class _Jv_InterpMethodInvocation; + friend class gnu::gcj::runtime::MethodInvocation; + + friend void _Jv_PrepareClass(jclass); + + friend void _Jv_callInterpretedMethod (ffi_cif*, + void*, + void **, + void*); +}; + +class _Jv_InterpMethodInvocation { + _Jv_InterpMethod *running; + void **sp; + unsigned char *pc; + void* state[0]; + + void** stack_base () { return &state[0]; } + void** local_base () { return &state[running->max_stack]; } + + friend class _Jv_InterpMethod; +}; + +class _Jv_InterpClass : public java::lang::Class +{ + _Jv_InterpMethod **interpreted_methods; + _Jv_ushort *field_initializers; + + friend class _Jv_ClassReader; + friend class _Jv_InterpMethod; + friend void _Jv_PrepareClass(jclass); + friend void _Jv_InitField (jobject, jclass, int); + friend void* _Jv_MarkObj (void *, void *, void *, void *); +}; + +struct _Jv_ResolvedMethod { + jint stack_item_count; + jint vtable_index; + jclass klass; + _Jv_Method* method; + + // a resolved method holds the cif in-line, so that _Jv_MarkObj just needs + // to mark the resolved method to hold on to the cif. Some memory could be + // saved by keeping a cache of cif's, since many will be the same. + ffi_cif cif; + ffi_type * arg_types[0]; +}; + +#endif /* INTERPRETER */ + +#endif /* __JAVA_INTERP_H__ */ diff --git a/libjava/include/javaprims.h b/libjava/include/javaprims.h index 98781ad..9d8c0a6 100644 --- a/libjava/include/javaprims.h +++ b/libjava/include/javaprims.h @@ -162,6 +162,7 @@ extern "Java" class VerifyError; class VirtualMachineError; class Void; + class VMClassLoader; namespace reflect { class AccessibleObject; diff --git a/libjava/include/jvm.h b/libjava/include/jvm.h index 75ca827..34da0ed 100644 --- a/libjava/include/jvm.h +++ b/libjava/include/jvm.h @@ -40,6 +40,8 @@ extern int _Jv_strLengthUtf8(char* str, int len); typedef struct _Jv_Utf8Const Utf8Const; _Jv_Utf8Const *_Jv_makeUtf8Const (char *s, int len); +_Jv_Utf8Const *_Jv_makeUtf8TypeConst (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); @@ -91,6 +93,8 @@ extern "C" void *_Jv_LookupInterfaceMethod (jclass klass, Utf8Const *name, extern "C" void _Jv_CheckArrayStore (jobject array, jobject obj); extern "C" void _Jv_RegisterClass (jclass klass); extern "C" void _Jv_RegisterClasses (jclass *classes); +extern void _Jv_UnregisterClass (_Jv_Utf8Const*, java::lang::ClassLoader*); + extern jclass _Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader); extern jclass _Jv_FindClassFromSignature (char *, diff --git a/libjava/interpret.cc b/libjava/interpret.cc new file mode 100644 index 0000000..1b9b800 --- /dev/null +++ b/libjava/interpret.cc @@ -0,0 +1,2449 @@ +// interpret.cc - Code for the interpreter + +/* Copyright (C) 1999 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. */ + +/* Author: Kresten Krab Thorup <krab@gnu.org> */ + +/* define this to get instruction timings. */ +/* #define TIME_MAINLOOP */ + +#include <config.h> + +#pragma implementation "java-interp.h" + +#include <cni.h> +#include <jvm.h> +#include <java-field.h> +#include <java-cpool.h> +#include <java-interp.h> +#include <java/lang/fdlibm.h> +#include <java/lang/System.h> +#include <java/lang/String.h> +#include <java/lang/Integer.h> +#include <java/lang/StringBuffer.h> +#include <java/io/PrintStream.h> +#include <java/lang/Class.h> +#include <java/lang/reflect/Modifier.h> +#include <java/lang/ClassCastException.h> +#include <java/lang/VirtualMachineError.h> +#include <java/lang/InternalError.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/ArithmeticException.h> +#include <java/lang/IncompatibleClassChangeError.h> +#include <java-insns.h> +#include <java-signal.h> +#ifdef TIME_MAINLOOP +#include <sys/time.h> +#include <stdio.h> +#endif + +#ifndef INTERPRETER + +#include <gnu/gcj/runtime/MethodInvocation.h> + +/* this is the exception handler hack, for the interpreter */ +void +gnu::gcj::runtime::MethodInvocation::continue1 (gnu::gcj::RawData *, + gnu::gcj::RawData *) +{ + JvFail ("no interpreter"); +} + +#else + +#define ClassError _CL_Q34java4lang5Error +extern java::lang::Class ClassError; + +static const int PUBLIC = 0x001; +static const int PRIVATE = 0x002; +static const int PROTECTED = 0x004; +static const int STATIC = 0x008; +static const int FINAL = 0x010; +static const int SYNCHRONIZED = 0x020; +static const int VOLATILE = 0x040; +static const int TRANSIENT = 0x080; +static const int NATIVE = 0x100; +static const int INTERFACE = 0x200; +static const int ABSTRACT = 0x400; +static const int ALL_FLAGS = 0x7FF; + +static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6); + +static void throw_internal_error (char *msg) + __attribute__ ((__noreturn__)); +static void throw_incompatible_class_change_error (jstring msg) + __attribute__ ((__noreturn__)); +#if !HANDLE_SEGV +static void throw_null_pointer_exception () + __attribute__ ((__noreturn__)); +#endif +#if !HANDLE_FPE +static void throw_arithmetic_exception () + __attribute__ ((__noreturn__)); +#endif + + +static inline void dupx (void **&sp, int n, int x) +{ + // first "slide" n+x elements n to the right + int top = n-1; + for (int i = 0; i < n+x; i++) + { + sp[(top-i)] = sp[(top-i)-n]; + } + + // next, copy the n top elements, n+x down + for (int i = 0; i < n; i++) + { + sp[top-(n+x)-i] = sp[top-i]; + } + + // the net effect + sp += n; +}; + + +#define PUSHA(V) \ + ({ jobject __v=(V); *(jobject*)sp++ = __v; }) +#define PUSHI(V) \ + ({ jint __v=(V); *(jint*)sp++ = __v; }) +#define PUSHF(V) \ + ({ jfloat __v=(V); *(jfloat*)sp++ = __v; }) +#define PUSHL(V) \ + ({ jlong __v=(V); memcpy ((void*)sp, (void*)&__v, 8); sp+=2; }) +#define PUSHD(V) \ + ({ jdouble __v=(V); memcpy ((void*)sp, (void*)&__v, 8); sp+=2; }) + +#define POPA() (*(jobject*)--sp) +#define POPI() (*(jint*)--sp) +#define POPF() (*(jfloat*)--sp) +#define POPL() ({ jlong __r; sp-=2; memcpy ((void*)&__r, sp, 8); __r; }) +#define POPD() ({ jdouble __r; sp-=2; memcpy ((void*)&__r, sp, 8); __r; }) + +#define LOADA(I) *sp++ = locals[I] +#define LOADI(I) *sp++ = locals[I] +#define LOADF(I) *sp++ = locals[I] +#define LOADL(I) ({ memcpy (sp, locals+(I), 8); sp+=2; }) +#define LOADD(I) ({ memcpy (sp, locals+(I), 8); sp+=2; }) + +#define STOREA(I) locals[I] = *--sp +#define STOREI(I) locals[I] = *--sp +#define STOREF(I) locals[I] = *--sp +#define STOREL(I) ({ sp-=2; memcpy (locals+(I), sp, 8); }) +#define STORED(I) ({ sp-=2; memcpy (locals+(I), sp, 8); }) + +#define PEEKI(I) (*(jint*) (locals+(I))) +#define PEEKA(I) (*(jobject*) (locals+(I))) + +#define POKEI(I,V) (*(jint*) (locals+(I)) = (V)) + + +#define BINOPI(OP) { \ + jint value2 = POPI(); \ + jint value1 = POPI(); \ + PUSHI(value1 OP value2); \ +} + +#define BINOPF(OP) { \ + jfloat value2 = POPF(); \ + jfloat value1 = POPF(); \ + PUSHF(value1 OP value2); \ +} + +#define BINOPL(OP) { \ + jlong value2 = POPL(); \ + jlong value1 = POPL(); \ + PUSHL(value1 OP value2); \ +} + +#define BINOPD(OP) { \ + jdouble value2 = POPD(); \ + jdouble value1 = POPD(); \ + PUSHD(value1 OP value2); \ +} + +static inline jint get1s(unsigned char* loc) { + return *(signed char*)loc; +} + +static inline jint get1u(unsigned char* loc) { + return *loc; +} + +static inline jint get2s(unsigned char* loc) { + return (((jint)*(signed char*)loc) << 8) | ((jint)*(loc+1)); +} + +static inline jint get2u(unsigned char* loc) { + return (((jint)(*loc)) << 8) | ((jint)*(loc+1)); +} + +static jint get4(unsigned char* loc) { + return (((jint)(loc[0])) << 24) + | (((jint)(loc[1])) << 16) + | (((jint)(loc[2])) << 8) + | (((jint)(loc[3])) << 0); +} + + +#if HANDLE_SEGV +#define NULLCHECK(X) +#else +#define NULLCHECK(X) \ + do { if ((X)==NULL) throw_null_pointer_exception (); } while (0) +#endif + +#if HANDLE_FPE +#define ZEROCHECK(X) +#else +#define ZEROCHECK(X) \ + do { if ((X) == 0) throw_arithmetic_exception (); } while (0) +#endif + +// this method starts the actual running of the method. It is inlined +// in three different variants in the static methods run_normal, +// run_sync_object and run_sync_class (see below). Those static methods +// are installed directly in the stub for this method (by +// _Jv_InterpMethod::ncode, in resolve.cc). + +inline jobject +_Jv_InterpMethod::run (ffi_cif* cif, + void *retp, + void**args, + _Jv_InterpMethodInvocation *inv) +{ + inv->running = this; + inv->pc = bytecode (); + inv->sp = inv->stack_base (); + void **locals = inv->local_base (); + + /* Go straight at it! the ffi raw format matches the internal + stack representation exactly! + */ + memcpy ((void*) locals, (void*) args, args_raw_size); + + next_segment: + /* this will call the method _Jv_InterpMethod::continue0, see below */ + jobject ex = + gnu::gcj::runtime::MethodInvocation::continue0 + ((gnu::gcj::RawData *)this, (gnu::gcj::RawData *)inv); + + if (ex == 0) // no exception... + { + /* define sp locally, so the POP? macros will pick it up */ + void **sp = (void**)inv->sp; + int rtype = cif->rtype->type; + + if (rtype == FFI_TYPE_POINTER) + { + jobject r = POPA(); + *(jobject*) retp = r; + return 0; + } + else if (rtype == FFI_TYPE_SINT32) + { + jint r = POPI(); + *(jint*)retp = r; + return 0; + } + else if (rtype == FFI_TYPE_VOID) + { + return 0; + } + else switch (rtype) + { + case FFI_TYPE_FLOAT: + { + jfloat r = POPF(); + *(jfloat*)retp = r; + return 0; + } + + case FFI_TYPE_DOUBLE: + { + jdouble r = POPD(); + *(jdouble*)retp = r; + return 0; + } + + case FFI_TYPE_UINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT8: + case FFI_TYPE_SINT16: + { + jint r = POPI(); + *(jint*)retp = r; + return 0; + } + + case FFI_TYPE_SINT64: + { + jlong r = POPL(); + *(jlong*)retp = r; + return 0; + } + + default: + throw_internal_error ("unknown return type"); + } + + } + + /** handle an exception */ + if ( find_exception (ex, inv) ) + goto next_segment; + + java::lang::System::out->println + (_Jv_NewStringUTF (self->name->data)); + + return ex; +} + +bool _Jv_InterpMethod::find_exception (jobject ex, + _Jv_InterpMethodInvocation *inv) +{ + int logical_pc = inv->pc - bytecode (); + _Jv_InterpException *exc = exceptions (); + jclass exc_class = ex->getClass (); + + for (int i = 0; i < exc_count; i++) + { + if (exc[i].start_pc <= logical_pc && logical_pc < exc[i].end_pc) + { + jclass handler; + + if (exc[i].handler_type != 0) + handler = (jclass) + _Jv_ResolvePoolEntry (defining_class, + exc[i].handler_type); + else + handler = NULL; + + if (handler==NULL || handler->isAssignableFrom (exc_class)) + { + inv->pc = bytecode () + exc[i].handler_pc; + inv->sp = inv->stack_base (); // reset stack + *(jobject*) (inv->sp ++) = ex; + return true; + } + } + } + return false; +} + +void _Jv_InterpMethod::run_normal (ffi_cif* cif, + void* ret, + void** args, + void* __this) +{ + _Jv_InterpMethod* _this = (_Jv_InterpMethod*)__this; + + // we do the alloca of the method invocation here, to allow the method + // "run" ro be inlined. Otherwise gcc will ignore the inline directive. + int storage_size = _this->max_stack+_this->max_locals; + _Jv_InterpMethodInvocation* inv = (_Jv_InterpMethodInvocation*) + alloca (sizeof (_Jv_InterpMethodInvocation) + + storage_size * sizeof (void*)); + + jobject ex = _this->run (cif, ret, args, inv); + if (ex != 0) _Jv_Throw (ex); +} + +void _Jv_InterpMethod::run_synch_object (ffi_cif* cif, + void* ret, + void** args, + void* __this) +{ + _Jv_InterpMethod* _this = (_Jv_InterpMethod*)__this; + jobject rcv = (jobject)args[0]; + + int storage_size = _this->max_stack+_this->max_locals; + _Jv_InterpMethodInvocation* inv = (_Jv_InterpMethodInvocation*) + alloca (sizeof (_Jv_InterpMethodInvocation) + + storage_size * sizeof (void*)); + + _Jv_MonitorEnter (rcv); + jobject ex = _this->run (cif, ret, args, inv); + _Jv_MonitorExit (rcv); + + if (ex != 0) _Jv_Throw (ex); +} + +void _Jv_InterpMethod::run_synch_class (ffi_cif* cif, + void* ret, + void** args, + void* __this) +{ + _Jv_InterpMethod* _this = (_Jv_InterpMethod*)__this; + jclass sync = _this->defining_class; + + int storage_size = _this->max_stack+_this->max_locals; + _Jv_InterpMethodInvocation* inv = (_Jv_InterpMethodInvocation*) + alloca (sizeof (_Jv_InterpMethodInvocation) + + storage_size * sizeof (void*)); + + _Jv_MonitorEnter (sync); + jobject ex = _this->run (cif, ret, args, inv); + _Jv_MonitorExit (sync); + + if (ex != 0) _Jv_Throw (ex); +} + +/* this is the exception handler hack, for the interpreter */ +void +gnu::gcj::runtime::MethodInvocation::continue1 (gnu::gcj::RawData *meth, + gnu::gcj::RawData *inv) +{ + _Jv_InterpMethod *meth0 = (_Jv_InterpMethod*)meth; + _Jv_InterpMethodInvocation *inv0 = (_Jv_InterpMethodInvocation*)inv; + meth0->continue1 (inv0); +} + +/* + This proceeds execution, as designated in "inv". If an exception + happens, then it is simply thrown, and handled in Java. Thus, the pc + needs to be stored in the invocation at all times, so we can figure + out which handler (if any) to invoke. + + One design issue, which I have not completely considered, is if it + should be possible to have interpreted classes linked in! Seldom used + (or non-critical) classes could reasonably be interpreted. +*/ + + +#ifdef TIME_MAINLOOP +static jlong insn_time [256] = { 0 }; +static jlong insn_count[256] = { 0 }; + +static void +dump_time () +{ + double total_all = 0; + for (int i = 0; i < 256; i++) + { + total_all += insn_time[i]; + } + + for (int i = 0; i < 256; i++) + { + jlong total = insn_time[i]; + jlong count = insn_count[i]; + + if (count == 0) continue; + + jlong amount = total/count; + + printf ("in 0x%02x: %7Li %7Li %7Li %2.1f%%\n", i, + (long long)count, (long long)total, (long long)amount, + (float) (100.0*(double)total/total_all) + ); + } +} +#endif + +void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) +{ + /* for some reason, which I do not understand, the compiler on x86 + * allocates almost 4k stack space for this function! Even though + * there are many local variables, they are all nicely contained + * within a block scope, except for the few declared right below + * here. What's going on?? It could well be, that there in fact is + * on the order of 1000 local variables, including all those inlined + * and expanded from macros... Compiling with -O0, it allocates a + * "modest" 300 bytes of stack space. Among all those options of + * gcc, why isn't there a -fpack-stack, allowing reuse of stack + * locations? */ + + void** sp = inv->sp; + unsigned char *pc = inv->pc; + void** locals = inv->local_base (); + int opcode; + + jclass defining_class = this->defining_class; + void **pool_data = defining_class->constants.data; + + /* these two are used in the invokeXXX instructions */ + void (*fun)(...); + _Jv_ResolvedMethod* rmeth; + +#ifdef TIME_MAINLOOP + struct timeval tv; + int last_opcode; + jlong last_time; + static jlong time_warp = 0; + +#define USEC(TV) \ + ((jlong) (TV).tv_sec * 1000000LL + (jlong)(TV).tv_usec) + + + if (time_warp == 0) + { + struct timeval tv2; + + gettimeofday (&tv, 0); + for (int i = 0; i < 100; i++) + gettimeofday (&tv2, 0); + + jlong then = USEC(tv); + jlong now = USEC(tv2); + time_warp = (now - then) / 100; + + if (time_warp == 0) + time_warp = 1; + } + +#define TIME_SUSPEND do { \ + gettimeofday (&tv, 0); \ + jlong now = USEC(tv); \ + insn_time[last_opcode] += (now - last_time) - time_warp; \ +} while(0) + +#define TIME_RESUME do { \ + gettimeofday (&tv, 0); \ + last_time = USEC(tv); \ +} while(0) + + last_opcode = 0; + gettimeofday (&tv, 0); + last_time = (jlong)tv.tv_sec * 1000000LL + (jlong)tv.tv_usec; + +#else + +#define TIME_SUSPEND +#define TIME_RESUME + +#endif + + next_insn: + inv->pc = pc; + +#ifdef TIME_MAINLOOP + + gettimeofday (&tv, 0); + jlong now = USEC(tv); + insn_time[last_opcode] += (now - last_time) - time_warp; + last_time = now; + last_opcode = *pc; + insn_count[last_opcode] += 1; + +#endif + opcode = *pc++; + + /* we special-case the single opcode aload_0 -- it makes + up 10% of the time spent in the main loop. */ + + switch (opcode) + { + case op_aload_0: // 0x2a + LOADA(0); + goto next_insn; + + case op_iload: // 0x15 + LOADI (get1u (pc++)); + goto next_insn; + + case op_getfield_4: // 0xd8 + { + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + PUSHI (*(jint*) ((char*)obj + field_offset)); + } + goto next_insn; + + case op_iload_1: // 0x1b + LOADI (1); + goto next_insn; + + case op_getfield_a: // 0xda + { + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + PUSHA(*(jobject*) ((char*)obj + field_offset)); + } + goto next_insn; + + case op_invokevirtual: // 0xb6 + { + int index = get2u (pc); pc += 2; + + /* _Jv_ResolvePoolEntry returns immediately if the value already + * is resolved. If we want to clutter up the code here to gain + * a little performance, then we can check the corresponding bit + * JV_CONSTANT_ResolvedFlag in the tag directly. For now, I + * don't think it is worth it. */ + + rmeth = (_Jv_ResolvedMethod*) + _Jv_ResolvePoolEntry (defining_class, index); + + sp -= rmeth->stack_item_count; + NULLCHECK(sp[0]); + + if (rmeth->vtable_index == -1) + { + // final methods do not appear in the vtable, + // if it does not appear in the superclass. + fun = (void (*) (...)) rmeth->method->ncode; + } + else + { + jobject rcv = (jobject)sp[0]; + _Jv_VTable *table = *(_Jv_VTable**)rcv; + fun = (void (*) (...))table->method[rmeth->vtable_index]; + } + } + goto perform_invoke; + + perform_invoke: + { + /* here goes the magic again... */ + ffi_cif *cif = &rmeth->cif; + void **raw = sp; + + jdouble rvalue; + + TIME_SUSPEND; + ffi_raw_call (cif, fun, (void*)&rvalue, (ffi_raw*) raw); + TIME_RESUME; + + int rtype = cif->rtype->type; + + /* the likelyhood of object, int, or void return is very high, + * so those are checked before the switch */ + if (rtype == FFI_TYPE_POINTER) + { + PUSHA (*(jobject*)&rvalue); + } + else if (rtype == FFI_TYPE_SINT32) + { + PUSHI (*(jint*)&rvalue); + } + else if (rtype == FFI_TYPE_VOID) + { + /* skip */ + } + else switch (rtype) + { + case FFI_TYPE_SINT8: + { + jbyte value = (*(jint*)&rvalue) & 0xff; + PUSHI (value); + } + break; + + case FFI_TYPE_SINT16: + { + jshort value = (*(jint*)&rvalue) & 0xffff; + PUSHI (value); + } + break; + + case FFI_TYPE_UINT16: + { + jint value = (*(jint*)&rvalue) & 0xffff; + PUSHI (value); + } + break; + + case FFI_TYPE_FLOAT: + PUSHF (*(jfloat*)&rvalue); + break; + + case FFI_TYPE_DOUBLE: + PUSHD (rvalue); + break; + + case FFI_TYPE_SINT64: + PUSHL (*(jlong*)&rvalue); + break; + + default: + throw_internal_error ("unknown return type in invokeXXX"); + } + + } + goto next_insn; + + + case op_nop: + goto next_insn; + + case op_aconst_null: + PUSHA (NULL); + goto next_insn; + + case op_iconst_m1: + case op_iconst_0: + case op_iconst_1: + case op_iconst_2: + case op_iconst_3: + case op_iconst_4: + case op_iconst_5: + PUSHI (opcode-op_iconst_0); + goto next_insn; + + case op_lconst_0: + case op_lconst_1: + PUSHL ((jlong) (opcode-op_lconst_0)); + goto next_insn; + + case op_fconst_0: + case op_fconst_1: + case op_fconst_2: + PUSHF ((jfloat) (opcode-op_fconst_0)); + goto next_insn; + + case op_dconst_0: + case op_dconst_1: + PUSHD ((jdouble) (opcode-op_dconst_0)); + goto next_insn; + + case op_bipush: + PUSHI (get1s(pc++)); + goto next_insn; + + case op_sipush: + PUSHI (get2s(pc)); pc += 2; + goto next_insn; + + case op_ldc: + { + int index = get1u (pc++); + PUSHA((jobject) pool_data[index]); + } + goto next_insn; + + case op_ldc_w: + { + int index = get2u (pc); pc += 2; + PUSHA((jobject) pool_data[index]); + } + goto next_insn; + + case op_ldc2_w: + { + int index = get2u (pc); pc += 2; + memcpy (sp, &pool_data[index], 8); + sp += 2; + } + goto next_insn; + + case op_lload: + LOADL (get1u (pc++)); + goto next_insn; + + case op_fload: + LOADF (get1u (pc++)); + goto next_insn; + + case op_dload: + LOADD (get1u (pc++)); + goto next_insn; + + case op_aload: + LOADA (get1u (pc++)); + goto next_insn; + + case op_iload_0: + LOADI (0); + goto next_insn; + + case op_iload_2: + LOADI (2); + goto next_insn; + + case op_iload_3: + LOADI (3); + goto next_insn; + + case op_lload_0: + case op_lload_1: + case op_lload_2: + case op_lload_3: + LOADL (opcode-op_lload_0); + goto next_insn; + + case op_fload_0: + case op_fload_1: + case op_fload_2: + case op_fload_3: + LOADF (opcode-op_fload_0); + goto next_insn; + + case op_dload_0: + case op_dload_1: + case op_dload_2: + case op_dload_3: + LOADD (opcode-op_dload_0); + goto next_insn; + + case op_aload_1: + LOADA(1); + goto next_insn; + + case op_aload_2: + LOADA(2); + goto next_insn; + + case op_aload_3: + LOADA(3); + goto next_insn; + + case op_iaload: + { + jint index = POPI(); + jintArray arr = (jintArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + PUSHI( elements(arr)[index] ); + } + goto next_insn; + + case op_laload: + { + jint index = POPI(); + jlongArray arr = (jlongArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + PUSHL( elements(arr)[index] ); + } + goto next_insn; + + case op_faload: + { + jint index = POPI(); + jfloatArray arr = (jfloatArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + PUSHF( elements(arr)[index] ); + } + goto next_insn; + + case op_daload: + { + jint index = POPI(); + jdoubleArray arr = (jdoubleArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + PUSHD( elements(arr)[index] ); + } + goto next_insn; + + case op_aaload: + { + jint index = POPI(); + jobjectArray arr = (jobjectArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + PUSHA( elements(arr)[index] ); + } + goto next_insn; + + case op_baload: + { + jint index = POPI(); + jbyteArray arr = (jbyteArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + PUSHI( elements(arr)[index] ); + } + goto next_insn; + + case op_caload: + { + jint index = POPI(); + jcharArray arr = (jcharArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + PUSHI( elements(arr)[index] ); + } + goto next_insn; + + case op_saload: + { + jint index = POPI(); + jshortArray arr = (jshortArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + PUSHI( elements(arr)[index] ); + } + goto next_insn; + + case op_istore: + STOREI (get1u (pc++)); + goto next_insn; + + case op_lstore: + STOREL (get1u (pc++)); + goto next_insn; + + case op_fstore: + STOREF (get1u (pc++)); + goto next_insn; + + case op_dstore: + STORED (get1u (pc++)); + goto next_insn; + + case op_astore: + STOREI (get1u (pc++)); + goto next_insn; + + case op_istore_0: + case op_istore_1: + case op_istore_2: + case op_istore_3: + STOREI (opcode-op_istore_0); + goto next_insn; + + case op_lstore_0: + case op_lstore_1: + case op_lstore_2: + case op_lstore_3: + STOREL (opcode-op_lstore_0); + goto next_insn; + + case op_fstore_0: + case op_fstore_1: + case op_fstore_2: + case op_fstore_3: + STOREF (opcode-op_fstore_0); + goto next_insn; + + case op_dstore_0: + case op_dstore_1: + case op_dstore_2: + case op_dstore_3: + STORED (opcode-op_dstore_0); + goto next_insn; + + case op_astore_0: + case op_astore_1: + case op_astore_2: + case op_astore_3: + STOREA (opcode-op_astore_0); + goto next_insn; + + case op_iastore: + { + jint value = POPI(); + jint index = POPI(); + jintArray arr = (jintArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + elements(arr)[index] = value; + } + goto next_insn; + + case op_lastore: + { + jlong value = POPL(); + jint index = POPI(); + jlongArray arr = (jlongArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + elements(arr)[index] = value; + } + goto next_insn; + + case op_fastore: + { + jfloat value = POPF(); + jint index = POPI(); + jfloatArray arr = (jfloatArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + elements(arr)[index] = value; + } + goto next_insn; + + case op_dastore: + { + jdouble value = POPD(); + jint index = POPI(); + jdoubleArray arr = (jdoubleArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + elements(arr)[index] = value; + } + goto next_insn; + + case op_aastore: + { + jobject value = POPA(); + jint index = POPI(); + jobjectArray arr = (jobjectArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + _Jv_CheckArrayStore (arr, value); + elements(arr)[index] = value; + } + goto next_insn; + + case op_bastore: + { + jbyte value = (jbyte) POPI(); + jint index = POPI(); + jbyteArray arr = (jbyteArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + elements(arr)[index] = value; + } + goto next_insn; + + case op_castore: + { + jchar value = (jchar) POPI(); + jint index = POPI(); + jcharArray arr = (jcharArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + elements(arr)[index] = value; + } + goto next_insn; + + case op_sastore: + { + jshort value = (jshort) POPI(); + jint index = POPI(); + jshortArray arr = (jshortArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + elements(arr)[index] = value; + } + goto next_insn; + + case op_pop: + sp -= 1; + goto next_insn; + + case op_pop2: + sp -= 2; + goto next_insn; + + case op_dup: + sp[0] = sp[-1]; + sp += 1; + goto next_insn; + + case op_dup_x1: + dupx (sp, 1, 1); + goto next_insn; + + case op_dup_x2: + dupx (sp, 1, 2); + goto next_insn; + + case op_dup2: + sp[0] = sp[-2]; + sp[1] = sp[-1]; + sp += 2; + goto next_insn; + + case op_dup2_x1: + dupx (sp, 2, 1); + goto next_insn; + + case op_dup2_x2: + dupx (sp, 2, 2); + goto next_insn; + + case op_swap: + { + jobject tmp1 = POPA(); + jobject tmp2 = POPA(); + PUSHA (tmp1); + PUSHA (tmp2); + } + goto next_insn; + + case op_iadd: + BINOPI(+); + goto next_insn; + + case op_ladd: + BINOPL(+); + goto next_insn; + + case op_fadd: + BINOPF(+); + goto next_insn; + + case op_dadd: + BINOPD(+); + goto next_insn; + + case op_isub: + BINOPI(-); + goto next_insn; + + case op_lsub: + BINOPL(-); + goto next_insn; + + case op_fsub: + BINOPF(-); + goto next_insn; + + case op_dsub: + BINOPD(-); + goto next_insn; + + case op_imul: + BINOPI(*); + goto next_insn; + + case op_lmul: + BINOPL(*); + goto next_insn; + + case op_fmul: + BINOPF(*); + goto next_insn; + + case op_dmul: + BINOPD(*); + goto next_insn; + + case op_idiv: + { + jint value2 = POPI(); + jint value1 = POPI(); + ZEROCHECK (value2); + jint res = value1 / value2; + PUSHI (res); + } + goto next_insn; + + case op_ldiv: + { + jlong value2 = POPL(); + jlong value1 = POPL(); + ZEROCHECK (value2); + jlong res = value1 / value2; + PUSHL (res); + } + goto next_insn; + + case op_fdiv: + { + jfloat value2 = POPF(); + jfloat value1 = POPF(); + ZEROCHECK (value2); + jfloat res = value1 / value2; + PUSHF (res); + } + goto next_insn; + + case op_ddiv: + { + jdouble value2 = POPD(); + jdouble value1 = POPD(); + ZEROCHECK (value2); + jdouble res = value1 / value2; + PUSHD (res); + } + goto next_insn; + + case op_irem: + { + jint value2 = POPI(); + jint value1 = POPI(); + ZEROCHECK (value2); + jint res = value1 % value2; + PUSHI (res); + } + goto next_insn; + + case op_lrem: + { + jlong value2 = POPL(); + jlong value1 = POPL(); + ZEROCHECK (value2); + jlong res = value1 % value2; + PUSHL (res); + } + goto next_insn; + + case op_frem: + { + jfloat value2 = POPF(); + jfloat value1 = POPF(); + ZEROCHECK (value2); + jfloat res = __ieee754_fmod (value1, value2); + PUSHF (res); + } + goto next_insn; + + case op_drem: + { + jdouble value2 = POPD(); + jdouble value1 = POPD(); + ZEROCHECK (value2); + jdouble res = __ieee754_fmod (value1, value2); + PUSHD (res); + } + goto next_insn; + + case op_ineg: + *(jint*) (sp-1) *= -1; + goto next_insn; + + case op_lneg: + *(jlong*) (sp-1) *= -1; + goto next_insn; + + case op_fneg: + *(jfloat*) (sp-1) *= -1; + goto next_insn; + + case op_dneg: + *(jdouble*) (sp-1) *= -1; + goto next_insn; + + case op_ishl: + { + jint shift = (POPI() & 0x1f); + jint value = POPI(); + PUSHI (value << shift); + } + goto next_insn; + + case op_lshl: + { + jint shift = (POPI() & 0x3f); + jlong value = POPL(); + PUSHL (value << shift); + } + goto next_insn; + + case op_ishr: + { + jint shift = (POPI() & 0x1f); + jint value = POPI(); + PUSHI (value >> shift); + } + goto next_insn; + + case op_lshr: + { + jint shift = (POPI() & 0x3f); + jlong value = POPL(); + PUSHL (value >> shift); + } + goto next_insn; + + case op_iushr: + { + jint shift = (POPI() & 0x1f); + unsigned long value = POPI(); + PUSHI ((jint) (value >> shift)); + } + goto next_insn; + + case op_lushr: + { + jint shift = (POPI() & 0x3f); + UINT64 value = (UINT64) POPL(); + PUSHL ((value >> shift)); + } + goto next_insn; + + case op_iand: + BINOPI (&); + goto next_insn; + + case op_land: + BINOPL (&); + goto next_insn; + + case op_ior: + BINOPI (|); + goto next_insn; + + case op_lor: + BINOPL (|); + goto next_insn; + + case op_ixor: + BINOPI (^); + goto next_insn; + + case op_lxor: + BINOPL (^); + goto next_insn; + + case op_iinc: + { + jint index = get1u (pc++); + jint amount = get1s (pc++); + *(jint*) (locals + index) += amount; + } + goto next_insn; + + case op_i2l: + PUSHL ((jlong)POPI ()); + goto next_insn; + + case op_i2f: + PUSHF ((jfloat)POPI ()); + goto next_insn; + + case op_i2d: + PUSHD ((jdouble)POPI ()); + goto next_insn; + + case op_l2i: + PUSHI ((jint)POPL ()); + goto next_insn; + + case op_l2f: + PUSHF ((jfloat)POPL ()); + goto next_insn; + + case op_l2d: + PUSHD ((jdouble)POPL ()); + goto next_insn; + + case op_f2i: + PUSHI ((jint)POPF ()); + goto next_insn; + + case op_f2l: + PUSHL ((jlong)POPF ()); + goto next_insn; + + case op_f2d: + PUSHD ((jdouble)POPF ()); + goto next_insn; + + case op_d2i: + PUSHI ((jint)POPD ()); + goto next_insn; + + case op_d2l: + PUSHL ((jlong)POPD ()); + goto next_insn; + + case op_d2f: + PUSHF ((jfloat)POPD ()); + goto next_insn; + + case op_i2b: + PUSHI ((jbyte)POPI ()); + goto next_insn; + + case op_i2c: + PUSHI ((jchar)POPI ()); + goto next_insn; + + case op_i2s: + PUSHI ((jshort)POPI ()); + goto next_insn; + + case op_lcmp: + { + jlong value2 = POPL (); + jlong value1 = POPL (); + if (value1 > value2) + { PUSHI (1); } + else if (value1 == value2) + { PUSHI (0); } + else + { PUSHI (-1); } + } + goto next_insn; + + case op_fcmpl: + case op_fcmpg: + { + jfloat value2 = POPF (); + jfloat value1 = POPF (); + if (value1 > value2) + PUSHI (1); + else if (value1 == value2) + PUSHI (0); + else if (value1 < value2) + PUSHI (-1); + else if (opcode == op_fcmpg) + PUSHI (1); + else + PUSHI (-1); + } + goto next_insn; + + case op_dcmpl: + case op_dcmpg: + { + jdouble value2 = POPD (); + jdouble value1 = POPD (); + if (value1 > value2) + PUSHI (1); + else if (value1 == value2) + PUSHI (0); + else if (value1 < value2) + PUSHI (-1); + else if (opcode == op_dcmpg) + PUSHI (1); + else + PUSHI (-1); + } + goto next_insn; + + case op_ifeq: + { + jint offset = get2s (pc); + if (POPI() == 0) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_ifne: + { + jint offset = get2s (pc); + if (POPI() != 0) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_iflt: + { + jint offset = get2s (pc); + if (POPI() < 0) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_ifge: + { + jint offset = get2s (pc); + if (POPI() >= 0) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_ifgt: + { + jint offset = get2s (pc); + if (POPI() > 0) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_ifle: + { + jint offset = get2s (pc); + if (POPI() <= 0) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_if_icmpeq: + { + jint offset = get2s (pc); + jint value2 = POPI(); + jint value1 = POPI(); + if (value1 == value2) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_if_icmpne: + { + jint offset = get2s (pc); + jint value2 = POPI(); + jint value1 = POPI(); + if (value1 != value2) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_if_icmplt: + { + jint offset = get2s (pc); + jint value2 = POPI(); + jint value1 = POPI(); + if (value1 < value2) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_if_icmpge: + { + jint offset = get2s (pc); + jint value2 = POPI(); + jint value1 = POPI(); + if (value1 >= value2) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_if_icmpgt: + { + jint offset = get2s (pc); + jint value2 = POPI(); + jint value1 = POPI(); + if (value1 > value2) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_if_icmple: + { + jint offset = get2s (pc); + jint value2 = POPI(); + jint value1 = POPI(); + if (value1 <= value2) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_if_acmpeq: + { + jint offset = get2s (pc); + jobject value2 = POPA(); + jobject value1 = POPA(); + if (value1 == value2) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_if_acmpne: + { + jint offset = get2s (pc); + jobject value2 = POPA(); + jobject value1 = POPA(); + if (value1 != value2) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_goto: + { + jint offset = get2s (pc); + pc = pc-1+offset; + } + goto next_insn; + + case op_jsr: + { + unsigned char *base_pc = pc-1; + jint offset = get2s (pc); pc += 2; + PUSHA ((jobject)pc); + pc = base_pc+offset; + } + goto next_insn; + + case op_ret: + { + jint index = get1u (pc); + pc = (unsigned char*) PEEKA (index); + } + goto next_insn; + + case op_tableswitch: + { + unsigned char *base_pc = pc-1; + int index = POPI(); + + unsigned char* base = bytecode (); + while ((pc-base) % 4 != 0) + pc++; + + jint def = get4 (pc); + jint low = get4 (pc+4); + jint high = get4 (pc+8); + + if (index < low || index > high) + pc = base_pc + def; + else + pc = base_pc + get4 (pc+4*(index-low+3)); + } + goto next_insn; + + case op_lookupswitch: + { + unsigned char *base_pc = pc-1; + int index = POPI(); + + unsigned char* base = bytecode (); + while ((pc-base) % 4 != 0) + pc++; + + jint def = get4 (pc); + jint npairs = get4 (pc+4); + + int max = npairs-1; + int min = 0; + + // simple binary search... + while (min < max) + { + int half = (min+max)/2; + int match = get4 (pc+ 4*(2 + 2*half)); + + if (index == match) + min = max = half; + + else if (index < match) + max = half-1; + + else + min = half+1; + } + + if (index == get4 (pc+ 4*(2 + 2*min))) + pc = base_pc + get4 (pc+ 4*(2 + 2*min + 1)); + else + pc = base_pc + def; + } + goto next_insn; + + /* on return, just save the sp and return to caller */ + case op_ireturn: + case op_lreturn: + case op_freturn: + case op_dreturn: + case op_areturn: + case op_return: + inv->sp = sp; + TIME_SUSPEND; + return; + + case op_getstatic: + { + unsigned char *base_pc = pc-1; + jint fieldref_index = get2u (pc); pc += 2; + _Jv_ResolvePoolEntry (defining_class, fieldref_index); + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + + if ((field->flags & STATIC) == 0) + throw_incompatible_class_change_error + (JvNewStringLatin1 ("field no longer static")); + + jclass type = field->type; + + if (type->isPrimitive ()) + { + switch (type->size_in_bytes) + { + case 1: + *base_pc = op_getstatic_1; + break; + + case 2: + if (type == JvPrimClass (char)) + *base_pc = op_getstatic_2u; + else + *base_pc = op_getstatic_2s; + break; + + case 4: + *base_pc = op_getstatic_4; + break; + + case 8: + *base_pc = op_getstatic_8; + break; + } + } + else + { + *base_pc = op_getstatic_a; + } + + pc = base_pc; + } + goto next_insn; + + case op_getfield: + { + unsigned char *base_pc = pc-1; + jint fieldref_index = get2u (pc); pc += 2; + _Jv_ResolvePoolEntry (defining_class, fieldref_index); + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + + if ((field->flags & STATIC) != 0) + throw_incompatible_class_change_error + (JvNewStringLatin1 ("field is static")); + + jclass type = field->type; + + if (type->isPrimitive ()) + { + switch (type->size_in_bytes) + { + case 1: + *base_pc = op_getfield_1; + break; + + case 2: + if (type == JvPrimClass (char)) + *base_pc = op_getfield_2u; + else + *base_pc = op_getfield_2s; + break; + + case 4: + *base_pc = op_getfield_4; + break; + + case 8: + *base_pc = op_getfield_8; + break; + } + } + else + { + *base_pc = op_getfield_a; + } + + if (field->u.boffset > 0xffff) + JvThrow (new java::lang::VirtualMachineError); + + base_pc[1] = (field->u.boffset>>8) & 0xff; + base_pc[2] = field->u.boffset & 0xff; + + pc = base_pc; + } + goto next_insn; + + case op_putstatic: + { + unsigned char* base_pc = pc-1; + jint fieldref_index = get2u (pc); pc += 2; + _Jv_ResolvePoolEntry (defining_class, fieldref_index); + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + + jclass type = field->type; + + // ResolvePoolEntry cannot check this + if ((field->flags & STATIC) == 0) + throw_incompatible_class_change_error + (JvNewStringLatin1 ("field no longer static")); + + /* if this is patented, then maybe we could install + a function in the constant pool, to do the right thing */ + + if (type->isPrimitive ()) + { + switch (type->size_in_bytes) + { + case 1: + *base_pc = op_putstatic_1; + break; + + case 2: + *base_pc = op_putstatic_2; + break; + + case 4: + *base_pc = op_putstatic_4; + break; + + case 8: + *base_pc = op_putstatic_8; + break; + } + } + else + { + *base_pc = op_putstatic_a; + } + + // do the instruction again! + pc = base_pc; + } + goto next_insn; + + + case op_putfield: + { + unsigned char* base_pc = pc-1; + jint fieldref_index = get2u (pc); pc += 2; + _Jv_ResolvePoolEntry (defining_class, fieldref_index); + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + + jclass type = field->type; + + if ((field->flags & STATIC) != 0) + throw_incompatible_class_change_error + (JvNewStringLatin1 ("field is static")); + + if (type->isPrimitive ()) + { + switch (type->size_in_bytes) + { + case 1: + *base_pc = op_putfield_1; + break; + + case 2: + *base_pc = op_putfield_2; + break; + + case 4: + *base_pc = op_putfield_4; + break; + + case 8: + *base_pc = op_putfield_8; + break; + } + } + else + { + *base_pc = op_putfield_a; + } + + if (field->u.boffset > 0xffff) + JvThrow (new java::lang::VirtualMachineError); + + base_pc[1] = (field->u.boffset>>8) & 0xff; + base_pc[2] = field->u.boffset & 0xff; + + // do the instruction again! + pc = base_pc; + } + goto next_insn; + + + case op_getfield_1: + { + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + PUSHI (*(jbyte*) ((char*)obj + field_offset)); + } + goto next_insn; + + case op_getfield_2s: + { + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + PUSHI (*(jshort*) ((char*)obj + field_offset)); + } + goto next_insn; + + case op_getfield_2u: + { + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + PUSHI (*(jchar*) ((char*)obj + field_offset)); + } + goto next_insn; + + case op_getfield_8: + { + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + PUSHL(*(jlong*) ((char*)obj + field_offset)); + } + goto next_insn; + + case op_getstatic_1: + { + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + PUSHI (*(jbyte*) (field->u.addr)); + } + goto next_insn; + + case op_getstatic_2s: + { + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + PUSHI(*(jshort*) (field->u.addr)); + } + goto next_insn; + + case op_getstatic_2u: + { + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + PUSHI(*(jchar*) (field->u.addr)); + } + goto next_insn; + + case op_getstatic_4: + { + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + PUSHI(*(jint*) (field->u.addr)); + } + goto next_insn; + + case op_getstatic_8: + { + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + PUSHL(*(jlong*) (field->u.addr)); + } + goto next_insn; + + case op_getstatic_a: + { + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + PUSHA(*(jobject*) (field->u.addr)); + } + goto next_insn; + + case op_putfield_1: + { + jint value = POPI(); + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + *(jbyte*) ((char*)obj + field_offset) = value; + } + goto next_insn; + + case op_putfield_2: + { + jint value = POPI(); + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + *(jchar*) ((char*)obj + field_offset) = value; + } + goto next_insn; + + case op_putfield_4: + { + jint value = POPI(); + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + *(jint*) ((char*)obj + field_offset) = value; + } + goto next_insn; + + case op_putfield_8: + { + jlong value = POPL(); + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + *(jlong*) ((char*)obj + field_offset) = value; + } + goto next_insn; + + case op_putfield_a: + { + jobject value = POPA(); + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + *(jobject*) ((char*)obj + field_offset) = value; + } + goto next_insn; + + case op_putstatic_1: + { + jint value = POPI(); + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + *(jbyte*) (field->u.addr) = value; + } + goto next_insn; + + case op_putstatic_2: + { + jint value = POPI(); + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + *(jchar*) (field->u.addr) = value; + } + goto next_insn; + + case op_putstatic_4: + { + jint value = POPI(); + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + *(jint*) (field->u.addr) = value; + } + goto next_insn; + + case op_putstatic_8: + { + jlong value = POPL(); + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + *(jlong*) (field->u.addr) = value; + } + goto next_insn; + + case op_putstatic_a: + { + jobject value = POPA(); + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + *(jobject*) (field->u.addr) = value; + } + goto next_insn; + + case op_invokespecial: + { + int index = get2u (pc); pc += 2; + + rmeth = (_Jv_ResolvedMethod*) + _Jv_ResolvePoolEntry (defining_class, index); + + sp -= rmeth->stack_item_count; + + NULLCHECK(sp[0]); + + fun = (void (*) (...))rmeth->method->ncode; + } + goto perform_invoke; + + case op_invokestatic: + { + int index = get2u (pc); pc += 2; + + rmeth = (_Jv_ResolvedMethod*) + _Jv_ResolvePoolEntry (defining_class, index); + + sp -= rmeth->stack_item_count; + + _Jv_InitClass (rmeth->klass); + fun = (void (*) (...))rmeth->method->ncode; + } + goto perform_invoke; + + case op_invokeinterface: + { + int index = get2u (pc); pc += 2; + + // invokeinterface has two unused bytes... + pc += 2; + + rmeth = (_Jv_ResolvedMethod*) + _Jv_ResolvePoolEntry (defining_class, index); + + sp -= rmeth->stack_item_count; + NULLCHECK(sp[0]); + + jobject rcv = (jobject)sp[0]; + + fun = (void (*) (...)) + _Jv_LookupInterfaceMethod (rcv->getClass (), + rmeth->method->name, + rmeth->method->signature); + } + goto perform_invoke; + + + case op_new: + { + int index = get2u (pc); pc += 2; + jclass klass = (jclass) _Jv_ResolvePoolEntry (defining_class, + index); + _Jv_InitClass (klass); + jobject res = _Jv_AllocObject (klass, klass->size_in_bytes); + PUSHA (res); + } + goto next_insn; + + case op_newarray: + { + int atype = get1u (pc++); + int size = POPI(); + jobject result = _Jv_NewArray (atype, size); + PUSHA (result); + } + goto next_insn; + + case op_anewarray: + { + int index = get2u (pc); pc += 2; + jclass klass = (jclass) _Jv_ResolvePoolEntry (defining_class, index); + int size = POPI(); + _Jv_InitClass (klass); + jobject result = _Jv_NewObjectArray (size, klass, 0); + PUSHA (result); + } + goto next_insn; + + case op_arraylength: + { + __JArray *arr = (__JArray*)POPA(); + PUSHI (arr->length); + } + goto next_insn; + + case op_athrow: + { + jobject value = POPA(); + TIME_SUSPEND; + JvThrow (value); + } + goto next_insn; + + case op_checkcast: + { + jobject value = POPA(); + jint index = get2u (pc); pc += 2; + jclass to = (jclass)_Jv_ResolvePoolEntry (defining_class, + index); + + if (value != NULL && ! to->isInstance (value)) + { + TIME_SUSPEND; + JvThrow (new java::lang::ClassCastException + (to->getName())); + } + + PUSHA (value); + } + goto next_insn; + + case op_instanceof: + { + jobject value = POPA(); + jint index = get2u (pc); pc += 2; + jclass to = (jclass)_Jv_ResolvePoolEntry (defining_class, + index); + PUSHI (to->isInstance (value)); + } + goto next_insn; + + case op_monitorenter: + { + jobject value = POPA(); + NULLCHECK(value); + _Jv_MonitorEnter (value); + } + goto next_insn; + + case op_monitorexit: + { + jobject value = POPA(); + NULLCHECK(value); + _Jv_MonitorExit (value); + } + goto next_insn; + + case op_ifnull: + { + unsigned char* base_pc = pc-1; + jint offset = get2s (pc); pc += 2; + jobject val = POPA(); + if (val == NULL) + pc = base_pc+offset; + } + goto next_insn; + + case op_ifnonnull: + { + unsigned char* base_pc = pc-1; + jint offset = get2s (pc); pc += 2; + jobject val = POPA(); + if (val != NULL) + pc = base_pc+offset; + } + goto next_insn; + + case op_wide: + { + jint the_mod_op = get1u (pc++); + jint wide = get2u (pc); pc += 2; + + switch (the_mod_op) + { + case op_istore: + STOREI (wide); + goto next_insn; + + case op_fstore: + STOREF (wide); + goto next_insn; + + case op_astore: + STOREA (wide); + goto next_insn; + + case op_lload: + LOADL (wide); + goto next_insn; + + case op_dload: + LOADD (wide); + goto next_insn; + + case op_iload: + LOADI (wide); + goto next_insn; + + case op_aload: + LOADA (wide); + goto next_insn; + + case op_lstore: + STOREL (wide); + goto next_insn; + + case op_dstore: + STORED (wide); + goto next_insn; + + case op_ret: + pc = (unsigned char*) PEEKA (wide); + goto next_insn; + + case op_iinc: + { + jint amount = get2s (pc); pc += 2; + jint value = PEEKI (wide); + POKEI (wide, value+amount); + } + goto next_insn; + + default: + throw_internal_error ("illegal bytecode modified by wide"); + } + + } + + case op_multianewarray: + { + int kind_index = get2u (pc); pc += 2; + int dim = get1u (pc); pc += 1; + + jclass type = (jclass) _Jv_ResolvePoolEntry (defining_class, + kind_index); + _Jv_InitClass (type); + jint *sizes = (jint*) alloca (sizeof (jint)*dim); + + for (int i = dim - 1; i >= 0; i--) + { + sizes[i] = POPI (); + } + + jobject res = _Jv_NewMultiArray (type,dim, sizes); + + PUSHA (res); + } + goto next_insn; + + case op_goto_w: + { + unsigned char* base_pc = pc-1; + int offset = get4 (pc); pc += 4; + pc = base_pc+offset; + } + goto next_insn; + + case op_jsr_w: + { + unsigned char* base_pc = pc-1; + int offset = get4 (pc); pc += 4; + PUSHA((jobject)pc); + pc = base_pc+offset; + } + goto next_insn; + + default: + throw_internal_error ("opcode not implemented"); + + } + goto next_insn; +} + + +static void +throw_internal_error (char *msg) +{ + JvThrow (new java::lang::InternalError (JvNewStringLatin1 (msg))); +} + +static void +throw_incompatible_class_change_error (jstring msg) +{ + JvThrow (new java::lang::IncompatibleClassChangeError (msg)); +} + +#if !HANDLE_SEGV +static java::lang::NullPointerException *null_pointer_exc; +static void +throw_null_pointer_exception () +{ + if (null_pointer_exc == NULL) + null_pointer_exc = new java::lang::NullPointerException; + + JvThrow (null_pointer_exc); +} +#endif + +#if !HANDLE_FPE +static java::lang::ArithmeticException *arithmetic_exc; +static void +throw_arithmetic_exception () +{ + if (arithmetic_exc == NULL) + arithmetic_exc = new java::lang::ArithmeticException + (JvNewStringLatin1 ("/ by zero")); + + JvThrow (arithmetic_exc); +} +#endif + +void +jvdump(jobject o) +{ + _Jv_InterpMethod::dump_object(o); +} + +/* FIXME: This is not finished! */ +void +_Jv_InterpMethod::dump_object(jobject o) +{ + java::io::PrintStream *out = java::lang::System::out; + + if (o == NULL) + { + out->println (JvNewStringLatin1 ("<null>")); + return; + } + + jclass klass = o->getClass (); + + out->print (klass->getName ()); + out->print (JvNewStringLatin1 ("@0x")); + out->print (java::lang::Integer::toHexString ((jint)o)); + out->print (JvNewStringLatin1 ("{")); +#if 0 + while (klass && klass != &ObjectClass) + { + _Jv_Field *fields = klass->fields; + int max = klass->field_count; + + for (int i = 0; i < max; ++i) + { + out->print (_Jv_NewStringUTF (field->name->data)); + out->print (JvNewStringLatin1 ("=")); + + if (JvFieldIsRef (field)) + { + if (field->flags & STATIC) + out->print (JvGetSt) + } + field = field->getNextInstanceField (); + + if (i+1 < max && klass->getSuperclass () != null) + out->print (JvNewStringLatin1 ("; ")); + } + + klass = klass->getSuperclass(); + } +#endif + out->print (JvNewStringLatin1 ("}\n")); + +} + +#endif // INTERPRETER diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h index eb0a2f95..df55425 100644 --- a/libjava/java/lang/Class.h +++ b/libjava/java/lang/Class.h @@ -21,25 +21,30 @@ details. */ extern "C" void _Jv_InitClass (jclass klass); extern "C" void _Jv_RegisterClasses (jclass *classes); +// These are the possible values for the `state' field of the class +// structure. Note that ordering is important here; in particular +// `resolved' must come between `nothing' and the other states. +// Whenever the state changes, one should notify all waiters of this +// class. +#define JV_STATE_NOTING 0 // set by compiler + +#define JV_STATE_PRELOADING 1 // can do _Jv_FindClass +#define JV_STATE_LOADING 3 // has super installed +#define JV_STATE_LOADED 5 // is complete + +#define JV_STATE_COMPILED 6 // this was a compiled class + +#define JV_STATE_PREPARED 7 // layout & static init done +#define JV_STATE_LINKED 9 // strings interned + +#define JV_STATE_IN_PROGRESS 10 // <clinit> running +#define JV_STATE_DONE 12 // + +#define JV_STATE_ERROR 14 // must be last + struct _Jv_Field; struct _Jv_VTable; -#define CONSTANT_Class 7 -#define CONSTANT_Fieldref 9 -#define CONSTANT_Methodref 10 -#define CONSTANT_InterfaceMethodref 11 -#define CONSTANT_String 8 -#define CONSTANT_Integer 3 -#define CONSTANT_Float 4 -#define CONSTANT_Long 5 -#define CONSTANT_Double 6 -#define CONSTANT_NameAndType 12 -#define CONSTANT_Utf8 1 -#define CONSTANT_Unicode 2 -#define CONSTANT_ResolvedFlag 16 -#define CONSTANT_ResolvedString (CONSTANT_String+CONSTANT_ResolvedFlag) -#define CONSTANT_ResolvedClass (CONSTANT_Class+CONSTANT_ResolvedFlag) - struct _Jv_Constants { jint size; @@ -134,9 +139,11 @@ public: return size_in_bytes; } + // finalization + void finalize (); + private: void checkMemberAccess (jint flags); - void resolveConstants (void); // Various functions to handle class initialization. java::lang::Throwable *hackTrampoline (jint, java::lang::Throwable *); @@ -147,12 +154,6 @@ private: friend _Jv_Method *_Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name, _Jv_Utf8Const *signature); friend void _Jv_InitClass (jclass klass); - friend void _Jv_RegisterClasses (jclass *classes); - friend jclass _Jv_FindClassInCache (_Jv_Utf8Const *name, - java::lang::ClassLoader *loader); - friend jclass _Jv_FindArrayClass (jclass element); - friend jclass _Jv_NewClass (_Jv_Utf8Const *name, jclass superclass, - java::lang::ClassLoader *loader); friend jfieldID JvGetFirstInstanceField (jclass); friend jint JvNumInstanceFields (jclass); @@ -165,6 +166,41 @@ private: friend class _Jv_PrimClass; + // Friends classes and functions to implement the ClassLoader + friend class java::lang::ClassLoader; + + friend void _Jv_WaitForState (jclass, int); + friend void _Jv_RegisterClasses (jclass *classes); + friend void _Jv_RegisterInitiatingLoader (jclass,java::lang::ClassLoader*); + friend void _Jv_UnregisterClass (jclass); + friend jclass _Jv_FindClass (_Jv_Utf8Const *name, + java::lang::ClassLoader *loader); + friend jclass _Jv_FindClassInCache (_Jv_Utf8Const *name, + java::lang::ClassLoader *loader); + friend jclass _Jv_FindArrayClass (jclass element, + java::lang::ClassLoader *loader); + friend jclass _Jv_NewClass (_Jv_Utf8Const *name, jclass superclass, + java::lang::ClassLoader *loader); + + friend void _Jv_InternClassStrings (jclass); + +#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); + friend void* _Jv_ResolvePoolEntry (jclass, int); + friend void _Jv_PrepareClass (jclass); + + friend class _Jv_ClassReader; + friend class _Jv_InterpClass; + friend class _Jv_InterpMethod; + friend class _Jv_InterpMethodInvocation; +#endif + #ifdef JV_MARKOBJ_DECL friend JV_MARKOBJ_DECL; #endif diff --git a/libjava/java/lang/Class.java b/libjava/java/lang/Class.java index 4ffccea..bc826e9 100644 --- a/libjava/java/lang/Class.java +++ b/libjava/java/lang/Class.java @@ -152,4 +152,7 @@ public final class Class implements Serializable // Initialize the class. private native void initializeClass (); + + // finalization + protected native void finalize (); } diff --git a/libjava/java/lang/ClassLoader.java b/libjava/java/lang/ClassLoader.java index 048cea7..f0b533f 100644 --- a/libjava/java/lang/ClassLoader.java +++ b/libjava/java/lang/ClassLoader.java @@ -9,86 +9,394 @@ Libgcj License. Please consult the file "LIBGCJ_LICENSE" for details. */ package java.lang; + import java.io.InputStream; -import java.util.Hashtable; +import java.net.URL; +import java.net.URLConnection; +import java.util.Stack; /** - * @author Tom Tromey <tromey@cygnus.com> - * @date October 28, 1998 + * The class <code>ClassLoader</code> is intended to be subclassed by + * applications in order to describe new ways of loading classes, + * such as over the network. + * + * @author Kresten Krab Thorup */ /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 * Status: Just a stub; not useful at all. */ -public abstract class ClassLoader -{ - protected ClassLoader () - { - cache = new Hashtable (); - } +public abstract class ClassLoader { - protected final Class defineClass (String className, byte[] bytecode, - int offset, int length) - { - throw new ClassFormatError ("defineClass unimplemented"); - } + static private ClassLoader system; + + private static native ClassLoader getVMClassLoader0 (); - protected final Class defineClass (byte[] bytecodes, - int offset, int length) - { - return defineClass (null, bytecodes, offset, length); - } + static public ClassLoader getSystemClassLoader () { + if (system == null) + system = getVMClassLoader0 (); + return system; + } - protected final Class findLoadedClass (String className) - { - return (Class) cache.get(className); - } + /** + * Creates a <code>ClassLoader</code>. The only thing this + * constructor does, is to call + * <code>checkCreateClassLoader</code> on the current + * security manager. + * @exception java.lang.SecurityException if not allowed + */ + protected ClassLoader() + { + SecurityManager security = System.getSecurityManager (); + if (security != null) + security.checkCreateClassLoader (); + } - protected final Class findSystemClass (String className) - throws ClassNotFoundException - { - Class c = system.findLoadedClass(className); - system.resolveClass(c); - return c; - } + /** + * Loads and link the class by the given name. + * @param name the name of the class. + * @return the class loaded. + * @see ClassLoader#loadClass(String,boolean) + * @exception java.lang.ClassNotFoundException + */ + public Class loadClass(String name) + throws java.lang.ClassNotFoundException, java.lang.LinkageError + { + return loadClass (name, true); + } - // FIXME: Needs URL. - // public URL getResource (String resName); + /** + * Loads the class by the given name. + * As per java 1.1, this has been deprecated. Use + * <code>loadClass(String)</code> + * instead. + * @param name the name of the class. + * @param link if the class should be linked. + * @return the class loaded. + * @exception java.lang.ClassNotFoundException + * @deprecated + */ + protected abstract Class loadClass(String name, boolean link) + throws java.lang.ClassNotFoundException, java.lang.LinkageError; - public InputStream getResourceAsStream (String resName) - { - return null; - } + /** + * Defines a class, given the class-data. According to the JVM, this + * method should not be used; instead use the variant of this method + * in which the name of the class being defined is specified + * explicitly. + * <P> + * If the name of the class, as specified (implicitly) in the class + * data, denotes a class which has already been loaded by this class + * loader, an instance of + * <code>java.lang.ClassNotFoundException</code> will be thrown. + * + * @param data bytes in class file format. + * @param off offset to start interpreting data. + * @param len length of data in class file. + * @return the class defined. + * @exception java.lang.ClassNotFoundException + * @exception java.lang.LinkageError + * @see ClassLoader#defineClass(String,byte[],int,int) */ + protected final Class defineClass(byte[] data, int off, int len) + throws java.lang.ClassNotFoundException, java.lang.LinkageError + { + return defineClass (null, data, off, len); + } - // FIXME: Needs URL. - // public static final URL getSystemResource (String resName); + /** + * Defines a class, given the class-data. This is preferable + * over <code>defineClass(byte[],off,len)</code> since it is more + * secure. If the expected name does not match that of the class + * file, <code>ClassNotFoundException</code> is thrown. If + * <code>name</code> denotes the name of an already loaded class, a + * <code>LinkageError</code> is thrown. + * <p> + * + * FIXME: How do we assure that the class-file data is not being + * modified, simultaneously with the class loader running!? If this + * was done in some very clever way, it might break security. + * Right now I am thinking that defineclass should make sure never to + * read an element of this array more than once, and that that would + * assure the ``immutable'' appearance. It is still to be determined + * if this is in fact how defineClass operates. + * + * @param name the expected name. + * @param data bytes in class file format. + * @param off offset to start interpreting data. + * @param len length of data in class file. + * @return the class defined. + * @exception java.lang.ClassNotFoundException + * @exception java.lang.LinkageError + */ + protected final synchronized Class defineClass(String name, + byte[] data, + int off, + int len) + throws java.lang.ClassNotFoundException, java.lang.LinkageError + { + if (data==null || data.length < off+len || off<0 || len<0) + throw new ClassFormatError ("arguments to defineClass " + + "are meaningless"); - public static final InputStream getSystemResourceAsStream (String resName) - { - return null; - } + // as per 5.3.5.1 + if (name != null && findLoadedClass (name) != null) + throw new java.lang.LinkageError ("class " + + name + + " already loaded"); - protected abstract Class loadClass (String className, boolean resolve) - throws ClassNotFoundException; - public Class loadClass (String name) throws ClassNotFoundException - { - return loadClass (name, true); - } + try { + // Since we're calling into native code here, + // we better make sure that any generated + // exception is to spec! + + return defineClass0 (name, data, off, len); + + } catch (java.lang.LinkageError x) { + throw x; // rethrow + + } catch (java.lang.ClassNotFoundException x) { + throw x; // rethrow + + } catch (java.lang.VirtualMachineError x) { + throw x; // rethrow + + } catch (java.lang.Throwable x) { + // This should never happen, or we are beyond spec. + + throw new InternalError ("Unexpected exception " + + "while defining class " + + name + ": " + + x.toString ()); + } + } + + /** This is the entry point of defineClass into the native code */ + private native Class defineClass0 (String name, + byte[] data, + int off, + int len) + throws java.lang.ClassNotFoundException, java.lang.LinkageError; - protected final void resolveClass (Class c) - { - // Nothing for now. - } - protected final void setSigners (Class cl, Object[] signers) - { - // Nothing for now. + /** This is called by defineClass0, once the "raw" and uninitialized + * class object has been created, and handles exceptions generated + * while actually defining the class (_Jv_DefineClass). defineClass0 + * holds the lock on the new class object, so it needs to capture + * these exceptions. */ + + private static Throwable defineClass1 (Class klass, byte[] data, + int offset, int length) + { + try { + defineClass2 (klass, data, offset, length); + } catch (Throwable x) { + return x; } + return null; + } + + /** This is just a wrapper for _Jv_DefineClass */ + private static native void defineClass2 (Class klass, byte[] data, + int offset, int length) + throws Throwable; + + /** + * Link the given class. This will bring the class to a state where + * the class initializer can be run. Linking involves the following + * steps: + * <UL> + * <LI> Prepare (allocate and internalize) the constant strings that + * are used in this class. + * <LI> Allocate storage for static fields, and define the layout + * of instance fields. + * <LI> Perform static initialization of ``static final'' int, + * long, float, double and String fields for which there is a + * compile-time constant initializer. + * <LI> Create the internal representation of the ``vtable''. + * </UL> + * For <code>gcj</code>-compiled classes, only the first step is + * performed. The compiler will have done the rest already. + * <P> + * This is called by the system automatically, + * as part of class initialization; there is no reason to ever call + * this method directly. + * <P> + * For historical reasons, this method has a name which is easily + * misunderstood. Java classes are never ``resolved''. Classes are + * linked; whereas method and field references are resolved. + * <P> + * FIXME: The JDK documentation declares this method + * <code>final</code>, we declare it <code>static</code> -- any + * objections? This allows us to call it directly from native code + * with less hassle. + * + * @param clazz the class to link. + * @exception java.lang.LinkageError + */ + protected static void resolveClass(Class clazz) + throws java.lang.LinkageError + { + synchronized (clazz) + { + try { + linkClass0 (clazz); + } catch (Throwable x) { + markClassErrorState0 (clazz); + + if (x instanceof Error) + throw (Error)x; + else + throw new java.lang.InternalError + ("unexpected exception during linking: " + x); + } + } + } + + /** Internal method. Calls _Jv_PrepareClass and + * _Jv_InternClassStrings. This is only called from resolveClass. */ + private static native void linkClass0(Class clazz) + throws java.lang.LinkageError; + + /** Internal method. Marks the given clazz to be in an erroneous + * state, and calls notifyAll() on the class object. This should only + * be called when the caller has the lock on the class object. */ + private static native void markClassErrorState0(Class clazz); + + + /** + * Returns a class found in a system-specific way, typically + * via the <code>java.class.path</code> system property. + * + * @param name the class to resolve. + * @return the class loaded. + * @exception java.lang.LinkageError + * @exception java.lang.ClassNotFoundException + */ + protected native static Class findSystemClass(String name) + throws java.lang.ClassNotFoundException, java.lang.LinkageError; + + /* + * Does currently nothing. + */ + protected final void setSigners(Class claz, Object[] signers) { + /* claz.setSigners (signers); */ + } + + /* + * If a class named <code>name</code> was previously loaded using + * this <code>ClassLoader</code>, then it is returned. Otherwise + * it returns <code>null</code>. + * @param name class to find. + * @return the class loaded, or null. + */ + protected native Class findLoadedClass(String name); - // Class cache. - private Hashtable cache; + public static final InputStream getSystemResourceAsStream(String name) { + return system.getResourceAsStream (name); + } - // The system class loader. FIXME: should have an actual value - private static final ClassLoader system = null; + public static final URL getSystemResource(String name) { + return system.getResource (name); + } + + public static final byte[] getSystemResourceAsBytes(String name) { + return system.getResourceAsBytes (name); + } + + /** + * Return an InputStream representing the resource name. + * This is essentially like + * <code>getResource(name).openStream()</code>, except + * it masks out any IOException and returns null on failure. + * @param name resource to load + * @return an InputStream, or null + * @see java.lang.ClassLoader#getResource(String) + * @see java.lang.ClassLoader#getResourceAsBytes(String) + * @see java.io.InputStream + */ + public InputStream getResourceAsStream(String name) + { + try { + URL res = getResource (name); + if (res == null) return null; + return res.openStream (); + } catch (java.io.IOException x) { + return null; + } + } + + /** + * Return a byte array <code>byte[]</code> representing the + * resouce <code>name</code>. This only works for resources + * that have a known <code>content-length</code>, and + * it will block while loading the resource. Returns null + * for error conditions.<p> + * Since it is synchroneous, this is only convenient for + * resources that are "readily" available. System resources + * can conveniently be loaded this way, and the runtime + * system uses this to load class files. <p> + * To find the class data for a given class, use + * something like the following: + * <ul><code> + * String res = clazz.getName().replace ('.', '/')) + ".class";<br> + * byte[] data = getResourceAsBytes (res); + * </code></ul> + * @param name resource to load + * @return a byte array, or null + * @see java.lang.ClassLoader#getResource(String) + * @see java.lang.ClassLoader#getResourceAsStream(String) + */ + public byte[] getResourceAsBytes(String name) { + try { + URL res = getResource (name); + if (res == null) return null; + URLConnection conn = res.openConnection (); + int len = conn.getContentLength (); + if (len == -1) return null; + return readbytes (conn.getInputStream (), len); + } catch (java.io.IOException x) { + return null; + } + } + + /** + * Return an java.io.URL representing the resouce <code>name</code>. + * @param name resource to load + * @return a URL, or null if there is no such resource. + * @see java.lang.ClassLoader#getResourceAsBytes(String) + * @see java.lang.ClassLoader#getResourceAsStream(String) + * @see java.io.URL + */ + public URL getResource(String name) { + return null; + } + + /** + * Utility routine to read a resource fully, even if the given + * InputStream only provides partial results. + */ + private static byte[] readbytes (InputStream is, int length) + { + try { + + byte[] data = new byte[length]; + int read; + int off = 0; + + while (off != length) + { + read = is.read (data, off, (int) (length-off)); + + if (read == -1) + return null; + + off += read; + } + + return data; + } catch (java.io.IOException x) { + return null; + } + } } diff --git a/libjava/java/lang/FirstThread.java b/libjava/java/lang/FirstThread.java index ec0f1db..0dd5c9c 100644 --- a/libjava/java/lang/FirstThread.java +++ b/libjava/java/lang/FirstThread.java @@ -19,12 +19,30 @@ package java.lang; final class FirstThread extends Thread { - public native void run (); + public native void run0 (); + public void run () + { + try { + run0 (); + } catch (Throwable ex) { + System.err.println ("uncaught exception at top level"); + ex.printStackTrace (); + } + } public FirstThread (ThreadGroup g, Class k, Object o) { super (g, null, "main"); klass = k; + klass_name = null; + args = o; + } + + public FirstThread (ThreadGroup g, String class_name, Object o) + { + super (g, null, "main"); + klass = null; + klass_name = class_name; args = o; } @@ -36,5 +54,6 @@ final class FirstThread extends Thread // Private data. private Class klass; + private String klass_name; private Object args; } diff --git a/libjava/java/lang/VMClassLoader.java b/libjava/java/lang/VMClassLoader.java new file mode 100644 index 0000000..026f6d8 --- /dev/null +++ b/libjava/java/lang/VMClassLoader.java @@ -0,0 +1,117 @@ +/* Copyright (C) 1999 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. */ + +/* Author: Kresten Krab Thorup <krab@gnu.org> */ + +package java.lang; + +import java.io.*; +import java.net.URL; +import gnu.gcj.util.path.SearchPath; + +final class VMClassLoader extends java.lang.ClassLoader +{ + private SearchPath path; + private final String path_seperator; + private final String file_seperator; + private final char file_seperator_char; + + private VMClassLoader () { + path_seperator = System.getProperty ("path.separator", ":"); + file_seperator = System.getProperty ("file.separator", "/"); + + file_seperator_char = file_seperator.charAt (0); + + String class_path = System.getProperty ("java.class.path", "."); + path = new SearchPath (class_path); + } + + protected Class loadClass(String name, + boolean resolve) + throws java.lang.ClassNotFoundException, java.lang.LinkageError + { + return loadClassInternal (name, resolve, false); + } + + /** I'm a little in doubt here, if this method is + actually supposed to throw a LinkageError, or not. + The spec, 20.14.3, is a little unclear. It says: + + `` The general contract of loadClass is that, given the name + of a class, it either returns the Class object for the class + or throws a ClassNotFoundException.'' + + However, by making LinkageError a checked exception, + i.e., mention it directly in the throws clause, + we'll force caller to consider that case as well. + **/ + + protected Class loadClassInternal(String name, + boolean resolve, + boolean fromBootLoader) + throws java.lang.ClassNotFoundException, java.lang.LinkageError + { + Class clazz; + + /** TODO: call _Jv_VerifyClassName **/ + if ( (name.indexOf ('/') != -1) + || (name.charAt (0) == '.') + || (name.indexOf (file_seperator) != -1) + || (name.indexOf ("..") != -1)) + { + throw new IllegalArgumentException (name); + } + + // already loaded? + clazz = findLoadedClass (name); + + // we need access to the boot class loader here + if (clazz == null && !fromBootLoader) + clazz = findBootClass (name); + + if (clazz == null) + { + StringBuffer res = new StringBuffer (); + + // here we do actually replace .'s with /'s because + // we're going to find something in the file system. + res.append (name.replace ('.', file_seperator_char)); + res.append (".class"); + + byte[] data = getResourceAsBytes (res.toString ()); + + if (data == null) + throw new ClassNotFoundException (name); + + clazz = defineClass (name, data, 0, data.length); + + } + + if (resolve && clazz != null) + resolveClass (clazz); + + return clazz; + } + + private native Class findBootClass (String name); + + public InputStream getResourceAsStream(String name) + { + return path.getStream (name); + } + + public URL getResource(String name) + { + return path.getURL (name); + } + + public byte[] getResourceAsBytes(String name) + { + return path.getBytes (name); + } +} diff --git a/libjava/java/lang/VirtualMachineError.java b/libjava/java/lang/VirtualMachineError.java index dcc907c..ee6d8e8 100644 --- a/libjava/java/lang/VirtualMachineError.java +++ b/libjava/java/lang/VirtualMachineError.java @@ -20,6 +20,11 @@ package java.lang; * Status: Believed complete and correct. */ +/* FIXME: We should consider adding some special error message when this + * exception is thrown, or maybe if it being caught at top-level. Such + * a message would direct the user to send a bug report to + * gcj-bugs@cygnus.com, or something like that. --KKT */ + public abstract class VirtualMachineError extends Error { public VirtualMachineError () diff --git a/libjava/java/lang/natClass.cc b/libjava/java/lang/natClass.cc index 1768df5..367f14a 100644 --- a/libjava/java/lang/natClass.cc +++ b/libjava/java/lang/natClass.cc @@ -39,6 +39,8 @@ details. */ #include <java/lang/System.h> #include <java/lang/SecurityManager.h> +#include <java-cpool.h> + #define CloneableClass _CL_Q34java4lang9Cloneable @@ -59,28 +61,6 @@ static _Jv_Utf8Const *void_signature = _Jv_makeUtf8Const ("()V", 3); static _Jv_Utf8Const *clinit_name = _Jv_makeUtf8Const ("<clinit>", 8); static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6); -// These are the possible values for the `state' field. They more or -// less follow the section numbers in the Java Language Spec. Right -// now we don't bother to represent other interesting states, e.g. the -// states a class might inhabit before it is prepared. Note that -// ordering is important here; in particular `resolved' must come -// between `nothing' and the other states. -#define STATE_NOTHING 0 -#define STATE_RESOLVED 1 -#define STATE_IN_PROGRESS 6 -#define STATE_DONE 9 -#define STATE_ERROR 10 - -// Size of local hash table. -#define HASH_LEN 256 - -// Hash function for Utf8Consts. -#define HASH_UTF(Utf) (((Utf)->hash) % HASH_LEN) - -// This is the table we use to keep track of loaded classes. See Spec -// section 12.2. -static jclass loaded_classes[HASH_LEN]; - jclass @@ -111,6 +91,9 @@ java::lang::Class::forName (jstring className) #endif if (! klass) JvThrow (new java::lang::ClassNotFoundException (className)); + + _Jv_InitClass (klass); + return klass; } @@ -380,33 +363,13 @@ java::lang::Class::newInstance (void) return r; } -// Initialize the constants. void -java::lang::Class::resolveConstants (void) +java::lang::Class::finalize (void) { - for (int i = 0; i < constants.size; ++i) - { - if (constants.tags[i] == CONSTANT_String) - { - jstring str; - str = _Jv_NewStringUtf8Const ((_Jv_Utf8Const *) constants.data[i]); - constants.data[i] = (void *) str; - constants.tags[i] = CONSTANT_ResolvedString; - } - else if (constants.tags[i] == CONSTANT_Class) - { - _Jv_Utf8Const *name = (_Jv_Utf8Const *) constants.data[i]; - jclass klass = _Jv_FindClassFromSignature (name->data, loader); - if (! klass) - { - jstring str = _Jv_NewStringUtf8Const (name); - JvThrow (new java::lang::ClassNotFoundException (str)); - } - - constants.data[i] = (void *) klass; - constants.tags[i] = CONSTANT_ResolvedClass; - } - } +#ifdef INTERPRETER + JvAssert (_Jv_IsInterpretedClass (this)); + _Jv_UnregisterClass (this); +#endif } // FIXME. @@ -424,38 +387,52 @@ void java::lang::Class::initializeClass (void) { // Short-circuit to avoid needless locking. - if (state == STATE_DONE) + if (state == JV_STATE_DONE) return; - // Step 1. - _Jv_MonitorEnter (this); + // do this before we enter the monitor below, since this can cause + // exceptions. Here we assume, that reading "state" is an atomic + // operation, I pressume that is true? --Kresten + if (state < JV_STATE_LINKED) + { +#ifdef INTERPRETER + if (_Jv_IsInterpretedClass (this)) + { + java::lang::ClassLoader::resolveClass (this); - // FIXME: This should actually be handled by calling into the class - // loader. For now we put it here. - if (state < STATE_RESOLVED) + // Step 1. + _Jv_MonitorEnter (this); + } + else +#endif + { + // Step 1. + _Jv_MonitorEnter (this); + _Jv_InternClassStrings (this); + } + } + else { - // We set the state before calling resolveConstants to avoid - // infinite recursion when processing String or Class. - state = STATE_RESOLVED; - resolveConstants (); + // Step 1. + _Jv_MonitorEnter (this); } // Step 2. java::lang::Thread *self = java::lang::Thread::currentThread(); // FIXME: `self' can be null at startup. Hence this nasty trick. self = (java::lang::Thread *) ((long) self | 1); - while (state == STATE_IN_PROGRESS && thread && thread != self) + while (state == JV_STATE_IN_PROGRESS && thread && thread != self) wait (); // Steps 3 & 4. - if (state == STATE_DONE || state == STATE_IN_PROGRESS || thread == self) + if (state == JV_STATE_DONE || state == JV_STATE_IN_PROGRESS || thread == self) { _Jv_MonitorExit (this); return; } // Step 5. - if (state == STATE_ERROR) + if (state == JV_STATE_ERROR) { _Jv_MonitorExit (this); JvThrow (new java::lang::NoClassDefFoundError); @@ -463,7 +440,7 @@ java::lang::Class::initializeClass (void) // Step 6. thread = self; - state = STATE_IN_PROGRESS; + state = JV_STATE_IN_PROGRESS; _Jv_MonitorExit (this); // Step 7. @@ -477,7 +454,7 @@ java::lang::Class::initializeClass (void) { // Caught an exception. _Jv_MonitorEnter (this); - state = STATE_ERROR; + state = JV_STATE_ERROR; notify (); _Jv_MonitorExit (this); JvThrow (except); @@ -492,7 +469,7 @@ java::lang::Class::initializeClass (void) if (! except) { _Jv_MonitorEnter (this); - state = STATE_DONE; + state = JV_STATE_DONE; } else { @@ -503,7 +480,7 @@ java::lang::Class::initializeClass (void) except = hackTrampoline(2, except); } _Jv_MonitorEnter (this); - state = STATE_ERROR; + state = JV_STATE_ERROR; } notify (); _Jv_MonitorExit (this); @@ -530,6 +507,64 @@ _Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name, return NULL; } +#define MCACHE_SIZE 1013 + +struct _Jv_mcache { + jclass klass; + _Jv_Method *method; +}; + +static _Jv_mcache method_cache[MCACHE_SIZE]; +static int method_cache_count; + +static void* +_Jv_FindMethodInCache (jclass klass, + _Jv_Utf8Const *name, + _Jv_Utf8Const *signature) +{ + for (int index = name->hash % MCACHE_SIZE; + method_cache[index].klass != NULL; + index = (index+1) % MCACHE_SIZE) + { + _Jv_mcache *mc = (method_cache+index); + _Jv_Method *m = mc->method; + + if (mc->klass == klass + && m != NULL // thread safe check + && _Jv_equalUtf8Consts (m->name, name) + && _Jv_equalUtf8Consts (m->signature, signature)) + { + return mc->method->ncode; + } + } + return NULL; +} + +static void +_Jv_AddMethodToCache (jclass klass, + _Jv_Method *method) +{ + _Jv_MonitorEnter (&ClassClass); + + if (method_cache_count > MCACHE_SIZE*2/3) + { + for (int i = 0; i < MCACHE_SIZE; i++) + method_cache[i].klass = 0; + } + + for (int index = method->name->hash % MCACHE_SIZE; + method_cache[index].klass != NULL; + index = (index+1) % MCACHE_SIZE) + { + method_cache[index].method = method; + method_cache[index].klass = klass; + } + + method_cache_count += 1; + + _Jv_MonitorExit (&ClassClass); +} + void * _Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name, _Jv_Utf8Const *signature) @@ -539,6 +574,14 @@ _Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name, // 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; for (; klass; klass = klass->getSuperclass()) { @@ -553,6 +596,8 @@ _Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name, if (! java::lang::reflect::Modifier::isPublic(meth->accflags)) JvThrow (new java::lang::IllegalAccessError); + _Jv_AddMethodToCache (klass, meth); + return meth->ncode; } JvThrow (new java::lang::IncompatibleClassChangeError); @@ -565,219 +610,6 @@ _Jv_InitClass (jclass klass) klass->initializeClass(); } -// This function is called many times during startup, before main() is -// run. We do our runtime initialization here the very first time we -// are called. At that point in time we know for certain we are -// running single-threaded, so we don't need to lock when modifying -// `init'. CLASSES is NULL-terminated. -void -_Jv_RegisterClasses (jclass *classes) -{ - static bool init = false; - - if (! init) - { - init = true; - _Jv_InitThreads (); - _Jv_InitGC (); - _Jv_InitializeSyncMutex (); - } - - JvSynchronize sync (&ClassClass); - for (; *classes; ++classes) - { - jclass klass = *classes; - jint hash = HASH_UTF (klass->name); - klass->next = loaded_classes[hash]; - loaded_classes[hash] = klass; - } -} - -void -_Jv_RegisterClass (jclass klass) -{ - jclass classes[2]; - classes[0] = klass; - classes[1] = NULL; - _Jv_RegisterClasses (classes); -} - -jclass -_Jv_FindClassInCache (_Jv_Utf8Const *name, java::lang::ClassLoader *loader) -{ - JvSynchronize sync (&ClassClass); - jint hash = HASH_UTF (name); - jclass klass; - for (klass = loaded_classes[hash]; klass; klass = klass->next) - { - if (loader == klass->loader && _Jv_equalUtf8Consts (name, klass->name)) - break; - } - return klass; -} - -#if 0 -jclass -_Jv_FindClassInCache (jstring name, java::lang::ClassLoader *loader) -{ - JvSynchronize sync (&ClassClass); - jint hash = name->hashCode(); - jclass klass = loaded_classes[(_Jv_ushort) hash % HASH_LEN]; - for ( ; klass; klass = klass->next) - { - if (loader == klass->loader - && _Jv_equalUtf8Consts (klass->name, name, hash)) - break; - } - return klass; -} -#endif - -jclass -_Jv_FindClass (_Jv_Utf8Const* name, java::lang::ClassLoader *loader) -{ - jclass klass = _Jv_FindClassInCache (name, loader); - if (loader && ! klass) - { - klass = loader->loadClass(_Jv_NewStringUtf8Const (name)); - if (klass) - _Jv_RegisterClass (klass); - } - return klass; -} - -#if 0 -jclass -_Jv_FindClass (jstring name, java::lang::ClassLoader *loader) -{ - jclass klass = _Jv_FindClassInCache (name, loader); - if (loader && ! klass) - { - klass = loader->loadClass(name); - if (klass) - _Jv_RegisterClass (klass); - } - return klass; -} -#endif - -jclass -_Jv_NewClass (_Jv_Utf8Const *name, jclass superclass, - java::lang::ClassLoader *loader) -{ - jclass ret = (jclass) JvAllocObject (&ClassClass); - - ret->next = NULL; - ret->name = name; - ret->accflags = 0; - ret->superclass = superclass; - ret->constants.size = 0; - ret->constants.tags = NULL; - ret->constants.data = NULL; - ret->methods = NULL; - ret->method_count = 0; - ret->vtable_method_count = 0; - ret->fields = NULL; - ret->size_in_bytes = 0; - ret->field_count = 0; - ret->static_field_count = 0; - ret->vtable = NULL; - ret->interfaces = NULL; - ret->loader = loader; - ret->interface_count = 0; - ret->state = 0; - ret->thread = NULL; - - _Jv_RegisterClass (ret); - - return ret; -} - -jclass -_Jv_FindArrayClass (jclass element) -{ - _Jv_Utf8Const *array_name; - int len; - if (element->isPrimitive()) - { - // For primitive types the array is cached in the class. - jclass ret = (jclass) element->methods; - if (ret) - return ret; - len = 3; - } - else - len = element->name->length + 5; - - { - char signature[len]; - int index = 0; - signature[index++] = '['; - // Compute name of array class to see if we've already cached it. - if (element->isPrimitive()) - { - signature[index++] = (char) element->method_count; - } - else - { - size_t length = element->name->length; - const char *const name = element->name->data; - if (name[0] != '[') - signature[index++] = 'L'; - memcpy (&signature[index], name, length); - index += length; - if (name[0] != '[') - signature[index++] = ';'; - } - array_name = _Jv_makeUtf8Const (signature, index); - } - - jclass array_class = _Jv_FindClassInCache (array_name, element->loader); - - if (! array_class) - { - // Create new array class. - array_class = _Jv_NewClass (array_name, &ObjectClass, element->loader); - - // Note that `vtable_method_count' doesn't include the initial - // NULL slot. - int dm_count = ObjectClass.vtable_method_count + 1; - - // Create a new vtable by copying Object's vtable (except the - // class pointer, of course). Note that we allocate this as - // unscanned memory -- the vtables are handled specially by the - // GC. - int size = (sizeof (_Jv_VTable) + - ((dm_count - 1) * sizeof (void *))); - _Jv_VTable *vtable = (_Jv_VTable *) _Jv_AllocBytes (size); - vtable->clas = array_class; - memcpy (vtable->method, ObjectClass.vtable->method, - dm_count * sizeof (void *)); - array_class->vtable = vtable; - array_class->vtable_method_count = ObjectClass.vtable_method_count; - - // Stash the pointer to the element type. - array_class->methods = (_Jv_Method *) element; - - // Register our interfaces. - // FIXME: for JDK 1.2 we need Serializable. - static jclass interfaces[] = { &CloneableClass }; - array_class->interfaces = interfaces; - array_class->interface_count = 1; - - // FIXME: initialize other Class instance variables, - // e.g. `fields'. - - array_class->state = STATE_DONE; - } - - // For primitive types, point back at this array. - if (element->isPrimitive()) - element->methods = (_Jv_Method *) array_class; - - return array_class; -} - jboolean _Jv_IsInstanceOf(jobject obj, jclass cl) { diff --git a/libjava/java/lang/natClassLoader.cc b/libjava/java/lang/natClassLoader.cc new file mode 100644 index 0000000..13452ec --- /dev/null +++ b/libjava/java/lang/natClassLoader.cc @@ -0,0 +1,624 @@ +// natClassLoader.cc - Implementation of java.lang.ClassLoader native methods. + +/* Copyright (C) 1999 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. */ + +/* Author: Kresten Krab Thorup <krab@gnu.org> */ + +#include <config.h> + +#include <stdlib.h> +#include <string.h> + +#include <cni.h> +#include <jvm.h> +#include <java/lang/Character.h> +#include <java/lang/Thread.h> +#include <java/lang/ClassLoader.h> +#include <java/lang/VMClassLoader.h> +#include <java/lang/InternalError.h> +#include <java/lang/LinkageError.h> +#include <java/lang/ClassFormatError.h> +#include <java/lang/NoClassDefFoundError.h> +#include <java/lang/ClassNotFoundException.h> +#include <java/lang/ClassCircularityError.h> +#include <java/lang/IncompatibleClassChangeError.h> +#include <java/lang/reflect/Modifier.h> + +#include <java-interp.h> + +#define CloneableClass _CL_Q34java4lang9Cloneable +extern java::lang::Class CloneableClass; +#define ObjectClass _CL_Q34java4lang6Object +extern java::lang::Class ObjectClass; +#define ClassClass _CL_Q34java4lang5Class +extern java::lang::Class ClassClass; +#define VMClassLoaderClass _CL_Q34java4lang17VMClassLoader +extern java::lang::Class VMClassLoader; +#define ClassLoaderClass _CL_Q34java4lang11ClassLoader +extern java::lang::Class ClassLoaderClass; + +/////////// java.lang.ClassLoader native methods //////////// + +#ifdef INTERPRETER +java::lang::VMClassLoader *redirect = 0; +#endif + +java::lang::ClassLoader* +java::lang::ClassLoader::getVMClassLoader0 () +{ +#ifdef INTERPRETER + if (redirect == 0) + redirect = new java::lang::VMClassLoader; + return redirect; +#else + return 0; +#endif +} + +void +java::lang::ClassLoader::defineClass2 (jclass klass, jbyteArray data, + jint offset, jint length) +{ +#ifdef INTERPRETER + _Jv_DefineClass (klass, data, offset, length); +#endif +} + +java::lang::Class * +java::lang::ClassLoader::defineClass0 (jstring name, + jbyteArray data, + jint offset, + jint length) +{ +#ifdef INTERPRETER + jclass klass; + klass = (jclass) JvAllocObject (&ClassClass, sizeof (_Jv_InterpClass)); + + // synchronize on the class, so that it is not + // attempted initialized until we're done loading. + _Jv_MonitorEnter (klass); + + // record which is the defining loader + klass->loader = this; + + // register that we are the initiating loader... + if (name != 0) + { + _Jv_Utf8Const * name2 = _Jv_makeUtf8Const (name); + + _Jv_VerifyClassName (name2); + + klass->name = name2; + } + + // this will do the magic. loadInto also operates + // as an exception trampoline for now... + Throwable *ex = defineClass1 (klass, data, offset, length); + + if (ex) // we failed to load it + { + klass->state = JV_STATE_ERROR; + klass->notifyAll (); + + _Jv_UnregisterClass (klass); + + _Jv_MonitorExit (klass); + + // FIXME: Here we may want to test that EX does + // indeed represent a valid exception. That is, + // anything but ClassNotFoundException, + // or some kind of Error. + + JvThrow (ex); + } + + // if everything proceeded sucessfully, we're loaded. + JvAssert (klass->state == JV_STATE_LOADED); + + // if an exception is generated, this is initially missed. + // however, we come back here in handleException0 below... + _Jv_MonitorExit (klass); + + return klass; + +#else // INTERPRETER + + return 0; +#endif +} + +void +_Jv_WaitForState (jclass klass, int state) +{ + if (klass->state >= state) + return; + + _Jv_MonitorEnter (klass) ; + + if (state == JV_STATE_LINKED) + { + _Jv_MonitorExit (klass); + _Jv_InternClassStrings (klass); + return; + } + + java::lang::Thread *self = java::lang::Thread::currentThread(); + + // this is similar to the strategy for class initialization. + // if we already hold the lock, just leave. + while (klass->state <= state + && klass->thread + && klass->thread != self) + klass->wait (); + + _Jv_MonitorExit (klass); + + if (klass->state == JV_STATE_ERROR) + { + _Jv_Throw (new java::lang::LinkageError ()); + } +} + +// Finish linking a class. Only called from ClassLoader::resolveClass. +void +java::lang::ClassLoader::linkClass0 (java::lang::Class *klass) +{ + if (klass->state >= JV_STATE_LINKED) + return; + +#ifdef INTERPRETER + if (_Jv_IsInterpretedClass (klass)) + { + _Jv_PrepareClass (klass); + } +#endif + + _Jv_InternClassStrings (klass); +} + +void +java::lang::ClassLoader::markClassErrorState0 (java::lang::Class *klass) +{ + klass->state = JV_STATE_ERROR; + klass->notifyAll (); +} + + +/** this is the only native method in VMClassLoader, so + we define it here. */ +jclass +java::lang::VMClassLoader::findBootClass (jstring name) +{ + return _Jv_FindClassInCache (_Jv_makeUtf8Const (name), 0); +} + +jclass +java::lang::ClassLoader::findLoadedClass (jstring name) +{ + return _Jv_FindClassInCache (_Jv_makeUtf8Const (name), this); +} + +jclass +java::lang::ClassLoader::findSystemClass (jstring name) +{ + return _Jv_FindClass (_Jv_makeUtf8Const (name), 0); +} + + +/* This is the final step of linking, internalizing the constant strings + * of a class. This is called for both compiled and interpreted + * classes, and it is *only* called from ClassLoader::linkClass0, + * which is always in a context where the current thread has a lock on + * the class in question. We define it here, and not in resolve.cc, so that + * the entire resolve.cc can be #ifdef'ed away when not using the + * interpreter. */ +void +_Jv_InternClassStrings(jclass klass) +{ + if (klass->state >= JV_STATE_LINKED) + return; + + // short-circuit, so that mutually dependent classes are ok + klass->state = JV_STATE_LINKED; + + _Jv_Constants *pool = &klass->constants; + for (int i = 1; i < pool->size; ++i) + { + if (pool->tags[i] == JV_CONSTANT_String) + { + jstring str; + str = _Jv_NewStringUtf8Const ((_Jv_Utf8Const *) pool->data[i]); + pool->data[i] = (void *) str; + pool->tags[i] |= JV_CONSTANT_ResolvedFlag; + } + } + + klass->notifyAll (); +} + + +// +// A single class can have many "initiating" class loaders, +// and a single "defining" class loader. The Defining +// class loader is what is returned from Class.getClassLoader() +// and is used when loading dependent classes during resolution. +// The set of initiating class loaders are used to ensure +// safety of linking, and is maintained in the hash table +// "initiated_classes". A defining classloader is by definition also +// initiating, so we only store classes in this table, if they have more +// than one class loader associated. +// + + +// Size of local hash table. +#define HASH_LEN 1013 + +// Hash function for Utf8Consts. +#define HASH_UTF(Utf) (((Utf)->hash) % HASH_LEN) + +struct _Jv_LoaderInfo { + _Jv_LoaderInfo *next; + java::lang::Class *klass; + java::lang::ClassLoader *loader; +}; + +_Jv_LoaderInfo *initiated_classes[HASH_LEN]; +jclass loaded_classes[HASH_LEN]; + +jclass +_Jv_FindClassInCache (_Jv_Utf8Const *name, java::lang::ClassLoader *loader) +{ + _Jv_MonitorEnter (&ClassClass); + jint hash = HASH_UTF (name); + + // first, if LOADER is a defining loader, then it is also initiating + jclass klass; + for (klass = loaded_classes[hash]; klass; klass = klass->next) + { + if (loader == klass->loader && _Jv_equalUtf8Consts (name, klass->name)) + break; + } + + // otherwise, it may be that the class in question was defined + // by some other loader, but that the loading was initiated by + // the loader in question. + if (!klass) + { + _Jv_LoaderInfo *info; + for (info = initiated_classes[hash]; info; info = info->next) + { + if (loader == info->loader + && _Jv_equalUtf8Consts (name, info->klass->name)) + { + klass = info->klass; + break; + } + } + } + + _Jv_MonitorExit (&ClassClass); + + return klass; +} + +void +_Jv_UnregisterClass (jclass the_class) +{ + _Jv_MonitorEnter (&ClassClass); + jint hash = HASH_UTF(the_class->name); + + jclass *klass = &(loaded_classes[hash]); + for ( ; *klass; klass = &((*klass)->next)) + { + if (*klass == the_class) + { + *klass = (*klass)->next; + break; + } + } + + _Jv_LoaderInfo **info = &(initiated_classes[hash]); + for ( ; *info; info = &((*info)->next)) + { + while ((*info)->klass == the_class) + { + *info = (*info)->next; + } + } + + _Jv_MonitorExit (&ClassClass); +} + +void +_Jv_RegisterInitiatingLoader (jclass klass, java::lang::ClassLoader *loader) +{ + _Jv_LoaderInfo *info = new _Jv_LoaderInfo; // non-gc alloc! + jint hash = HASH_UTF(klass->name); + + _Jv_MonitorEnter (&ClassClass); + info->loader = loader; + info->klass = klass; + info->next = initiated_classes[hash]; + initiated_classes[hash] = info; + _Jv_MonitorExit (&ClassClass); + +} + +// This function is called many times during startup, before main() is +// run. We do our runtime initialization here the very first time we +// are called. At that point in time we know for certain we are +// running single-threaded, so we don't need to lock when modifying +// `init'. CLASSES is NULL-terminated. +void +_Jv_RegisterClasses (jclass *classes) +{ + static bool init = false; + + if (! init) + { + init = true; + _Jv_InitThreads (); + _Jv_InitGC (); + _Jv_InitializeSyncMutex (); + } + + JvSynchronize sync (&ClassClass); + for (; *classes; ++classes) + { + jclass klass = *classes; + jint hash = HASH_UTF (klass->name); + klass->next = loaded_classes[hash]; + loaded_classes[hash] = klass; + + // registering a compiled class causes + // it to be immediately "prepared". + if (klass->state == JV_STATE_NOTING) + klass->state = JV_STATE_COMPILED; + } +} + +void +_Jv_RegisterClass (jclass klass) +{ + jclass classes[2]; + classes[0] = klass; + classes[1] = NULL; + _Jv_RegisterClasses (classes); +} + +#if 0 +// NOTE: this one is out of date with the new loader stuff... +jclass +_Jv_FindClassInCache (jstring name, java::lang::ClassLoader *loader) +{ + JvSynchronize sync (&ClassClass); + jint hash = name->hashCode(); + jclass klass = loaded_classes[(_Jv_ushort) hash % HASH_LEN]; + for ( ; klass; klass = klass->next) + { + if (loader == klass->loader + && _Jv_equal (klass->name, name, hash)) + break; + } + _Jv_MonitorExit (&ClassClass); + return klass; +} +#endif + +jclass _Jv_FindClass (_Jv_Utf8Const *name, + java::lang::ClassLoader *loader) +{ + jclass klass = _Jv_FindClassInCache (name, loader); + +#ifdef INTERPRETER + if (! klass) + { + jstring sname = _Jv_NewStringUTF (name->data); + + if (loader) + { + // Load using a user-defined loader, jvmspec 5.3.2 + klass = loader->loadClass(sname, false); + + // if "loader" delegateted the loadClass operation + // to another loader, register explicitly + // that he is also an initiating loader of the + // given class. + + if (klass && (klass->getClassLoader () != loader)) + _Jv_RegisterInitiatingLoader (klass, 0); + } + else + { + if (redirect == NULL) + { + _Jv_InitClass (&ClassLoaderClass); + java::lang::ClassLoader::getSystemClassLoader (); + } + + // Load using the bootstrap loader jmspec 5.3.1 + klass = redirect -> loadClassInternal (sname, false, true); + + // register that we're an initiating loader + if (klass) + { + _Jv_RegisterInitiatingLoader (klass, 0); + } + } + } + else + { + // we need classes to be in the hash while + // we're loading, so that they can refer to themselves. + _Jv_WaitForState (klass, JV_STATE_LOADED); + } +#endif + + return klass; +} + +#if 0 +// NOTE: this one is out of date with the new class loader stuff... +jclass +_Jv_FindClass (jstring name, java::lang::ClassLoader *loader) +{ + jclass klass = _Jv_FindClassInCache (name, loader); + if (! klass) + { + if (loader) + { + klass = loader->loadClass(name); + } + else + { + // jmspec 5.3.1.2 + + // delegate to the system loader + klass = java::lang::ClassLoader::system.loadClass (sname); + + // register that we're an initiating loader + if (klass) + _Jv_RegisterInitiatingLoader (klass, 0); + } + } + else + { + _Jv_WaitForState (klass, JV_STATE_LOADED); + } + + return klass; +} +#endif + +jclass +_Jv_NewClass (_Jv_Utf8Const *name, jclass superclass, + java::lang::ClassLoader *loader) +{ + jclass ret = (jclass) JvAllocObject (&ClassClass); + + ret->next = NULL; + ret->name = name; + ret->accflags = 0; + ret->superclass = superclass; + ret->constants.size = 0; + ret->constants.tags = NULL; + ret->constants.data = NULL; + ret->methods = NULL; + ret->method_count = 0; + ret->vtable_method_count = 0; + ret->fields = NULL; + ret->size_in_bytes = 0; + ret->field_count = 0; + ret->static_field_count = 0; + ret->vtable = NULL; + ret->interfaces = NULL; + ret->loader = loader; + ret->interface_count = 0; + ret->state = 0; + ret->thread = NULL; + + _Jv_RegisterClass (ret); + + return ret; +} + +jclass +_Jv_FindArrayClass (jclass element, java::lang::ClassLoader *loader) +{ + _Jv_Utf8Const *array_name; + int len; + if (element->isPrimitive()) + { + // For primitive types the array is cached in the class. + jclass ret = (jclass) element->methods; + if (ret) + return ret; + len = 3; + } + else + len = element->name->length + 5; + + { + char signature[len]; + int index = 0; + signature[index++] = '['; + // Compute name of array class to see if we've already cached it. + if (element->isPrimitive()) + { + signature[index++] = (char) element->method_count; + } + else + { + size_t length = element->name->length; + const char *const name = element->name->data; + if (name[0] != '[') + signature[index++] = 'L'; + memcpy (&signature[index], name, length); + index += length; + if (name[0] != '[') + signature[index++] = ';'; + } + array_name = _Jv_makeUtf8Const (signature, index); + } + + jclass array_class = _Jv_FindClassInCache (array_name, element->loader); + + if (! array_class) + { + // Create new array class. + array_class = _Jv_NewClass (array_name, &ObjectClass, element->loader); + + // Note that `vtable_method_count' doesn't include the initial + // NULL slot. + int dm_count = ObjectClass.vtable_method_count + 1; + + // Create a new vtable by copying Object's vtable (except the + // class pointer, of course). Note that we allocate this as + // unscanned memory -- the vtables are handled specially by the + // GC. + int size = (sizeof (_Jv_VTable) + + ((dm_count - 1) * sizeof (void *))); + _Jv_VTable *vtable = (_Jv_VTable *) _Jv_AllocBytes (size); + vtable->clas = array_class; + memcpy (vtable->method, ObjectClass.vtable->method, + dm_count * sizeof (void *)); + array_class->vtable = vtable; + array_class->vtable_method_count = ObjectClass.vtable_method_count; + + // Stash the pointer to the element type. + array_class->methods = (_Jv_Method *) element; + + // Register our interfaces. + // FIXME: for JDK 1.2 we need Serializable. + static jclass interfaces[] = { &CloneableClass }; + array_class->interfaces = interfaces; + array_class->interface_count = 1; + + // as per vmspec 5.3.3.2 + array_class->accflags = element->accflags; + + // FIXME: initialize other Class instance variables, + // e.g. `fields'. + + // say this class is initialized and ready to go! + array_class->state = JV_STATE_DONE; + + // vmspec, section 5.3.3 describes this + if (element->loader != loader) + _Jv_RegisterInitiatingLoader (array_class, loader); + } + + // For primitive types, point back at this array. + if (element->isPrimitive()) + element->methods = (_Jv_Method *) array_class; + + return array_class; +} + + diff --git a/libjava/java/lang/natFirstThread.cc b/libjava/java/lang/natFirstThread.cc index d47446b..319e487 100644 --- a/libjava/java/lang/natFirstThread.cc +++ b/libjava/java/lang/natFirstThread.cc @@ -27,7 +27,7 @@ details. */ typedef void main_func (jobject); void -java::lang::FirstThread::run (void) +java::lang::FirstThread::run0 (void) { Utf8Const* main_signature = _Jv_makeUtf8Const ("([Ljava.lang.String;)V", 22); Utf8Const* main_name = _Jv_makeUtf8Const ("main", 4); @@ -41,6 +41,12 @@ java::lang::FirstThread::run (void) DIE ("class must be public"); #endif + if (klass == NULL) + { + klass = java::lang::Class::forName (klass_name); + if (klass != NULL) _Jv_InitClass (klass); + } + _Jv_Method *meth = _Jv_GetMethodLocal (klass, main_name, main_signature); // Some checks from Java Spec section 12.1.4. diff --git a/libjava/java/lang/reflect/natArray.cc b/libjava/java/lang/reflect/natArray.cc index 3da8b5c..2c951db 100644 --- a/libjava/java/lang/reflect/natArray.cc +++ b/libjava/java/lang/reflect/natArray.cc @@ -45,10 +45,11 @@ java::lang::reflect::Array::newInstance (jclass componentType, jintArray dimensi if (ndims == 1) return newInstance (componentType, dims[0]); jclass arrayType = componentType; - for (int i = 0; i < ndims; i++) - arrayType = _Jv_FindArrayClass (arrayType); - return _Jv_NewMultiArray (arrayType, ndims, dims); + for (int i = 0; i < ndims; i++) // FIXME 2nd arg should + // be "current" loader + arrayType = _Jv_FindArrayClass (arrayType, 0); + return _Jv_NewMultiArray (arrayType, ndims, dims); } jint diff --git a/libjava/java/lang/reflect/natMethod.cc b/libjava/java/lang/reflect/natMethod.cc index 720bbc3..a62d1ff 100644 --- a/libjava/java/lang/reflect/natMethod.cc +++ b/libjava/java/lang/reflect/natMethod.cc @@ -378,8 +378,10 @@ java::lang::reflect::Method::getType () while (*ptr != ';' && ptr[1] != '\0'); break; } + + // FIXME: 2'nd argument should be "current loader" while (--num_arrays >= 0) - type = _Jv_FindArrayClass (type); + type = _Jv_FindArrayClass (type, 0); *argPtr++ = type; } parameter_types = args; diff --git a/libjava/java/net/natPlainSocketImpl.cc b/libjava/java/net/natPlainSocketImpl.cc index d42b821..e652ba7 100644 --- a/libjava/java/net/natPlainSocketImpl.cc +++ b/libjava/java/net/natPlainSocketImpl.cc @@ -354,7 +354,7 @@ java::net::PlainSocketImpl::getOption (jint optID) if (l_val.l_onoff) return new java::lang::Integer (l_val.l_linger); else - return new java::lang::Boolean (false); + return new java::lang::Boolean ((__java_boolean)false); #else JvThrow (new java::lang::InternalError ( JvNewStringUTF ("SO_LINGER not supported"))); diff --git a/libjava/libgcj.spec.in b/libjava/libgcj.spec.in index a46acef..e9ee02d 100644 --- a/libjava/libgcj.spec.in +++ b/libjava/libgcj.spec.in @@ -4,7 +4,7 @@ # to link with libgcj. # %rename lib liborig -*lib: -lgcj -lm @GCSPEC@ @THREADSPEC@ @ZLIBSPEC@ @SYSTEMSPEC@ %(liborig) +*lib: -lgcj -lm @INTERPSPEC@ @GCSPEC@ @THREADSPEC@ @ZLIBSPEC@ @SYSTEMSPEC@ %(liborig) %rename cc1 cc1orig *cc1: @DIVIDESPEC@ %(cc1orig) diff --git a/libjava/prims.cc b/libjava/prims.cc index c26c299..90fd96d 100644 --- a/libjava/prims.cc +++ b/libjava/prims.cc @@ -180,6 +180,24 @@ _Jv_makeUtf8Const (char* s, int len) return (m); } +_Jv_Utf8Const * +_Jv_makeUtf8Const (jstring string) +{ + jint hash = string->hashCode (); + jint len = _Jv_GetStringUTFLength (string); + + Utf8Const* m = (Utf8Const*) + _Jv_AllocBytesChecked (sizeof(Utf8Const) + len + 1); + + m->hash = hash; + m->length = len; + + _Jv_GetStringUTFRegion (string, 0, string->length (), m->data); + m->data[len] = 0; + + return m; +} + #ifdef DEBUG @@ -298,7 +316,10 @@ _Jv_NewObjectArray (jsize count, jclass elementClass, jobject init) JvThrow (no_memory); size_t size = count * sizeof (jobject) + sizeof (__JArray); - jclass clas = _Jv_FindArrayClass (elementClass); + + // FIXME: second argument should be "current loader" // + jclass clas = _Jv_FindArrayClass (elementClass, 0); + jobjectArray obj = (jobjectArray) _Jv_AllocArray (size); if (! obj) JvThrow (no_memory); @@ -338,7 +359,7 @@ _Jv_NewPrimArray (jclass eltype, jint count) arr->length = count; // Note that we assume we are given zeroed memory by the allocator. - jclass klass = _Jv_FindArrayClass (eltype); + jclass klass = _Jv_FindArrayClass (eltype, 0); // Set the vtbl last to avoid problems if the GC happens during the // window in this function between the allocation and this // assignment. @@ -531,9 +552,11 @@ _Jv_FindClassFromSignature (char *sig, java::lang::ClassLoader *loader) ; _Jv_Utf8Const *name = _Jv_makeUtf8Const (&sig[1], i - 1); return _Jv_FindClass (name, loader); + } case '[': - return _Jv_FindArrayClass (_Jv_FindClassFromSignature (&sig[1], loader)); + return _Jv_FindArrayClass (_Jv_FindClassFromSignature (&sig[1], loader), + loader); } JvFail ("couldn't understand class signature"); return NULL; // Placate compiler. @@ -588,9 +611,20 @@ JvRunMain (jclass klass, int argc, const char **argv) LTDL_SET_PRELOADED_SYMBOLS (); #endif - arg_vec = JvConvertArgv (argc - 1, argv + 1); - main_group = new java::lang::ThreadGroup (23); - main_thread = new java::lang::FirstThread (main_group, klass, arg_vec); + if (klass == NULL) + { + arg_vec = JvConvertArgv (argc - 2, argv + 2); + main_group = new java::lang::ThreadGroup (23); + main_thread = new java::lang::FirstThread (main_group, + JvNewStringLatin1 (argv[1]), + arg_vec); + } + else + { + arg_vec = JvConvertArgv (argc - 1, argv + 1); + main_group = new java::lang::ThreadGroup (23); + main_thread = new java::lang::FirstThread (main_group, klass, arg_vec); + } main_thread->start(); _Jv_ThreadWait (); @@ -598,6 +632,7 @@ JvRunMain (jclass klass, int argc, const char **argv) java::lang::Runtime::getRuntime ()->exit (0); } + void * @@ -630,7 +665,7 @@ _Jv_divI (jint dividend, jint divisor) if (divisor == 0) _Jv_Throw (arithexception); - if (dividend == 0x80000000L && divisor == -1) + if (dividend == (jint) 0x80000000L && divisor == -1) return dividend; return dividend / divisor; @@ -642,7 +677,7 @@ _Jv_remI (jint dividend, jint divisor) if (divisor == 0) _Jv_Throw (arithexception); - if (dividend == 0x80000000L && divisor == -1) + if (dividend == (jint) 0x80000000L && divisor == -1) return 0; return dividend % divisor; @@ -654,7 +689,7 @@ _Jv_divJ (jlong dividend, jlong divisor) if (divisor == 0) _Jv_Throw (arithexception); - if (dividend == 0x8000000000000000LL && divisor == -1) + if (dividend == (jlong) 0x8000000000000000LL && divisor == -1) return dividend; return dividend / divisor; @@ -666,9 +701,15 @@ _Jv_remJ (jlong dividend, jlong divisor) if (divisor == 0) _Jv_Throw (arithexception); - if (dividend == 0x8000000000000000LL && divisor == -1) + if (dividend == (jlong) 0x8000000000000000LL && divisor == -1) return 0; return dividend % divisor; } + + + + + + diff --git a/libjava/resolve.cc b/libjava/resolve.cc new file mode 100644 index 0000000..a2d61c9 --- /dev/null +++ b/libjava/resolve.cc @@ -0,0 +1,1101 @@ +// resolve.cc - Code for linking and resolving classes and pool entries. + +/* Copyright (C) 1999 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. */ + +/* Author: Kresten Krab Thorup <krab@gnu.org> */ + +#include <java-interp.h> + +#ifdef INTERPRETER + +#include <cni.h> +#include <jvm.h> +#include <string.h> +#include <java-cpool.h> +#include <java/lang/Class.h> +#include <java/lang/String.h> +#include <java/lang/Thread.h> +#include <java/lang/InternalError.h> +#include <java/lang/VirtualMachineError.h> +#include <java/lang/NoSuchFieldError.h> +#include <java/lang/ClassFormatError.h> +#include <java/lang/IllegalAccessError.h> +#include <java/lang/AbstractMethodError.h> +#include <java/lang/ClassNotFoundException.h> +#include <java/lang/IncompatibleClassChangeError.h> + +static void throw_internal_error (char *msg) + __attribute__ ((__noreturn__)); +static void throw_class_format_error (jstring msg) + __attribute__ ((__noreturn__)); +static void throw_class_format_error (char *msg) + __attribute__ ((__noreturn__)); + +#define StringClass _CL_Q34java4lang6String +extern java::lang::Class StringClass; +#define ClassObject _CL_Q34java4lang6Object +extern java::lang::Class ClassObject; +#define ObjectClass _CL_Q34java4lang6Object +extern java::lang::Class ObjectClass; + + +static int get_alignment_from_class (jclass); + +static _Jv_ResolvedMethod* +_Jv_BuildResolvedMethod (_Jv_Method*, + jclass, + jboolean, + jint); + + +static const int PUBLIC = 0x001; +static const int PRIVATE = 0x002; +static const int PROTECTED = 0x004; +static const int STATIC = 0x008; +static const int FINAL = 0x010; +static const int SYNCHRONIZED = 0x020; +static const int VOLATILE = 0x040; +static const int TRANSIENT = 0x080; +static const int NATIVE = 0x100; +static const int INTERFACE = 0x200; +static const int ABSTRACT = 0x400; +static const int ALL_FLAGS = 0x7FF; + +// We need to know the name of a constructor. +static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6); + +static void throw_incompatible_class_change_error (jstring msg) +{ + JvThrow (new java::lang::IncompatibleClassChangeError (msg)); +} + +void* +_Jv_ResolvePoolEntry (jclass klass, int index) +{ + _Jv_Constants *pool = &klass->constants; + + if ((pool->tags[index] & JV_CONSTANT_ResolvedFlag) != 0) + return pool->data[index]; + + switch (pool->tags[index]) { + case JV_CONSTANT_Class: + { + _Jv_Utf8Const *name = (_Jv_Utf8Const *) pool->data[index]; + + jclass found; + if (name->data[0] == '[') + found = _Jv_FindClassFromSignature (&name->data[0], + klass->loader); + else + found = _Jv_FindClass (name, klass->loader); + + if (! found) + { + jstring str = _Jv_NewStringUTF (name->data); + JvThrow (new java::lang::ClassNotFoundException (str)); + } + + if ((found->accflags & PUBLIC) == PUBLIC + || (_Jv_ClassNameSamePackage (found->name, + klass->name))) + { + pool->data[index] = (void *) found; + pool->tags[index] |= JV_CONSTANT_ResolvedFlag; + } + else + { + JvThrow (new java::lang::IllegalAccessError (found->getName())); + } + } + break; + + case JV_CONSTANT_String: + { + jstring str; + str = _Jv_NewStringUtf8Const ((_Jv_Utf8Const *) pool->data[index]); + pool->data[index] = (void *) str; + pool->tags[index] |= JV_CONSTANT_ResolvedFlag; + } + break; + + case JV_CONSTANT_Fieldref: + { + _Jv_ushort class_index, name_and_type_index; + _Jv_loadIndexes ((const void**) &pool->data[index], + class_index, + name_and_type_index); + jclass owner = (jclass) _Jv_ResolvePoolEntry (klass, class_index); + + if (owner != klass) + _Jv_InitClass (owner); + + _Jv_ushort name_index, type_index; + _Jv_loadIndexes ((const void**) &pool->data[name_and_type_index], + name_index, + type_index); + + _Jv_Utf8Const *field_name = (_Jv_Utf8Const*) pool->data[name_index]; + _Jv_Utf8Const *field_type_name = + (_Jv_Utf8Const*) pool->data[type_index]; + + // FIXME: The implementation of this function + // (_Jv_FindClassFromSignature) will generate an instance of + // _Jv_Utf8Const for each call if the field type is a class name + // (Lxx.yy.Z;). This may be too expensive to do for each and + // every fieldref being resolved. For now, we fix the problem by + // only doing it when we have a loader different from the class + // declaring the field. + + jclass field_type = 0; + + if (owner->loader != klass->loader) + field_type = _Jv_FindClassFromSignature (field_type_name->data, + klass->loader); + + _Jv_Field* the_field = 0; + + for (jclass cls = owner; cls != 0; cls = cls->getSuperclass ()) + { + for (int i = 0; i < cls->field_count; i++) + { + _Jv_Field *field = &cls->fields[i]; + if (! _Jv_equalUtf8Consts (field->name, field_name)) + continue; + + // now, check field access. + + if ( (cls == klass) + || ((field->flags & PUBLIC) != 0) + || (((field->flags & PROTECTED) != 0) + && cls->isAssignableFrom (klass)) + || (((field->flags & PRIVATE) == 0) + && _Jv_ClassNameSamePackage (cls->name, + klass->name))) + { + /* resove the field using the class' own loader + if necessary */ + + if (!field->isResolved ()) + _Jv_ResolveField (field, cls->loader); + + if (field_type != 0 && field->type != field_type) + JvThrow + (new java::lang::LinkageError + (JvNewStringLatin1 + ("field type mismatch with different loaders"))); + + the_field = field; + goto end_of_field_search; + } + else + { + JvThrow (new java::lang::IllegalAccessError); + } + } + } + + end_of_field_search: + if (the_field == 0) + { + jstring msg = JvNewStringLatin1 ("field "); + msg = msg->concat (owner->getName ()); + msg = msg->concat (JvNewStringLatin1(".")); + msg = msg->concat (_Jv_NewStringUTF (field_name->data)); + msg = msg->concat (JvNewStringLatin1(" was not found.")); + throw_incompatible_class_change_error (msg); + } + + pool->data[index] = (void*)the_field; + pool->tags[index] |= JV_CONSTANT_ResolvedFlag; + } + break; + + case JV_CONSTANT_Methodref: + case JV_CONSTANT_InterfaceMethodref: + { + _Jv_ushort class_index, name_and_type_index; + _Jv_loadIndexes ((const void**) &pool->data[index], + class_index, + name_and_type_index); + jclass owner = (jclass) _Jv_ResolvePoolEntry (klass, class_index); + + if (owner != klass) + _Jv_InitClass (owner); + + _Jv_ushort name_index, type_index; + _Jv_loadIndexes ((const void**) &pool->data[name_and_type_index], + name_index, + type_index); + + _Jv_Utf8Const *method_name = (_Jv_Utf8Const*) pool->data[name_index]; + _Jv_Utf8Const *method_signature = + (_Jv_Utf8Const*) pool->data[type_index]; + + int vtable_index = -1; + _Jv_Method *the_method = 0; + jclass found_class = 0; + + // we make a loop here, because methods are allowed to be moved to + // a super class, and still be visible.. (binary compatibility). + + for (jclass cls = owner; cls != 0; cls = cls->getSuperclass ()) + { + for (int i = 0; i < cls->method_count; i++) + { + _Jv_Method *method = &cls->methods[i]; + if ( (!_Jv_equalUtf8Consts (method->name, + method_name)) + || (!_Jv_equalUtf8Consts (method->signature, + method_signature))) + continue; + + if (cls == klass + || ((method->accflags & PUBLIC) != 0) + || (((method->accflags & PROTECTED) != 0) + && cls->isAssignableFrom (klass)) + || (((method->accflags & PRIVATE) == 0) + && _Jv_ClassNameSamePackage (cls->name, + klass->name))) + { + // FIXME: if (cls->loader != klass->loader), then we + // must actually check that the types of arguments + // correspond. That is, for each argument type, and + // the return type, doing _Jv_FindClassFromSignature + // with either loader should produce the same result, + // i.e., exactly the same jclass object. JVMS 5.4.3.3 + + the_method = method; + found_class = cls; + + + if (pool->tags[index] == JV_CONSTANT_InterfaceMethodref) + vtable_index = -1; + else + vtable_index = _Jv_DetermineVTableIndex + (cls, method_name, method_signature); + + if (vtable_index == 0) + throw_incompatible_class_change_error + (JvNewStringLatin1 ("method not found")); + + goto end_of_method_search; + } + else + { + JvThrow (new java::lang::IllegalAccessError); + } + } + } + + end_of_method_search: + if (the_method == 0) + { + jstring msg = JvNewStringLatin1 ("method "); + msg = msg->concat (owner->getName ()); + msg = msg->concat (JvNewStringLatin1(".")); + msg = msg->concat (_Jv_NewStringUTF (method_name->data)); + msg = msg->concat (JvNewStringLatin1(" was not found.")); + JvThrow(new java::lang::NoSuchFieldError (msg)); + } + + pool->data[index] = (void*) + _Jv_BuildResolvedMethod(the_method, + found_class, + ((the_method->accflags & STATIC) != 0), + vtable_index); + pool->tags[index] |= JV_CONSTANT_ResolvedFlag; + } + break; + + } + + return pool->data[index]; +} + +void +_Jv_ResolveField (_Jv_Field *field, java::lang::ClassLoader *loader) +{ + if (! field->isResolved ()) + { + _Jv_Utf8Const *sig = (_Jv_Utf8Const*)field->type; + field->type = _Jv_FindClassFromSignature (sig->data, loader); + field->flags &= ~_Jv_FIELD_UNRESOLVED_FLAG; + } +} + +_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. + + Returns 0 if this class does not declare the given method. + Returns -1 if the given method does not appear in the vtable. + i.e., it is static, private, final or a constructor. + Otherwise, returns the vtable index. */ +int +_Jv_DetermineVTableIndex (jclass klass, + _Jv_Utf8Const *name, + _Jv_Utf8Const *signature) +{ + jclass super_class = klass->getSuperclass (); + + if (super_class != NULL) + { + int prev = _Jv_DetermineVTableIndex (super_class, + name, + signature); + if (prev != 0) + return prev; + } + + /* at this point, we know that the super-class does not declare + * the method. Otherwise, the above call would have found it, and + * determined the result of this function (-1 or some positive + * number). + */ + + _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature); + + /* now, if we do not declare this method, return zero */ + if (meth == NULL) + return 0; + + /* so now, we know not only that the super class does not declare the + * method, but we do! So, this is a first declaration of the method. */ + + /* now, the checks for things that are declared in this class, but do + * not go into the vtable. There are three cases. + * 1) the method is static, private or final + * 2) the class itself is final, or + * 3) it is the method <init> + */ + + if ( (meth->accflags & (STATIC|PRIVATE|FINAL)) != 0 + || (klass->accflags & FINAL) != 0 + || _Jv_equalUtf8Consts (name, init_name)) + return -1; + + /* reaching this point, we know for sure, that the method in question + * will be in the vtable. The question is where. */ + + /* the base offset, is where we will start assigning vtable + * indexes for this class. It is 1 for base classes + * (vtable->method[0] is unused), and for non-base classes it is the + * number of entries in the super class' vtable plus 1. */ + + int base_offset; + if (super_class == 0) + base_offset = 1; + else + base_offset = super_class->vtable_method_count+1; + + /* we will consider methods 0..this_method_index-1. And for each one, + * determine if it is new (i.e., if it appears in the super class), + * and if it should go in the vtable. If so, increment base_offset */ + + int this_method_index = meth - (&klass->methods[0]); + + for (int i = 0; i < this_method_index; i++) + { + _Jv_Method *m = &klass->methods[i]; + + /* fist some checks for things that surely do not go in the + * vtable */ + + if ((m->accflags & (STATIC|PRIVATE)) != 0) + continue; + if (_Jv_equalUtf8Consts (m->name, init_name)) + continue; + + /* Then, we need to know if this method appears in the + superclass. (This is where this function gets expensive) */ + _Jv_Method *sm = _Jv_LookupDeclaredMethod (super_class, + m->name, + m->signature); + + /* if it was somehow declared in the superclass, skip this */ + if (sm != NULL) + continue; + + /* but if it is final, and not declared in the super class, + * then we also skip it */ + if ((m->accflags & FINAL) != 0) + continue; + + /* finally, we can assign the index of this method */ + /* m->vtable_index = base_offset */ + base_offset += 1; + } + + return base_offset; +} + +/* this is installed in place of abstract methods */ +static void +_Jv_abstractMethodError () +{ + JvThrow (new java::lang::AbstractMethodError); +} + +void +_Jv_PrepareClass(jclass klass) +{ + /* + * The job of this function is to: 1) assign storage to fields, and 2) + * build the vtable. static fields are assigned real memory, instance + * fields are assigned offsets. + * + * NOTE: we have a contract with the garbage collector here. Static + * reference fields must not be resolved, until after they have storage + * assigned which is the check used by the collector to see if it + * should indirect the static field reference and mark the object + * pointed to. + * + * Most fields are resolved lazily (i.e. have their class-type + * assigned) when they are accessed the first time by calling as part + * of _Jv_ResolveField, which is allways called after _Jv_PrepareClass. + * Static fields with initializers are resolved as part of this + * function, as are fields with primitive types. + */ + + if (! _Jv_IsInterpretedClass (klass)) + return; + + if (klass->state >= JV_STATE_PREPARED) + return; + + // make sure super-class is linked. This involves taking a lock on + // the super class, so we use the Java method resolveClass, which will + // unlock it properly, should an exception happen. + + java::lang::ClassLoader::resolveClass (klass->superclass); + + _Jv_InterpClass *clz = (_Jv_InterpClass*)klass; + + /************ PART ONE: OBJECT LAYOUT ***************/ + + int instance_size; + int static_size; + + // java.lang.Object is never interpreted! + instance_size = clz->superclass->size (); + static_size = 0; + + for (int i = 0; i < clz->field_count; i++) + { + int field_size; + int field_align; + + _Jv_Field *field = &clz->fields[i]; + + if (! field->isRef ()) + { + // it's safe to resolve the field here, since it's + // a primitive class, which does not cause loading to happen. + _Jv_ResolveField (field, clz->loader); + + field_size = field->type->size (); + field_align = get_alignment_from_class (field->type); + } + else + { + field_size = sizeof (jobject); + field_align = __alignof__ (jobject); + } + +#ifndef COMPACT_FIELDS + field->bsize = field_size; +#endif + + if (field->flags & STATIC) + { + /* this computes an offset into a region we'll allocate + shortly, and then add this offset to the start address */ + + static_size = ROUND (static_size, field_align); + field->u.boffset = static_size; + static_size += field_size; + } + else + { + instance_size = ROUND (instance_size, field_align); + field->u.boffset = instance_size; + instance_size += field_size; + } + } + + // set the instance size for the class + clz->size_in_bytes = instance_size; + + // allocate static memory + if (static_size != 0) + { + char *static_data = (char*)_Jv_AllocBytesChecked (static_size); + + memset (static_data, 0, static_size); + + for (int i = 0; i < clz->field_count; i++) + { + _Jv_Field *field = &clz->fields[i]; + + if ((field->flags & STATIC) != 0) + { + field->u.addr = static_data + field->u.boffset; + + if (clz->field_initializers[i] != 0) + { + _Jv_ResolveField (field, clz->loader); + _Jv_InitField (0, clz, i); + } + } + } + + // now we don't need the field_initializers anymore, so let the + // collector get rid of it! + + clz->field_initializers = 0; + } + + /************ PART TWO: VTABLE LAYOUT ***************/ + + /* preparation: build the vtable stubs (even interfaces can) + have code -- for static constructors. */ + for (int i = 0; i < clz->method_count; i++) + { + _Jv_InterpMethod *imeth = clz->interpreted_methods[i]; + + if (imeth != 0) // it could be abstract or native + { + clz->methods[i].ncode = imeth->ncode (); + } + else + { + if ((clz->methods[i].accflags & NATIVE) != 0) + { + JvThrow + (new java::lang::VirtualMachineError + (JvNewStringLatin1 + ("the interpreter does not support native methods"))); + } + } + } + + if (clz->accflags & INTERFACE) + { + clz->state = JV_STATE_PREPARED; + clz->notifyAll (); + 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; + + jclass super_class = clz->getSuperclass (); + + if (super_class == 0) + throw_internal_error ("cannot handle interpreted base classes"); + + for (int i = 0; i < clz->method_count; i++) + { + _Jv_Method *this_meth = &clz->methods[i]; + + if ((this_meth->accflags & (STATIC|PRIVATE)) != 0 + || _Jv_equalUtf8Consts (this_meth->name, init_name)) + { + /* skip this, it doesn't go in the vtable */ + continue; + } + + _Jv_Method *orig_meth = _Jv_LookupDeclaredMethod (super_class, + this_meth->name, + this_meth->signature); + + if (orig_meth == 0) + { + // new methods that are final, also don't go in the vtable + if ((this_meth->accflags & FINAL) != 0) + continue; + + new_method_count += 1; + continue; + } + + if ((orig_meth->accflags & (STATIC|PRIVATE|FINAL)) != 0 + || ((orig_meth->accflags & ABSTRACT) == 0 + && (this_meth->accflags & ABSTRACT) != 0 + && (klass->accflags & ABSTRACT) == 0)) + { + clz->state = JV_STATE_ERROR; + clz->notifyAll (); + JvThrow (new java::lang::IncompatibleClassChangeError + (clz->getName ())); + } + + /* FIXME: At this point, if (loader != super_class->loader), we + * need to "impose class loader constraints" for the types + * involved in the signature of this method */ + } + + /* determine size */ + int vtable_count = (super_class->vtable_method_count) + new_method_count; + clz->vtable_method_count = vtable_count; + + /* allocate vtable structure */ + _Jv_VTable *vtable = (_Jv_VTable*) + _Jv_AllocBytesChecked (sizeof (_Jv_VTable) + + (sizeof (void*) * (vtable_count))); + vtable->clas = clz; + + /* copy super class' vtable entries (index 0 goes unused). */ + memcpy ((void*)&vtable->method[1], + (void*)&super_class->vtable->method[1], + sizeof (void*) * super_class->vtable_method_count); + + /* now, install our own vtable entries, reprise... */ + for (int i = 0; i < clz->method_count; i++) + { + _Jv_Method *this_meth = &clz->methods[i]; + + int index = _Jv_DetermineVTableIndex (clz, + this_meth->name, + this_meth->signature); + + if (index == 0) + throw_internal_error ("method now found in own class"); + + if (index != -1) + { + if (index > clz->vtable_method_count+1) + throw_internal_error ("vtable problem..."); + + if (clz->interpreted_methods[i] == 0) + vtable->method[index] = (void*)&_Jv_abstractMethodError; + else + vtable->method[index] = this_meth->ncode; + } + } + + /* finally, assign the vtable! */ + clz->vtable = vtable; + + /* wooha! we're done. */ + clz->state = JV_STATE_PREPARED; + clz->notifyAll (); +} + +/** Do static initialization for fields with a constant initializer */ +void +_Jv_InitField (jobject obj, jclass klass, int index) +{ + if (obj != 0 && klass == 0) + klass = obj->getClass (); + + if (!_Jv_IsInterpretedClass (klass)) + return; + + _Jv_InterpClass *clz = (_Jv_InterpClass*)klass; + + _Jv_Field * field = (&clz->fields[0]) + index; + + if (index > clz->field_count) + throw_internal_error ("field out of range"); + + int init = clz->field_initializers[index]; + if (init == 0) + return; + + _Jv_Constants *pool = &clz->constants; + int tag = pool->tags[init]; + + if (! field->isResolved ()) + throw_internal_error ("initializing unresolved field"); + + if (obj==0 && ((field->flags & STATIC) == 0)) + throw_internal_error ("initializing non-static field with no object"); + + void *addr = 0; + + if ((field->flags & STATIC) != 0) + addr = (void*) field->u.addr; + else + addr = (void*) (((char*)obj) + field->u.boffset); + + switch (tag) + { + case JV_CONSTANT_String: + { + _Jv_MonitorEnter (clz); + jstring str; + str = _Jv_NewStringUtf8Const ((_Jv_Utf8Const *) pool->data[init]); + pool->data[init] = (void *) str; + pool->tags[init] = JV_CONSTANT_ResolvedString; + _Jv_MonitorExit (clz); + } + /* fall through */ + + case JV_CONSTANT_ResolvedString: + if (! (field->type == &StringClass || field->type == &ObjectClass)) + throw_class_format_error ("string initialiser to non-string field"); + + *(jstring*)addr = *(jstring*) (pool->data + init); + break; + + case JV_CONSTANT_Integer: + { + int value = *(jint*)(pool->data + init); + + if (field->type == JvPrimClass (boolean)) + *(jboolean*)addr = (jboolean)value; + + else if (field->type == JvPrimClass (byte)) + *(jbyte*)addr = (jbyte)value; + + else if (field->type == JvPrimClass (char)) + *(jchar*)addr = (jchar)value; + + else if (field->type == JvPrimClass (short)) + *(jshort*)addr = (jshort)value; + + else if (field->type == JvPrimClass (int)) + *(jint*)addr = (jint)value; + + else + throw_class_format_error ("erroneous field initializer"); + } + break; + + case JV_CONSTANT_Long: + if (field->type != JvPrimClass (long)) + throw_class_format_error ("erroneous field initializer"); + + memcpy (addr, pool->data+init, 8); + break; + + case JV_CONSTANT_Float: + if (field->type != JvPrimClass (float)) + throw_class_format_error ("erroneous field initializer"); + + memcpy (addr, pool->data+init, 4); + break; + + case JV_CONSTANT_Double: + if (field->type != JvPrimClass (double)) + throw_class_format_error ("erroneous field initializer"); + + memcpy (addr, pool->data+init, 8); + break; + + default: + throw_class_format_error ("erroneous field initializer"); + } +} + +static int +get_alignment_from_class (jclass klass) +{ + if (klass == JvPrimClass (byte)) + return __alignof__ (jbyte); + else if (klass == JvPrimClass (short)) + return __alignof__ (jshort); + else if (klass == JvPrimClass (int)) + return __alignof__ (jint); + else if (klass == JvPrimClass (long)) + return __alignof__ (jlong); + else if (klass == JvPrimClass (boolean)) + return __alignof__ (jboolean); + else if (klass == JvPrimClass (char)) + return __alignof__ (jchar); + else if (klass == JvPrimClass (float)) + return __alignof__ (jfloat); + else if (klass == JvPrimClass (double)) + return __alignof__ (jdouble); + else + return __alignof__ (jobject); +} + + +inline static unsigned char* +skip_one_type (unsigned char* ptr) +{ + int ch = *ptr++; + + while (ch == '[') + { + ch = *ptr++; + } + + if (ch == 'L') + { + do { ch = *ptr++; } while (ch != ';'); + } + + return ptr; +} + +static ffi_type* +get_ffi_type_from_signature (unsigned char* ptr) +{ + switch (*ptr) + { + case 'L': + case '[': + return &ffi_type_pointer; + break; + + case 'Z': + case 'B': + return &ffi_type_sint8; + break; + + case 'C': + return &ffi_type_uint16; + break; + + case 'S': + return &ffi_type_sint16; + break; + + case 'I': + return &ffi_type_sint32; + break; + + case 'J': + return &ffi_type_sint64; + break; + + case 'F': + return &ffi_type_float; + break; + + case 'D': + return &ffi_type_double; + break; + + case 'V': + return &ffi_type_void; + break; + } + + throw_internal_error ("unknown type in signature"); +} + +/* this function yields the number of actual arguments, that is, if the + * function is non-static, then one is added to the number of elements + * found in the signature */ + +static int +count_arguments (_Jv_Utf8Const *signature, + jboolean staticp) +{ + unsigned char *ptr = (unsigned char*) signature->data; + int arg_count = staticp ? 0 : 1; + + /* first, count number of arguments */ + + // skip '(' + ptr++; + + // count args + while (*ptr != ')') + { + ptr = skip_one_type (ptr); + arg_count += 1; + } + + return arg_count; +} + +/* This beast will build a cif, given the signature. Memory for + * the cif itself and for the argument types must be allocated by the + * caller. + */ + +static int +init_cif (_Jv_Utf8Const* signature, + int arg_count, + jboolean staticp, + ffi_cif *cif, + ffi_type **arg_types) +{ + unsigned char *ptr = (unsigned char*) signature->data; + + int arg_index = 0; // arg number + int item_count = 0; // stack-item count + + // setup receiver + if (!staticp) + { + arg_types[arg_index++] = &ffi_type_pointer; + item_count += 1; + } + + // skip '(' + ptr++; + + // assign arg types + while (*ptr != ')') + { + arg_types[arg_index++] = get_ffi_type_from_signature (ptr); + + if (*ptr == 'J' || *ptr == 'D') + item_count += 2; + else + item_count += 1; + + ptr = skip_one_type (ptr); + } + + // skip ')' + ptr++; + ffi_type *rtype = get_ffi_type_from_signature (ptr); + + ptr = skip_one_type (ptr); + if (ptr != (unsigned char*)signature->data + signature->length) + throw_internal_error ("did not find end of signature"); + + if (ffi_prep_cif (cif, FFI_DEFAULT_ABI, + arg_count, rtype, arg_types) != FFI_OK) + throw_internal_error ("ffi_prep_cif failed"); + + return item_count; +} + + +/* we put this one here, and not in interpret.cc because it + * calls the utility routines count_arguments + * which are static to this module. The following struct defines the + * layout we use for the stubs, it's only used in the ncode method. */ + +typedef struct { + ffi_raw_closure closure; + ffi_cif cif; + ffi_type *arg_types[0]; +} ncode_closure; + +typedef void (*ffi_closure_fun) (ffi_cif*,void*,ffi_raw*,void*); + +void* _Jv_InterpMethod::ncode () +{ + if (self->ncode != 0) + return self->ncode; + + jboolean staticp = (self->accflags & 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; + + args_raw_size = ffi_raw_size (&closure->cif); + + if ((self->accflags & SYNCHRONIZED) != 0) + { + if (staticp) + fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class; + else + fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object; + } + else + { + fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal; + } + + ffi_prep_raw_closure (&closure->closure, + &closure->cif, + fun, + (void*)this); + + self->ncode = (void*)closure; + return self->ncode; +} + + +/* A _Jv_ResolvedMethod is what is put in the constant pool for a + * MethodRef or InterfacemethodRef. */ +static _Jv_ResolvedMethod* +_Jv_BuildResolvedMethod (_Jv_Method* method, + jclass klass, + jboolean staticp, + jint vtable_index) +{ + int arg_count = count_arguments (method->signature, staticp); + + _Jv_ResolvedMethod* result = (_Jv_ResolvedMethod*) + _Jv_AllocBytesChecked (sizeof (_Jv_ResolvedMethod) + + arg_count*sizeof (ffi_type*)); + + result->stack_item_count + = init_cif (method->signature, + arg_count, + staticp, + &result->cif, + &result->arg_types[0]); + + result->vtable_index = vtable_index; + result->method = method; + result->klass = klass; + + return result; +} + + +static void +throw_class_format_error (jstring msg) +{ + if (msg == 0) + JvThrow (new java::lang::ClassFormatError); + else + JvThrow (new java::lang::ClassFormatError (msg)); +} + +static void +throw_class_format_error (char *msg) +{ + throw_class_format_error (JvNewStringLatin1 (msg)); +} + +static void +throw_internal_error (char *msg) +{ + JvThrow + (new java::lang::InternalError (JvNewStringLatin1 (msg))); +} + + +#endif diff --git a/libjava/testsuite/Makefile.in b/libjava/testsuite/Makefile.in index 139abea..ac2e92d 100644 --- a/libjava/testsuite/Makefile.in +++ b/libjava/testsuite/Makefile.in @@ -71,6 +71,7 @@ COMPPATH = @COMPPATH@ CPP = @CPP@ CXX = @CXX@ CXXCPP = @CXXCPP@ +DIVIDESPEC = @DIVIDESPEC@ DLLTOOL = @DLLTOOL@ EH_COMMON_INCLUDE = @EH_COMMON_INCLUDE@ EXEEXT = @EXEEXT@ @@ -79,6 +80,7 @@ GCINCS = @GCINCS@ GCLIBS = @GCLIBS@ GCOBJS = @GCOBJS@ GCSPEC = @GCSPEC@ +INTERPSPEC = @INTERPSPEC@ LD = @LD@ LIBGCJ_CFLAGS = @LIBGCJ_CFLAGS@ LIBGCJ_CXXFLAGS = @LIBGCJ_CXXFLAGS@ |