OSDN Git Service

1999-08-09 Anthony Green <green@cygnus.com>
authorgreen <green@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 8 Aug 1999 14:06:23 +0000 (14:06 +0000)
committergreen <green@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 8 Aug 1999 14:06:23 +0000 (14:06 +0000)
        * 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@28597 138bc75d-0d04-0410-961f-82ee72b054a4

42 files changed:
libjava/ChangeLog
libjava/Makefile.am
libjava/Makefile.in
libjava/NEWS
libjava/THANKS
libjava/acconfig.h
libjava/boehm.cc
libjava/configure
libjava/configure.in
libjava/defineclass.cc [new file with mode: 0644]
libjava/gij.cc [new file with mode: 0644]
libjava/gnu/gcj/runtime/MethodInvocation.java [new file with mode: 0644]
libjava/gnu/gcj/util/path/CacheEntry.java [new file with mode: 0644]
libjava/gnu/gcj/util/path/DirectoryPathEntry.java [new file with mode: 0644]
libjava/gnu/gcj/util/path/PathEntry.java [new file with mode: 0644]
libjava/gnu/gcj/util/path/SearchPath.java [new file with mode: 0644]
libjava/gnu/gcj/util/path/URLPathEntry.java [new file with mode: 0644]
libjava/gnu/gcj/util/path/ZipPathEntry.java [new file with mode: 0644]
libjava/include/config.h.in
libjava/include/java-cpool.h [new file with mode: 0644]
libjava/include/java-field.h
libjava/include/java-insns.h [new file with mode: 0644]
libjava/include/java-interp.h [new file with mode: 0644]
libjava/include/javaprims.h
libjava/include/jvm.h
libjava/interpret.cc [new file with mode: 0644]
libjava/java/lang/Class.h
libjava/java/lang/Class.java
libjava/java/lang/ClassLoader.java
libjava/java/lang/FirstThread.java
libjava/java/lang/VMClassLoader.java [new file with mode: 0644]
libjava/java/lang/VirtualMachineError.java
libjava/java/lang/natClass.cc
libjava/java/lang/natClassLoader.cc [new file with mode: 0644]
libjava/java/lang/natFirstThread.cc
libjava/java/lang/reflect/natArray.cc
libjava/java/lang/reflect/natMethod.cc
libjava/java/net/natPlainSocketImpl.cc
libjava/libgcj.spec.in
libjava/prims.cc
libjava/resolve.cc [new file with mode: 0644]
libjava/testsuite/Makefile.in

index 1954795..24051fc 100644 (file)
@@ -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.
index c9cc9b9..83217c8 100644 (file)
@@ -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 \
index 94e4189..c03c322 100644 (file)
@@ -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' \
index 114e48a..e83836d 100644 (file)
@@ -1,3 +1,7 @@
+New in libgcj X.XX:
+
+* libgcj now includes a bytecode interpreter.
+
 New in libgcj 2.95:
 
 * First public release
index 93b24a8..5b9b9f8 100644 (file)
@@ -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
index daddbb1..1bd5025 100644 (file)
@@ -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
index f9e72ba..2e1b5f2 100644 (file)
@@ -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
     {
index a08e388..eac0e54 100755 (executable)
@@ -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
index 4549889..861530a 100644 (file)
@@ -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 (file)
index 0000000..09f8f47
--- /dev/null
@@ -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 ('!');
+}
+
+\f
+/** 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);
+}
+
+
+
+\f
+/* 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");
+       }
+    }
+
+}
+
+\f
+/** 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;
+}
+
+
+\f
+/** 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 (file)
index 0000000..f29e825
--- /dev/null
@@ -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 (file)
index 0000000..d1664ba
--- /dev/null
@@ -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 (file)
index 0000000..949200b
--- /dev/null
@@ -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 (file)
index 0000000..a9ca602
--- /dev/null
@@ -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 (file)
index 0000000..f83fc17
--- /dev/null
@@ -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 (file)
index 0000000..ffc2ca8
--- /dev/null
@@ -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 (file)
index 0000000..68f9200
--- /dev/null
@@ -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 (file)
index 0000000..ac02262
--- /dev/null
@@ -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;
+       }
+           
+    }
+}
+
index d9b9a0a..03f51ba 100644 (file)
 #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 (file)
index 0000000..f4d7ef9
--- /dev/null
@@ -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__ */
index b4529fc..d00d9ce 100644 (file)
@@ -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 (file)
index 0000000..8b19abd
--- /dev/null
@@ -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 (file)
index 0000000..70feec1
--- /dev/null
@@ -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__ */
index 98781ad..9d8c0a6 100644 (file)
@@ -162,6 +162,7 @@ extern "Java"
       class VerifyError;
       class VirtualMachineError;
       class Void;
+      class VMClassLoader;
       namespace reflect
       {
         class AccessibleObject;
index 75ca827..34da0ed 100644 (file)
@@ -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 (file)
index 0000000..1b9b800
--- /dev/null
@@ -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
index eb0a2f9..df55425 100644 (file)
@@ -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
index 4ffccea..bc826e9 100644 (file)
@@ -152,4 +152,7 @@ public final class Class implements Serializable
 
   // Initialize the class.
   private native void initializeClass ();
+
+  // finalization
+  protected native void finalize ();
 }
index 048cea7..f0b533f 100644 (file)
@@ -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;
+    }
+  }
 }
index ec0f1db..0dd5c9c 100644 (file)
@@ -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 (file)
index 0000000..026f6d8
--- /dev/null
@@ -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);
+  }
+}
index dcc907c..ee6d8e8 100644 (file)
@@ -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 ()
index 1768df5..367f14a 100644 (file)
@@ -39,6 +39,8 @@ details.  */
 #include <java/lang/System.h>
 #include <java/lang/SecurityManager.h>
 
+#include <java-cpool.h>
+
 \f
 
 #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];
-
 \f
 
 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 (file)
index 0000000..13452ec
--- /dev/null
@@ -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;
+}
+
+
index d47446b..319e487 100644 (file)
@@ -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.
index 3da8b5c..2c951db 100644 (file)
@@ -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
index 720bbc3..a62d1ff 100644 (file)
@@ -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;
index d42b821..e652ba7 100644 (file)
@@ -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")));      
index a46acef..e9ee02d 100644 (file)
@@ -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)
index c26c299..90fd96d 100644 (file)
@@ -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;
+}
+
 \f
 
 #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);
 }
 
+
 \f
 
 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 (file)
index 0000000..a2d61c9
--- /dev/null
@@ -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
index 139abea..ac2e92d 100644 (file)
@@ -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@