summaryrefslogtreecommitdiff
path: root/libjava/interpret.cc
diff options
context:
space:
mode:
authorgreen <green@138bc75d-0d04-0410-961f-82ee72b054a4>1999-08-08 14:06:23 +0000
committergreen <green@138bc75d-0d04-0410-961f-82ee72b054a4>1999-08-08 14:06:23 +0000
commit9a6624c49770e9b5e630a7c51eb0a13002d9df83 (patch)
tree277498eeeff558237a9cd88b0ea8b3788b31d645 /libjava/interpret.cc
parent47c5fab6136c7525f4abe013644d7d20570d1b94 (diff)
downloadgcc-9a6624c49770e9b5e630a7c51eb0a13002d9df83.tar.gz
1999-08-09 Anthony Green <green@cygnus.com>
* gij.cc: New file. * include/config.h.in: Rebuilt. * acconfig.h: Add INTERPRETER. * configure: Rebuilt. * Makefile.in: Rebuilt. * Makefile.am (libffi_files): Identify the libffi object files for inclusion in libgcj. (LIBFFIINCS): Define. * interpret.cc (gnu::gcj::runtime::MethodInvocation::continue1): Dummy definition for configurations without an interpreter. * java/net/natPlainSocketImpl.cc (getOption): Disamiguate call to java::lang::Boolean constructor. * include/java-interp.h: Always include java-cpool.h. * java/lang/natClassLoader.cc (getVMClassLoader0): Always return 0 when INTERPRETER not defined. * java/lang/Class.h (finalize): Define. * gnu/gcj/util/path/DirectoryPathEntry.java (getURL): Catch IOException from File.getCanonicalPath. (getStream): Likewise. * NEWS: More news. * THANKS: More thanks. 1999-08-09 Kresten Krab Thorup <krab@gnu.org> * resolve.cc (get_ffi_type_from_signature): Generate uint16 for jchar type. (_Jv_PrepareClass): Allow non-abstract classes to have abstract subclasses. (_Jv_ResolvePoolEntry): Revert subclass check for protected fields and methods. * interpret.cc (continue1/perform_invoke): Don't sign extend uint16 return val. (continue1/lshl,lshr): Push long, not int. (continue1/ulshr): Use UINT64, not long long. * defineclass.cc (handleFieldsEnd): Handle case when all fields are static. * java/lang/natClass.cc (forName): Add call to _Jv_InitClass. * java/lang/FirstThread.java (run): Add top-level exception handler. (run0): Renamed from run. 1999-08-08 Kresten Krab Thorup <krab@gnu.org> * configure.in (--with-interpreter): Added. * include/config.h.in (INTERPRETER): Added. * java/lang/ClassLoader.java: File replaced. * java/lang/VMClassLoader.java: New file. * java/lang/natClassLoader.cc: New file. * gnu/gcj/runtime/MethodInvocation.java: New file. * gnu/gcj/util/path/SearchPath.java: New file. * gnu/gcj/util/path/PathEntry.java: New file. * gnu/gcj/util/path/DirectoryPathEntry.java: New file. * gnu/gcj/util/path/ZipPathEntry.java: New file. * gnu/gcj/util/path/URLPathEntry.java: New file. * gnu/gcj/util/path/CacheEntry.java: New file. * include/java-interp.h: New file. * include/java-cpool.h: New file. * include/java-insns.h: New file. * defineclass.cc: New file. * interpret.cc: New file. * resolve.cc: New file. * java/lang/natClass.cc (loaded_classes, _Jv_RegisterClass, _Jv_RegisterClasses, _Jv_FindClassInCache, _Jv_FindClass, _Jv_NewClass, _Jv_FindArrayClass): Moved to natClassLoader.cc. (finalize): New. (STATE_NOTHING, STATE_RESOLVED, STATE_IN_PROGRESS, STATE_DONE, STATE_ERROR): Moved to java/lang/Class.h and renamed with JV_ prefix. (initializeClass): Use new JV_ prefixed names. Also, call ClassLoader::resolveClass instead of _Jv_ResolveClass. * java/lang/Class.h (JV_STATE_PRELOADING, JV_STATE_LOADING, JV_STATE_LOADED, JV_STATE_COMPILED, JV_STATE_PREPARED, JV_STATE_LINKED): New. (_Jv_WaitForState, _Jv_RegisterInitiatingLoader, _Jv_UnregisterClass, _Jv_InternClassStrings): New friends. (_Jv_IsInterpretedClass, _Jv_InitField, _Jv_LookupDeclaredMethod, _Jv_DetermineVTableIndex, _Jv_ResolvePoolEntry, _Jv_PrepareClass, _Jv_ClassReader, _Jv_InterpClass, _Jv_InterpMethod, _Jv_InterpMethodInvocation): New friends for interpreter. (finalize): New. (CONSTANT_Class, CONSTANT_String, etc.): Moved to include/java-cpool.h and renamed with JV_ prefix. * include/jvm.h (_Jv_makeUtf8Const, _Jv_makeUtf8TypeConst): New decls. (_Jv_UnregisterClass): New decl. * java/lang/natClassLoader.cc (_Jv_FindArrayClass): Added class loader argument. (_Jv_FindClass): Use class loader. * prims.cc (_Jv_makeUtf8Const): New function. (_Jv_NewObjectArray): Change use of _Jv_FindArrayClass. (_Jv_NewPrimArray): Ditto. (_Jv_FindClassFromSignature): Ditto. * java/lang/reflect/natArray.cc (newInstance): Ditto. * java/lang/reflect/natMethod.cc (getType): Ditto. * include/java-field.h (_Jv_Field::isRef): Make robust for non-resolved contexts. * boehm.cc (_Jv_MarkObj): Mark interpreter-related fields. Also, don't mark class->next field. * java/lang/VirtualMachineError.java: Added FIXME note. * configure.in (INTERPSPEC): New spec. * libgcj.spec.in: Added INTERPSPEC. * Makefile.am: Added gcjh friends for java/lang/VMClassLoader and gnu/gcj/runtime/MethodInvocation. (libgcj_la_SOURCES): Added resolve.cc defineclass.cc interpret.cc. (ordinary_java_source_files): Added above mentioned java classes. * configure: Rebuilt. * Makefile.in: Rebuilt. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@28597 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava/interpret.cc')
-rw-r--r--libjava/interpret.cc2449
1 files changed, 2449 insertions, 0 deletions
diff --git a/libjava/interpret.cc b/libjava/interpret.cc
new file mode 100644
index 00000000000..1b9b8006da7
--- /dev/null
+++ b/libjava/interpret.cc
@@ -0,0 +1,2449 @@
+// interpret.cc - Code for the interpreter
+
+/* Copyright (C) 1999 Cygnus Solutions
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+/* Author: Kresten Krab Thorup <krab@gnu.org> */
+
+/* define this to get instruction timings. */
+/* #define TIME_MAINLOOP */
+
+#include <config.h>
+
+#pragma implementation "java-interp.h"
+
+#include <cni.h>
+#include <jvm.h>
+#include <java-field.h>
+#include <java-cpool.h>
+#include <java-interp.h>
+#include <java/lang/fdlibm.h>
+#include <java/lang/System.h>
+#include <java/lang/String.h>
+#include <java/lang/Integer.h>
+#include <java/lang/StringBuffer.h>
+#include <java/io/PrintStream.h>
+#include <java/lang/Class.h>
+#include <java/lang/reflect/Modifier.h>
+#include <java/lang/ClassCastException.h>
+#include <java/lang/VirtualMachineError.h>
+#include <java/lang/InternalError.h>
+#include <java/lang/NullPointerException.h>
+#include <java/lang/ArithmeticException.h>
+#include <java/lang/IncompatibleClassChangeError.h>
+#include <java-insns.h>
+#include <java-signal.h>
+#ifdef TIME_MAINLOOP
+#include <sys/time.h>
+#include <stdio.h>
+#endif
+
+#ifndef INTERPRETER
+
+#include <gnu/gcj/runtime/MethodInvocation.h>
+
+/* this is the exception handler hack, for the interpreter */
+void
+gnu::gcj::runtime::MethodInvocation::continue1 (gnu::gcj::RawData *,
+ gnu::gcj::RawData *)
+{
+ JvFail ("no interpreter");
+}
+
+#else
+
+#define ClassError _CL_Q34java4lang5Error
+extern java::lang::Class ClassError;
+
+static const int PUBLIC = 0x001;
+static const int PRIVATE = 0x002;
+static const int PROTECTED = 0x004;
+static const int STATIC = 0x008;
+static const int FINAL = 0x010;
+static const int SYNCHRONIZED = 0x020;
+static const int VOLATILE = 0x040;
+static const int TRANSIENT = 0x080;
+static const int NATIVE = 0x100;
+static const int INTERFACE = 0x200;
+static const int ABSTRACT = 0x400;
+static const int ALL_FLAGS = 0x7FF;
+
+static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6);
+
+static void throw_internal_error (char *msg)
+ __attribute__ ((__noreturn__));
+static void throw_incompatible_class_change_error (jstring msg)
+ __attribute__ ((__noreturn__));
+#if !HANDLE_SEGV
+static void throw_null_pointer_exception ()
+ __attribute__ ((__noreturn__));
+#endif
+#if !HANDLE_FPE
+static void throw_arithmetic_exception ()
+ __attribute__ ((__noreturn__));
+#endif
+
+
+static inline void dupx (void **&sp, int n, int x)
+{
+ // first "slide" n+x elements n to the right
+ int top = n-1;
+ for (int i = 0; i < n+x; i++)
+ {
+ sp[(top-i)] = sp[(top-i)-n];
+ }
+
+ // next, copy the n top elements, n+x down
+ for (int i = 0; i < n; i++)
+ {
+ sp[top-(n+x)-i] = sp[top-i];
+ }
+
+ // the net effect
+ sp += n;
+};
+
+
+#define PUSHA(V) \
+ ({ jobject __v=(V); *(jobject*)sp++ = __v; })
+#define PUSHI(V) \
+ ({ jint __v=(V); *(jint*)sp++ = __v; })
+#define PUSHF(V) \
+ ({ jfloat __v=(V); *(jfloat*)sp++ = __v; })
+#define PUSHL(V) \
+ ({ jlong __v=(V); memcpy ((void*)sp, (void*)&__v, 8); sp+=2; })
+#define PUSHD(V) \
+ ({ jdouble __v=(V); memcpy ((void*)sp, (void*)&__v, 8); sp+=2; })
+
+#define POPA() (*(jobject*)--sp)
+#define POPI() (*(jint*)--sp)
+#define POPF() (*(jfloat*)--sp)
+#define POPL() ({ jlong __r; sp-=2; memcpy ((void*)&__r, sp, 8); __r; })
+#define POPD() ({ jdouble __r; sp-=2; memcpy ((void*)&__r, sp, 8); __r; })
+
+#define LOADA(I) *sp++ = locals[I]
+#define LOADI(I) *sp++ = locals[I]
+#define LOADF(I) *sp++ = locals[I]
+#define LOADL(I) ({ memcpy (sp, locals+(I), 8); sp+=2; })
+#define LOADD(I) ({ memcpy (sp, locals+(I), 8); sp+=2; })
+
+#define STOREA(I) locals[I] = *--sp
+#define STOREI(I) locals[I] = *--sp
+#define STOREF(I) locals[I] = *--sp
+#define STOREL(I) ({ sp-=2; memcpy (locals+(I), sp, 8); })
+#define STORED(I) ({ sp-=2; memcpy (locals+(I), sp, 8); })
+
+#define PEEKI(I) (*(jint*) (locals+(I)))
+#define PEEKA(I) (*(jobject*) (locals+(I)))
+
+#define POKEI(I,V) (*(jint*) (locals+(I)) = (V))
+
+
+#define BINOPI(OP) { \
+ jint value2 = POPI(); \
+ jint value1 = POPI(); \
+ PUSHI(value1 OP value2); \
+}
+
+#define BINOPF(OP) { \
+ jfloat value2 = POPF(); \
+ jfloat value1 = POPF(); \
+ PUSHF(value1 OP value2); \
+}
+
+#define BINOPL(OP) { \
+ jlong value2 = POPL(); \
+ jlong value1 = POPL(); \
+ PUSHL(value1 OP value2); \
+}
+
+#define BINOPD(OP) { \
+ jdouble value2 = POPD(); \
+ jdouble value1 = POPD(); \
+ PUSHD(value1 OP value2); \
+}
+
+static inline jint get1s(unsigned char* loc) {
+ return *(signed char*)loc;
+}
+
+static inline jint get1u(unsigned char* loc) {
+ return *loc;
+}
+
+static inline jint get2s(unsigned char* loc) {
+ return (((jint)*(signed char*)loc) << 8) | ((jint)*(loc+1));
+}
+
+static inline jint get2u(unsigned char* loc) {
+ return (((jint)(*loc)) << 8) | ((jint)*(loc+1));
+}
+
+static jint get4(unsigned char* loc) {
+ return (((jint)(loc[0])) << 24)
+ | (((jint)(loc[1])) << 16)
+ | (((jint)(loc[2])) << 8)
+ | (((jint)(loc[3])) << 0);
+}
+
+
+#if HANDLE_SEGV
+#define NULLCHECK(X)
+#else
+#define NULLCHECK(X) \
+ do { if ((X)==NULL) throw_null_pointer_exception (); } while (0)
+#endif
+
+#if HANDLE_FPE
+#define ZEROCHECK(X)
+#else
+#define ZEROCHECK(X) \
+ do { if ((X) == 0) throw_arithmetic_exception (); } while (0)
+#endif
+
+// this method starts the actual running of the method. It is inlined
+// in three different variants in the static methods run_normal,
+// run_sync_object and run_sync_class (see below). Those static methods
+// are installed directly in the stub for this method (by
+// _Jv_InterpMethod::ncode, in resolve.cc).
+
+inline jobject
+_Jv_InterpMethod::run (ffi_cif* cif,
+ void *retp,
+ void**args,
+ _Jv_InterpMethodInvocation *inv)
+{
+ inv->running = this;
+ inv->pc = bytecode ();
+ inv->sp = inv->stack_base ();
+ void **locals = inv->local_base ();
+
+ /* Go straight at it! the ffi raw format matches the internal
+ stack representation exactly!
+ */
+ memcpy ((void*) locals, (void*) args, args_raw_size);
+
+ next_segment:
+ /* this will call the method _Jv_InterpMethod::continue0, see below */
+ jobject ex =
+ gnu::gcj::runtime::MethodInvocation::continue0
+ ((gnu::gcj::RawData *)this, (gnu::gcj::RawData *)inv);
+
+ if (ex == 0) // no exception...
+ {
+ /* define sp locally, so the POP? macros will pick it up */
+ void **sp = (void**)inv->sp;
+ int rtype = cif->rtype->type;
+
+ if (rtype == FFI_TYPE_POINTER)
+ {
+ jobject r = POPA();
+ *(jobject*) retp = r;
+ return 0;
+ }
+ else if (rtype == FFI_TYPE_SINT32)
+ {
+ jint r = POPI();
+ *(jint*)retp = r;
+ return 0;
+ }
+ else if (rtype == FFI_TYPE_VOID)
+ {
+ return 0;
+ }
+ else switch (rtype)
+ {
+ case FFI_TYPE_FLOAT:
+ {
+ jfloat r = POPF();
+ *(jfloat*)retp = r;
+ return 0;
+ }
+
+ case FFI_TYPE_DOUBLE:
+ {
+ jdouble r = POPD();
+ *(jdouble*)retp = r;
+ return 0;
+ }
+
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_SINT16:
+ {
+ jint r = POPI();
+ *(jint*)retp = r;
+ return 0;
+ }
+
+ case FFI_TYPE_SINT64:
+ {
+ jlong r = POPL();
+ *(jlong*)retp = r;
+ return 0;
+ }
+
+ default:
+ throw_internal_error ("unknown return type");
+ }
+
+ }
+
+ /** handle an exception */
+ if ( find_exception (ex, inv) )
+ goto next_segment;
+
+ java::lang::System::out->println
+ (_Jv_NewStringUTF (self->name->data));
+
+ return ex;
+}
+
+bool _Jv_InterpMethod::find_exception (jobject ex,
+ _Jv_InterpMethodInvocation *inv)
+{
+ int logical_pc = inv->pc - bytecode ();
+ _Jv_InterpException *exc = exceptions ();
+ jclass exc_class = ex->getClass ();
+
+ for (int i = 0; i < exc_count; i++)
+ {
+ if (exc[i].start_pc <= logical_pc && logical_pc < exc[i].end_pc)
+ {
+ jclass handler;
+
+ if (exc[i].handler_type != 0)
+ handler = (jclass)
+ _Jv_ResolvePoolEntry (defining_class,
+ exc[i].handler_type);
+ else
+ handler = NULL;
+
+ if (handler==NULL || handler->isAssignableFrom (exc_class))
+ {
+ inv->pc = bytecode () + exc[i].handler_pc;
+ inv->sp = inv->stack_base (); // reset stack
+ *(jobject*) (inv->sp ++) = ex;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void _Jv_InterpMethod::run_normal (ffi_cif* cif,
+ void* ret,
+ void** args,
+ void* __this)
+{
+ _Jv_InterpMethod* _this = (_Jv_InterpMethod*)__this;
+
+ // we do the alloca of the method invocation here, to allow the method
+ // "run" ro be inlined. Otherwise gcc will ignore the inline directive.
+ int storage_size = _this->max_stack+_this->max_locals;
+ _Jv_InterpMethodInvocation* inv = (_Jv_InterpMethodInvocation*)
+ alloca (sizeof (_Jv_InterpMethodInvocation)
+ + storage_size * sizeof (void*));
+
+ jobject ex = _this->run (cif, ret, args, inv);
+ if (ex != 0) _Jv_Throw (ex);
+}
+
+void _Jv_InterpMethod::run_synch_object (ffi_cif* cif,
+ void* ret,
+ void** args,
+ void* __this)
+{
+ _Jv_InterpMethod* _this = (_Jv_InterpMethod*)__this;
+ jobject rcv = (jobject)args[0];
+
+ int storage_size = _this->max_stack+_this->max_locals;
+ _Jv_InterpMethodInvocation* inv = (_Jv_InterpMethodInvocation*)
+ alloca (sizeof (_Jv_InterpMethodInvocation)
+ + storage_size * sizeof (void*));
+
+ _Jv_MonitorEnter (rcv);
+ jobject ex = _this->run (cif, ret, args, inv);
+ _Jv_MonitorExit (rcv);
+
+ if (ex != 0) _Jv_Throw (ex);
+}
+
+void _Jv_InterpMethod::run_synch_class (ffi_cif* cif,
+ void* ret,
+ void** args,
+ void* __this)
+{
+ _Jv_InterpMethod* _this = (_Jv_InterpMethod*)__this;
+ jclass sync = _this->defining_class;
+
+ int storage_size = _this->max_stack+_this->max_locals;
+ _Jv_InterpMethodInvocation* inv = (_Jv_InterpMethodInvocation*)
+ alloca (sizeof (_Jv_InterpMethodInvocation)
+ + storage_size * sizeof (void*));
+
+ _Jv_MonitorEnter (sync);
+ jobject ex = _this->run (cif, ret, args, inv);
+ _Jv_MonitorExit (sync);
+
+ if (ex != 0) _Jv_Throw (ex);
+}
+
+/* this is the exception handler hack, for the interpreter */
+void
+gnu::gcj::runtime::MethodInvocation::continue1 (gnu::gcj::RawData *meth,
+ gnu::gcj::RawData *inv)
+{
+ _Jv_InterpMethod *meth0 = (_Jv_InterpMethod*)meth;
+ _Jv_InterpMethodInvocation *inv0 = (_Jv_InterpMethodInvocation*)inv;
+ meth0->continue1 (inv0);
+}
+
+/*
+ This proceeds execution, as designated in "inv". If an exception
+ happens, then it is simply thrown, and handled in Java. Thus, the pc
+ needs to be stored in the invocation at all times, so we can figure
+ out which handler (if any) to invoke.
+
+ One design issue, which I have not completely considered, is if it
+ should be possible to have interpreted classes linked in! Seldom used
+ (or non-critical) classes could reasonably be interpreted.
+*/
+
+
+#ifdef TIME_MAINLOOP
+static jlong insn_time [256] = { 0 };
+static jlong insn_count[256] = { 0 };
+
+static void
+dump_time ()
+{
+ double total_all = 0;
+ for (int i = 0; i < 256; i++)
+ {
+ total_all += insn_time[i];
+ }
+
+ for (int i = 0; i < 256; i++)
+ {
+ jlong total = insn_time[i];
+ jlong count = insn_count[i];
+
+ if (count == 0) continue;
+
+ jlong amount = total/count;
+
+ printf ("in 0x%02x: %7Li %7Li %7Li %2.1f%%\n", i,
+ (long long)count, (long long)total, (long long)amount,
+ (float) (100.0*(double)total/total_all)
+ );
+ }
+}
+#endif
+
+void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
+{
+ /* for some reason, which I do not understand, the compiler on x86
+ * allocates almost 4k stack space for this function! Even though
+ * there are many local variables, they are all nicely contained
+ * within a block scope, except for the few declared right below
+ * here. What's going on?? It could well be, that there in fact is
+ * on the order of 1000 local variables, including all those inlined
+ * and expanded from macros... Compiling with -O0, it allocates a
+ * "modest" 300 bytes of stack space. Among all those options of
+ * gcc, why isn't there a -fpack-stack, allowing reuse of stack
+ * locations? */
+
+ void** sp = inv->sp;
+ unsigned char *pc = inv->pc;
+ void** locals = inv->local_base ();
+ int opcode;
+
+ jclass defining_class = this->defining_class;
+ void **pool_data = defining_class->constants.data;
+
+ /* these two are used in the invokeXXX instructions */
+ void (*fun)(...);
+ _Jv_ResolvedMethod* rmeth;
+
+#ifdef TIME_MAINLOOP
+ struct timeval tv;
+ int last_opcode;
+ jlong last_time;
+ static jlong time_warp = 0;
+
+#define USEC(TV) \
+ ((jlong) (TV).tv_sec * 1000000LL + (jlong)(TV).tv_usec)
+
+
+ if (time_warp == 0)
+ {
+ struct timeval tv2;
+
+ gettimeofday (&tv, 0);
+ for (int i = 0; i < 100; i++)
+ gettimeofday (&tv2, 0);
+
+ jlong then = USEC(tv);
+ jlong now = USEC(tv2);
+ time_warp = (now - then) / 100;
+
+ if (time_warp == 0)
+ time_warp = 1;
+ }
+
+#define TIME_SUSPEND do { \
+ gettimeofday (&tv, 0); \
+ jlong now = USEC(tv); \
+ insn_time[last_opcode] += (now - last_time) - time_warp; \
+} while(0)
+
+#define TIME_RESUME do { \
+ gettimeofday (&tv, 0); \
+ last_time = USEC(tv); \
+} while(0)
+
+ last_opcode = 0;
+ gettimeofday (&tv, 0);
+ last_time = (jlong)tv.tv_sec * 1000000LL + (jlong)tv.tv_usec;
+
+#else
+
+#define TIME_SUSPEND
+#define TIME_RESUME
+
+#endif
+
+ next_insn:
+ inv->pc = pc;
+
+#ifdef TIME_MAINLOOP
+
+ gettimeofday (&tv, 0);
+ jlong now = USEC(tv);
+ insn_time[last_opcode] += (now - last_time) - time_warp;
+ last_time = now;
+ last_opcode = *pc;
+ insn_count[last_opcode] += 1;
+
+#endif
+ opcode = *pc++;
+
+ /* we special-case the single opcode aload_0 -- it makes
+ up 10% of the time spent in the main loop. */
+
+ switch (opcode)
+ {
+ case op_aload_0: // 0x2a
+ LOADA(0);
+ goto next_insn;
+
+ case op_iload: // 0x15
+ LOADI (get1u (pc++));
+ goto next_insn;
+
+ case op_getfield_4: // 0xd8
+ {
+ jobject obj = POPA();
+ NULLCHECK(obj);
+ jint field_offset = get2u (pc); pc += 2;
+ PUSHI (*(jint*) ((char*)obj + field_offset));
+ }
+ goto next_insn;
+
+ case op_iload_1: // 0x1b
+ LOADI (1);
+ goto next_insn;
+
+ case op_getfield_a: // 0xda
+ {
+ jobject obj = POPA();
+ NULLCHECK(obj);
+ jint field_offset = get2u (pc); pc += 2;
+ PUSHA(*(jobject*) ((char*)obj + field_offset));
+ }
+ goto next_insn;
+
+ case op_invokevirtual: // 0xb6
+ {
+ int index = get2u (pc); pc += 2;
+
+ /* _Jv_ResolvePoolEntry returns immediately if the value already
+ * is resolved. If we want to clutter up the code here to gain
+ * a little performance, then we can check the corresponding bit
+ * JV_CONSTANT_ResolvedFlag in the tag directly. For now, I
+ * don't think it is worth it. */
+
+ rmeth = (_Jv_ResolvedMethod*)
+ _Jv_ResolvePoolEntry (defining_class, index);
+
+ sp -= rmeth->stack_item_count;
+ NULLCHECK(sp[0]);
+
+ if (rmeth->vtable_index == -1)
+ {
+ // final methods do not appear in the vtable,
+ // if it does not appear in the superclass.
+ fun = (void (*) (...)) rmeth->method->ncode;
+ }
+ else
+ {
+ jobject rcv = (jobject)sp[0];
+ _Jv_VTable *table = *(_Jv_VTable**)rcv;
+ fun = (void (*) (...))table->method[rmeth->vtable_index];
+ }
+ }
+ goto perform_invoke;
+
+ perform_invoke:
+ {
+ /* here goes the magic again... */
+ ffi_cif *cif = &rmeth->cif;
+ void **raw = sp;
+
+ jdouble rvalue;
+
+ TIME_SUSPEND;
+ ffi_raw_call (cif, fun, (void*)&rvalue, (ffi_raw*) raw);
+ TIME_RESUME;
+
+ int rtype = cif->rtype->type;
+
+ /* the likelyhood of object, int, or void return is very high,
+ * so those are checked before the switch */
+ if (rtype == FFI_TYPE_POINTER)
+ {
+ PUSHA (*(jobject*)&rvalue);
+ }
+ else if (rtype == FFI_TYPE_SINT32)
+ {
+ PUSHI (*(jint*)&rvalue);
+ }
+ else if (rtype == FFI_TYPE_VOID)
+ {
+ /* skip */
+ }
+ else switch (rtype)
+ {
+ case FFI_TYPE_SINT8:
+ {
+ jbyte value = (*(jint*)&rvalue) & 0xff;
+ PUSHI (value);
+ }
+ break;
+
+ case FFI_TYPE_SINT16:
+ {
+ jshort value = (*(jint*)&rvalue) & 0xffff;
+ PUSHI (value);
+ }
+ break;
+
+ case FFI_TYPE_UINT16:
+ {
+ jint value = (*(jint*)&rvalue) & 0xffff;
+ PUSHI (value);
+ }
+ break;
+
+ case FFI_TYPE_FLOAT:
+ PUSHF (*(jfloat*)&rvalue);
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ PUSHD (rvalue);
+ break;
+
+ case FFI_TYPE_SINT64:
+ PUSHL (*(jlong*)&rvalue);
+ break;
+
+ default:
+ throw_internal_error ("unknown return type in invokeXXX");
+ }
+
+ }
+ goto next_insn;
+
+
+ case op_nop:
+ goto next_insn;
+
+ case op_aconst_null:
+ PUSHA (NULL);
+ goto next_insn;
+
+ case op_iconst_m1:
+ case op_iconst_0:
+ case op_iconst_1:
+ case op_iconst_2:
+ case op_iconst_3:
+ case op_iconst_4:
+ case op_iconst_5:
+ PUSHI (opcode-op_iconst_0);
+ goto next_insn;
+
+ case op_lconst_0:
+ case op_lconst_1:
+ PUSHL ((jlong) (opcode-op_lconst_0));
+ goto next_insn;
+
+ case op_fconst_0:
+ case op_fconst_1:
+ case op_fconst_2:
+ PUSHF ((jfloat) (opcode-op_fconst_0));
+ goto next_insn;
+
+ case op_dconst_0:
+ case op_dconst_1:
+ PUSHD ((jdouble) (opcode-op_dconst_0));
+ goto next_insn;
+
+ case op_bipush:
+ PUSHI (get1s(pc++));
+ goto next_insn;
+
+ case op_sipush:
+ PUSHI (get2s(pc)); pc += 2;
+ goto next_insn;
+
+ case op_ldc:
+ {
+ int index = get1u (pc++);
+ PUSHA((jobject) pool_data[index]);
+ }
+ goto next_insn;
+
+ case op_ldc_w:
+ {
+ int index = get2u (pc); pc += 2;
+ PUSHA((jobject) pool_data[index]);
+ }
+ goto next_insn;
+
+ case op_ldc2_w:
+ {
+ int index = get2u (pc); pc += 2;
+ memcpy (sp, &pool_data[index], 8);
+ sp += 2;
+ }
+ goto next_insn;
+
+ case op_lload:
+ LOADL (get1u (pc++));
+ goto next_insn;
+
+ case op_fload:
+ LOADF (get1u (pc++));
+ goto next_insn;
+
+ case op_dload:
+ LOADD (get1u (pc++));
+ goto next_insn;
+
+ case op_aload:
+ LOADA (get1u (pc++));
+ goto next_insn;
+
+ case op_iload_0:
+ LOADI (0);
+ goto next_insn;
+
+ case op_iload_2:
+ LOADI (2);
+ goto next_insn;
+
+ case op_iload_3:
+ LOADI (3);
+ goto next_insn;
+
+ case op_lload_0:
+ case op_lload_1:
+ case op_lload_2:
+ case op_lload_3:
+ LOADL (opcode-op_lload_0);
+ goto next_insn;
+
+ case op_fload_0:
+ case op_fload_1:
+ case op_fload_2:
+ case op_fload_3:
+ LOADF (opcode-op_fload_0);
+ goto next_insn;
+
+ case op_dload_0:
+ case op_dload_1:
+ case op_dload_2:
+ case op_dload_3:
+ LOADD (opcode-op_dload_0);
+ goto next_insn;
+
+ case op_aload_1:
+ LOADA(1);
+ goto next_insn;
+
+ case op_aload_2:
+ LOADA(2);
+ goto next_insn;
+
+ case op_aload_3:
+ LOADA(3);
+ goto next_insn;
+
+ case op_iaload:
+ {
+ jint index = POPI();
+ jintArray arr = (jintArray) POPA();
+ NULLCHECK (arr);
+ if (index < 0 || index >= arr->length)
+ {
+ TIME_SUSPEND;
+ _Jv_ThrowBadArrayIndex (index);
+ }
+ PUSHI( elements(arr)[index] );
+ }
+ goto next_insn;
+
+ case op_laload:
+ {
+ jint index = POPI();
+ jlongArray arr = (jlongArray) POPA();
+ NULLCHECK (arr);
+ if (index < 0 || index >= arr->length)
+ {
+ TIME_SUSPEND;
+ _Jv_ThrowBadArrayIndex (index);
+ }
+ PUSHL( elements(arr)[index] );
+ }
+ goto next_insn;
+
+ case op_faload:
+ {
+ jint index = POPI();
+ jfloatArray arr = (jfloatArray) POPA();
+ NULLCHECK (arr);
+ if (index < 0 || index >= arr->length)
+ {
+ TIME_SUSPEND;
+ _Jv_ThrowBadArrayIndex (index);
+ }
+ PUSHF( elements(arr)[index] );
+ }
+ goto next_insn;
+
+ case op_daload:
+ {
+ jint index = POPI();
+ jdoubleArray arr = (jdoubleArray) POPA();
+ NULLCHECK (arr);
+ if (index < 0 || index >= arr->length)
+ {
+ TIME_SUSPEND;
+ _Jv_ThrowBadArrayIndex (index);
+ }
+ PUSHD( elements(arr)[index] );
+ }
+ goto next_insn;
+
+ case op_aaload:
+ {
+ jint index = POPI();
+ jobjectArray arr = (jobjectArray) POPA();
+ NULLCHECK (arr);
+ if (index < 0 || index >= arr->length)
+ {
+ TIME_SUSPEND;
+ _Jv_ThrowBadArrayIndex (index);
+ }
+ PUSHA( elements(arr)[index] );
+ }
+ goto next_insn;
+
+ case op_baload:
+ {
+ jint index = POPI();
+ jbyteArray arr = (jbyteArray) POPA();
+ NULLCHECK (arr);
+ if (index < 0 || index >= arr->length)
+ {
+ TIME_SUSPEND;
+ _Jv_ThrowBadArrayIndex (index);
+ }
+ PUSHI( elements(arr)[index] );
+ }
+ goto next_insn;
+
+ case op_caload:
+ {
+ jint index = POPI();
+ jcharArray arr = (jcharArray) POPA();
+ NULLCHECK (arr);
+ if (index < 0 || index >= arr->length)
+ {
+ TIME_SUSPEND;
+ _Jv_ThrowBadArrayIndex (index);
+ }
+ PUSHI( elements(arr)[index] );
+ }
+ goto next_insn;
+
+ case op_saload:
+ {
+ jint index = POPI();
+ jshortArray arr = (jshortArray) POPA();
+ NULLCHECK (arr);
+ if (index < 0 || index >= arr->length)
+ {
+ TIME_SUSPEND;
+ _Jv_ThrowBadArrayIndex (index);
+ }
+ PUSHI( elements(arr)[index] );
+ }
+ goto next_insn;
+
+ case op_istore:
+ STOREI (get1u (pc++));
+ goto next_insn;
+
+ case op_lstore:
+ STOREL (get1u (pc++));
+ goto next_insn;
+
+ case op_fstore:
+ STOREF (get1u (pc++));
+ goto next_insn;
+
+ case op_dstore:
+ STORED (get1u (pc++));
+ goto next_insn;
+
+ case op_astore:
+ STOREI (get1u (pc++));
+ goto next_insn;
+
+ case op_istore_0:
+ case op_istore_1:
+ case op_istore_2:
+ case op_istore_3:
+ STOREI (opcode-op_istore_0);
+ goto next_insn;
+
+ case op_lstore_0:
+ case op_lstore_1:
+ case op_lstore_2:
+ case op_lstore_3:
+ STOREL (opcode-op_lstore_0);
+ goto next_insn;
+
+ case op_fstore_0:
+ case op_fstore_1:
+ case op_fstore_2:
+ case op_fstore_3:
+ STOREF (opcode-op_fstore_0);
+ goto next_insn;
+
+ case op_dstore_0:
+ case op_dstore_1:
+ case op_dstore_2:
+ case op_dstore_3:
+ STORED (opcode-op_dstore_0);
+ goto next_insn;
+
+ case op_astore_0:
+ case op_astore_1:
+ case op_astore_2:
+ case op_astore_3:
+ STOREA (opcode-op_astore_0);
+ goto next_insn;
+
+ case op_iastore:
+ {
+ jint value = POPI();
+ jint index = POPI();
+ jintArray arr = (jintArray) POPA();
+ NULLCHECK (arr);
+ if (index < 0 || index >= arr->length)
+ {
+ TIME_SUSPEND;
+ _Jv_ThrowBadArrayIndex (index);
+ }
+ elements(arr)[index] = value;
+ }
+ goto next_insn;
+
+ case op_lastore:
+ {
+ jlong value = POPL();
+ jint index = POPI();
+ jlongArray arr = (jlongArray) POPA();
+ NULLCHECK (arr);
+ if (index < 0 || index >= arr->length)
+ {
+ TIME_SUSPEND;
+ _Jv_ThrowBadArrayIndex (index);
+ }
+ elements(arr)[index] = value;
+ }
+ goto next_insn;
+
+ case op_fastore:
+ {
+ jfloat value = POPF();
+ jint index = POPI();
+ jfloatArray arr = (jfloatArray) POPA();
+ NULLCHECK (arr);
+ if (index < 0 || index >= arr->length)
+ {
+ TIME_SUSPEND;
+ _Jv_ThrowBadArrayIndex (index);
+ }
+ elements(arr)[index] = value;
+ }
+ goto next_insn;
+
+ case op_dastore:
+ {
+ jdouble value = POPD();
+ jint index = POPI();
+ jdoubleArray arr = (jdoubleArray) POPA();
+ NULLCHECK (arr);
+ if (index < 0 || index >= arr->length)
+ {
+ TIME_SUSPEND;
+ _Jv_ThrowBadArrayIndex (index);
+ }
+ elements(arr)[index] = value;
+ }
+ goto next_insn;
+
+ case op_aastore:
+ {
+ jobject value = POPA();
+ jint index = POPI();
+ jobjectArray arr = (jobjectArray) POPA();
+ NULLCHECK (arr);
+ if (index < 0 || index >= arr->length)
+ {
+ TIME_SUSPEND;
+ _Jv_ThrowBadArrayIndex (index);
+ }
+ _Jv_CheckArrayStore (arr, value);
+ elements(arr)[index] = value;
+ }
+ goto next_insn;
+
+ case op_bastore:
+ {
+ jbyte value = (jbyte) POPI();
+ jint index = POPI();
+ jbyteArray arr = (jbyteArray) POPA();
+ NULLCHECK (arr);
+ if (index < 0 || index >= arr->length)
+ {
+ TIME_SUSPEND;
+ _Jv_ThrowBadArrayIndex (index);
+ }
+ elements(arr)[index] = value;
+ }
+ goto next_insn;
+
+ case op_castore:
+ {
+ jchar value = (jchar) POPI();
+ jint index = POPI();
+ jcharArray arr = (jcharArray) POPA();
+ NULLCHECK (arr);
+ if (index < 0 || index >= arr->length)
+ {
+ TIME_SUSPEND;
+ _Jv_ThrowBadArrayIndex (index);
+ }
+ elements(arr)[index] = value;
+ }
+ goto next_insn;
+
+ case op_sastore:
+ {
+ jshort value = (jshort) POPI();
+ jint index = POPI();
+ jshortArray arr = (jshortArray) POPA();
+ NULLCHECK (arr);
+ if (index < 0 || index >= arr->length)
+ {
+ TIME_SUSPEND;
+ _Jv_ThrowBadArrayIndex (index);
+ }
+ elements(arr)[index] = value;
+ }
+ goto next_insn;
+
+ case op_pop:
+ sp -= 1;
+ goto next_insn;
+
+ case op_pop2:
+ sp -= 2;
+ goto next_insn;
+
+ case op_dup:
+ sp[0] = sp[-1];
+ sp += 1;
+ goto next_insn;
+
+ case op_dup_x1:
+ dupx (sp, 1, 1);
+ goto next_insn;
+
+ case op_dup_x2:
+ dupx (sp, 1, 2);
+ goto next_insn;
+
+ case op_dup2:
+ sp[0] = sp[-2];
+ sp[1] = sp[-1];
+ sp += 2;
+ goto next_insn;
+
+ case op_dup2_x1:
+ dupx (sp, 2, 1);
+ goto next_insn;
+
+ case op_dup2_x2:
+ dupx (sp, 2, 2);
+ goto next_insn;
+
+ case op_swap:
+ {
+ jobject tmp1 = POPA();
+ jobject tmp2 = POPA();
+ PUSHA (tmp1);
+ PUSHA (tmp2);
+ }
+ goto next_insn;
+
+ case op_iadd:
+ BINOPI(+);
+ goto next_insn;
+
+ case op_ladd:
+ BINOPL(+);
+ goto next_insn;
+
+ case op_fadd:
+ BINOPF(+);
+ goto next_insn;
+
+ case op_dadd:
+ BINOPD(+);
+ goto next_insn;
+
+ case op_isub:
+ BINOPI(-);
+ goto next_insn;
+
+ case op_lsub:
+ BINOPL(-);
+ goto next_insn;
+
+ case op_fsub:
+ BINOPF(-);
+ goto next_insn;
+
+ case op_dsub:
+ BINOPD(-);
+ goto next_insn;
+
+ case op_imul:
+ BINOPI(*);
+ goto next_insn;
+
+ case op_lmul:
+ BINOPL(*);
+ goto next_insn;
+
+ case op_fmul:
+ BINOPF(*);
+ goto next_insn;
+
+ case op_dmul:
+ BINOPD(*);
+ goto next_insn;
+
+ case op_idiv:
+ {
+ jint value2 = POPI();
+ jint value1 = POPI();
+ ZEROCHECK (value2);
+ jint res = value1 / value2;
+ PUSHI (res);
+ }
+ goto next_insn;
+
+ case op_ldiv:
+ {
+ jlong value2 = POPL();
+ jlong value1 = POPL();
+ ZEROCHECK (value2);
+ jlong res = value1 / value2;
+ PUSHL (res);
+ }
+ goto next_insn;
+
+ case op_fdiv:
+ {
+ jfloat value2 = POPF();
+ jfloat value1 = POPF();
+ ZEROCHECK (value2);
+ jfloat res = value1 / value2;
+ PUSHF (res);
+ }
+ goto next_insn;
+
+ case op_ddiv:
+ {
+ jdouble value2 = POPD();
+ jdouble value1 = POPD();
+ ZEROCHECK (value2);
+ jdouble res = value1 / value2;
+ PUSHD (res);
+ }
+ goto next_insn;
+
+ case op_irem:
+ {
+ jint value2 = POPI();
+ jint value1 = POPI();
+ ZEROCHECK (value2);
+ jint res = value1 % value2;
+ PUSHI (res);
+ }
+ goto next_insn;
+
+ case op_lrem:
+ {
+ jlong value2 = POPL();
+ jlong value1 = POPL();
+ ZEROCHECK (value2);
+ jlong res = value1 % value2;
+ PUSHL (res);
+ }
+ goto next_insn;
+
+ case op_frem:
+ {
+ jfloat value2 = POPF();
+ jfloat value1 = POPF();
+ ZEROCHECK (value2);
+ jfloat res = __ieee754_fmod (value1, value2);
+ PUSHF (res);
+ }
+ goto next_insn;
+
+ case op_drem:
+ {
+ jdouble value2 = POPD();
+ jdouble value1 = POPD();
+ ZEROCHECK (value2);
+ jdouble res = __ieee754_fmod (value1, value2);
+ PUSHD (res);
+ }
+ goto next_insn;
+
+ case op_ineg:
+ *(jint*) (sp-1) *= -1;
+ goto next_insn;
+
+ case op_lneg:
+ *(jlong*) (sp-1) *= -1;
+ goto next_insn;
+
+ case op_fneg:
+ *(jfloat*) (sp-1) *= -1;
+ goto next_insn;
+
+ case op_dneg:
+ *(jdouble*) (sp-1) *= -1;
+ goto next_insn;
+
+ case op_ishl:
+ {
+ jint shift = (POPI() & 0x1f);
+ jint value = POPI();
+ PUSHI (value << shift);
+ }
+ goto next_insn;
+
+ case op_lshl:
+ {
+ jint shift = (POPI() & 0x3f);
+ jlong value = POPL();
+ PUSHL (value << shift);
+ }
+ goto next_insn;
+
+ case op_ishr:
+ {
+ jint shift = (POPI() & 0x1f);
+ jint value = POPI();
+ PUSHI (value >> shift);
+ }
+ goto next_insn;
+
+ case op_lshr:
+ {
+ jint shift = (POPI() & 0x3f);
+ jlong value = POPL();
+ PUSHL (value >> shift);
+ }
+ goto next_insn;
+
+ case op_iushr:
+ {
+ jint shift = (POPI() & 0x1f);
+ unsigned long value = POPI();
+ PUSHI ((jint) (value >> shift));
+ }
+ goto next_insn;
+
+ case op_lushr:
+ {
+ jint shift = (POPI() & 0x3f);
+ UINT64 value = (UINT64) POPL();
+ PUSHL ((value >> shift));
+ }
+ goto next_insn;
+
+ case op_iand:
+ BINOPI (&);
+ goto next_insn;
+
+ case op_land:
+ BINOPL (&);
+ goto next_insn;
+
+ case op_ior:
+ BINOPI (|);
+ goto next_insn;
+
+ case op_lor:
+ BINOPL (|);
+ goto next_insn;
+
+ case op_ixor:
+ BINOPI (^);
+ goto next_insn;
+
+ case op_lxor:
+ BINOPL (^);
+ goto next_insn;
+
+ case op_iinc:
+ {
+ jint index = get1u (pc++);
+ jint amount = get1s (pc++);
+ *(jint*) (locals + index) += amount;
+ }
+ goto next_insn;
+
+ case op_i2l:
+ PUSHL ((jlong)POPI ());
+ goto next_insn;
+
+ case op_i2f:
+ PUSHF ((jfloat)POPI ());
+ goto next_insn;
+
+ case op_i2d:
+ PUSHD ((jdouble)POPI ());
+ goto next_insn;
+
+ case op_l2i:
+ PUSHI ((jint)POPL ());
+ goto next_insn;
+
+ case op_l2f:
+ PUSHF ((jfloat)POPL ());
+ goto next_insn;
+
+ case op_l2d:
+ PUSHD ((jdouble)POPL ());
+ goto next_insn;
+
+ case op_f2i:
+ PUSHI ((jint)POPF ());
+ goto next_insn;
+
+ case op_f2l:
+ PUSHL ((jlong)POPF ());
+ goto next_insn;
+
+ case op_f2d:
+ PUSHD ((jdouble)POPF ());
+ goto next_insn;
+
+ case op_d2i:
+ PUSHI ((jint)POPD ());
+ goto next_insn;
+
+ case op_d2l:
+ PUSHL ((jlong)POPD ());
+ goto next_insn;
+
+ case op_d2f:
+ PUSHF ((jfloat)POPD ());
+ goto next_insn;
+
+ case op_i2b:
+ PUSHI ((jbyte)POPI ());
+ goto next_insn;
+
+ case op_i2c:
+ PUSHI ((jchar)POPI ());
+ goto next_insn;
+
+ case op_i2s:
+ PUSHI ((jshort)POPI ());
+ goto next_insn;
+
+ case op_lcmp:
+ {
+ jlong value2 = POPL ();
+ jlong value1 = POPL ();
+ if (value1 > value2)
+ { PUSHI (1); }
+ else if (value1 == value2)
+ { PUSHI (0); }
+ else
+ { PUSHI (-1); }
+ }
+ goto next_insn;
+
+ case op_fcmpl:
+ case op_fcmpg:
+ {
+ jfloat value2 = POPF ();
+ jfloat value1 = POPF ();
+ if (value1 > value2)
+ PUSHI (1);
+ else if (value1 == value2)
+ PUSHI (0);
+ else if (value1 < value2)
+ PUSHI (-1);
+ else if (opcode == op_fcmpg)
+ PUSHI (1);
+ else
+ PUSHI (-1);
+ }
+ goto next_insn;
+
+ case op_dcmpl:
+ case op_dcmpg:
+ {
+ jdouble value2 = POPD ();
+ jdouble value1 = POPD ();
+ if (value1 > value2)
+ PUSHI (1);
+ else if (value1 == value2)
+ PUSHI (0);
+ else if (value1 < value2)
+ PUSHI (-1);
+ else if (opcode == op_dcmpg)
+ PUSHI (1);
+ else
+ PUSHI (-1);
+ }
+ goto next_insn;
+
+ case op_ifeq:
+ {
+ jint offset = get2s (pc);
+ if (POPI() == 0)
+ pc = pc-1+offset;
+ else
+ pc = pc+2;
+ }
+ goto next_insn;
+
+ case op_ifne:
+ {
+ jint offset = get2s (pc);
+ if (POPI() != 0)
+ pc = pc-1+offset;
+ else
+ pc = pc+2;
+ }
+ goto next_insn;
+
+ case op_iflt:
+ {
+ jint offset = get2s (pc);
+ if (POPI() < 0)
+ pc = pc-1+offset;
+ else
+ pc = pc+2;
+ }
+ goto next_insn;
+
+ case op_ifge:
+ {
+ jint offset = get2s (pc);
+ if (POPI() >= 0)
+ pc = pc-1+offset;
+ else
+ pc = pc+2;
+ }
+ goto next_insn;
+
+ case op_ifgt:
+ {
+ jint offset = get2s (pc);
+ if (POPI() > 0)
+ pc = pc-1+offset;
+ else
+ pc = pc+2;
+ }
+ goto next_insn;
+
+ case op_ifle:
+ {
+ jint offset = get2s (pc);
+ if (POPI() <= 0)
+ pc = pc-1+offset;
+ else
+ pc = pc+2;
+ }
+ goto next_insn;
+
+ case op_if_icmpeq:
+ {
+ jint offset = get2s (pc);
+ jint value2 = POPI();
+ jint value1 = POPI();
+ if (value1 == value2)
+ pc = pc-1+offset;
+ else
+ pc = pc+2;
+ }
+ goto next_insn;
+
+ case op_if_icmpne:
+ {
+ jint offset = get2s (pc);
+ jint value2 = POPI();
+ jint value1 = POPI();
+ if (value1 != value2)
+ pc = pc-1+offset;
+ else
+ pc = pc+2;
+ }
+ goto next_insn;
+
+ case op_if_icmplt:
+ {
+ jint offset = get2s (pc);
+ jint value2 = POPI();
+ jint value1 = POPI();
+ if (value1 < value2)
+ pc = pc-1+offset;
+ else
+ pc = pc+2;
+ }
+ goto next_insn;
+
+ case op_if_icmpge:
+ {
+ jint offset = get2s (pc);
+ jint value2 = POPI();
+ jint value1 = POPI();
+ if (value1 >= value2)
+ pc = pc-1+offset;
+ else
+ pc = pc+2;
+ }
+ goto next_insn;
+
+ case op_if_icmpgt:
+ {
+ jint offset = get2s (pc);
+ jint value2 = POPI();
+ jint value1 = POPI();
+ if (value1 > value2)
+ pc = pc-1+offset;
+ else
+ pc = pc+2;
+ }
+ goto next_insn;
+
+ case op_if_icmple:
+ {
+ jint offset = get2s (pc);
+ jint value2 = POPI();
+ jint value1 = POPI();
+ if (value1 <= value2)
+ pc = pc-1+offset;
+ else
+ pc = pc+2;
+ }
+ goto next_insn;
+
+ case op_if_acmpeq:
+ {
+ jint offset = get2s (pc);
+ jobject value2 = POPA();
+ jobject value1 = POPA();
+ if (value1 == value2)
+ pc = pc-1+offset;
+ else
+ pc = pc+2;
+ }
+ goto next_insn;
+
+ case op_if_acmpne:
+ {
+ jint offset = get2s (pc);
+ jobject value2 = POPA();
+ jobject value1 = POPA();
+ if (value1 != value2)
+ pc = pc-1+offset;
+ else
+ pc = pc+2;
+ }
+ goto next_insn;
+
+ case op_goto:
+ {
+ jint offset = get2s (pc);
+ pc = pc-1+offset;
+ }
+ goto next_insn;
+
+ case op_jsr:
+ {
+ unsigned char *base_pc = pc-1;
+ jint offset = get2s (pc); pc += 2;
+ PUSHA ((jobject)pc);
+ pc = base_pc+offset;
+ }
+ goto next_insn;
+
+ case op_ret:
+ {
+ jint index = get1u (pc);
+ pc = (unsigned char*) PEEKA (index);
+ }
+ goto next_insn;
+
+ case op_tableswitch:
+ {
+ unsigned char *base_pc = pc-1;
+ int index = POPI();
+
+ unsigned char* base = bytecode ();
+ while ((pc-base) % 4 != 0)
+ pc++;
+
+ jint def = get4 (pc);
+ jint low = get4 (pc+4);
+ jint high = get4 (pc+8);
+
+ if (index < low || index > high)
+ pc = base_pc + def;
+ else
+ pc = base_pc + get4 (pc+4*(index-low+3));
+ }
+ goto next_insn;
+
+ case op_lookupswitch:
+ {
+ unsigned char *base_pc = pc-1;
+ int index = POPI();
+
+ unsigned char* base = bytecode ();
+ while ((pc-base) % 4 != 0)
+ pc++;
+
+ jint def = get4 (pc);
+ jint npairs = get4 (pc+4);
+
+ int max = npairs-1;
+ int min = 0;
+
+ // simple binary search...
+ while (min < max)
+ {
+ int half = (min+max)/2;
+ int match = get4 (pc+ 4*(2 + 2*half));
+
+ if (index == match)
+ min = max = half;
+
+ else if (index < match)
+ max = half-1;
+
+ else
+ min = half+1;
+ }
+
+ if (index == get4 (pc+ 4*(2 + 2*min)))
+ pc = base_pc + get4 (pc+ 4*(2 + 2*min + 1));
+ else
+ pc = base_pc + def;
+ }
+ goto next_insn;
+
+ /* on return, just save the sp and return to caller */
+ case op_ireturn:
+ case op_lreturn:
+ case op_freturn:
+ case op_dreturn:
+ case op_areturn:
+ case op_return:
+ inv->sp = sp;
+ TIME_SUSPEND;
+ return;
+
+ case op_getstatic:
+ {
+ unsigned char *base_pc = pc-1;
+ jint fieldref_index = get2u (pc); pc += 2;
+ _Jv_ResolvePoolEntry (defining_class, fieldref_index);
+ _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index];
+
+ if ((field->flags & STATIC) == 0)
+ throw_incompatible_class_change_error
+ (JvNewStringLatin1 ("field no longer static"));
+
+ jclass type = field->type;
+
+ if (type->isPrimitive ())
+ {
+ switch (type->size_in_bytes)
+ {
+ case 1:
+ *base_pc = op_getstatic_1;
+ break;
+
+ case 2:
+ if (type == JvPrimClass (char))
+ *base_pc = op_getstatic_2u;
+ else
+ *base_pc = op_getstatic_2s;
+ break;
+
+ case 4:
+ *base_pc = op_getstatic_4;
+ break;
+
+ case 8:
+ *base_pc = op_getstatic_8;
+ break;
+ }
+ }
+ else
+ {
+ *base_pc = op_getstatic_a;
+ }
+
+ pc = base_pc;
+ }
+ goto next_insn;
+
+ case op_getfield:
+ {
+ unsigned char *base_pc = pc-1;
+ jint fieldref_index = get2u (pc); pc += 2;
+ _Jv_ResolvePoolEntry (defining_class, fieldref_index);
+ _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index];
+
+ if ((field->flags & STATIC) != 0)
+ throw_incompatible_class_change_error
+ (JvNewStringLatin1 ("field is static"));
+
+ jclass type = field->type;
+
+ if (type->isPrimitive ())
+ {
+ switch (type->size_in_bytes)
+ {
+ case 1:
+ *base_pc = op_getfield_1;
+ break;
+
+ case 2:
+ if (type == JvPrimClass (char))
+ *base_pc = op_getfield_2u;
+ else
+ *base_pc = op_getfield_2s;
+ break;
+
+ case 4:
+ *base_pc = op_getfield_4;
+ break;
+
+ case 8:
+ *base_pc = op_getfield_8;
+ break;
+ }
+ }
+ else
+ {
+ *base_pc = op_getfield_a;
+ }
+
+ if (field->u.boffset > 0xffff)
+ JvThrow (new java::lang::VirtualMachineError);
+
+ base_pc[1] = (field->u.boffset>>8) & 0xff;
+ base_pc[2] = field->u.boffset & 0xff;
+
+ pc = base_pc;
+ }
+ goto next_insn;
+
+ case op_putstatic:
+ {
+ unsigned char* base_pc = pc-1;
+ jint fieldref_index = get2u (pc); pc += 2;
+ _Jv_ResolvePoolEntry (defining_class, fieldref_index);
+ _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index];
+
+ jclass type = field->type;
+
+ // ResolvePoolEntry cannot check this
+ if ((field->flags & STATIC) == 0)
+ throw_incompatible_class_change_error
+ (JvNewStringLatin1 ("field no longer static"));
+
+ /* if this is patented, then maybe we could install
+ a function in the constant pool, to do the right thing */
+
+ if (type->isPrimitive ())
+ {
+ switch (type->size_in_bytes)
+ {
+ case 1:
+ *base_pc = op_putstatic_1;
+ break;
+
+ case 2:
+ *base_pc = op_putstatic_2;
+ break;
+
+ case 4:
+ *base_pc = op_putstatic_4;
+ break;
+
+ case 8:
+ *base_pc = op_putstatic_8;
+ break;
+ }
+ }
+ else
+ {
+ *base_pc = op_putstatic_a;
+ }
+
+ // do the instruction again!
+ pc = base_pc;
+ }
+ goto next_insn;
+
+
+ case op_putfield:
+ {
+ unsigned char* base_pc = pc-1;
+ jint fieldref_index = get2u (pc); pc += 2;
+ _Jv_ResolvePoolEntry (defining_class, fieldref_index);
+ _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index];
+
+ jclass type = field->type;
+
+ if ((field->flags & STATIC) != 0)
+ throw_incompatible_class_change_error
+ (JvNewStringLatin1 ("field is static"));
+
+ if (type->isPrimitive ())
+ {
+ switch (type->size_in_bytes)
+ {
+ case 1:
+ *base_pc = op_putfield_1;
+ break;
+
+ case 2:
+ *base_pc = op_putfield_2;
+ break;
+
+ case 4:
+ *base_pc = op_putfield_4;
+ break;
+
+ case 8:
+ *base_pc = op_putfield_8;
+ break;
+ }
+ }
+ else
+ {
+ *base_pc = op_putfield_a;
+ }
+
+ if (field->u.boffset > 0xffff)
+ JvThrow (new java::lang::VirtualMachineError);
+
+ base_pc[1] = (field->u.boffset>>8) & 0xff;
+ base_pc[2] = field->u.boffset & 0xff;
+
+ // do the instruction again!
+ pc = base_pc;
+ }
+ goto next_insn;
+
+
+ case op_getfield_1:
+ {
+ jobject obj = POPA();
+ NULLCHECK(obj);
+ jint field_offset = get2u (pc); pc += 2;
+ PUSHI (*(jbyte*) ((char*)obj + field_offset));
+ }
+ goto next_insn;
+
+ case op_getfield_2s:
+ {
+ jobject obj = POPA();
+ NULLCHECK(obj);
+ jint field_offset = get2u (pc); pc += 2;
+ PUSHI (*(jshort*) ((char*)obj + field_offset));
+ }
+ goto next_insn;
+
+ case op_getfield_2u:
+ {
+ jobject obj = POPA();
+ NULLCHECK(obj);
+ jint field_offset = get2u (pc); pc += 2;
+ PUSHI (*(jchar*) ((char*)obj + field_offset));
+ }
+ goto next_insn;
+
+ case op_getfield_8:
+ {
+ jobject obj = POPA();
+ NULLCHECK(obj);
+ jint field_offset = get2u (pc); pc += 2;
+ PUSHL(*(jlong*) ((char*)obj + field_offset));
+ }
+ goto next_insn;
+
+ case op_getstatic_1:
+ {
+ jint fieldref_index = get2u (pc); pc += 2;
+ _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index];
+ PUSHI (*(jbyte*) (field->u.addr));
+ }
+ goto next_insn;
+
+ case op_getstatic_2s:
+ {
+ jint fieldref_index = get2u (pc); pc += 2;
+ _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index];
+ PUSHI(*(jshort*) (field->u.addr));
+ }
+ goto next_insn;
+
+ case op_getstatic_2u:
+ {
+ jint fieldref_index = get2u (pc); pc += 2;
+ _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index];
+ PUSHI(*(jchar*) (field->u.addr));
+ }
+ goto next_insn;
+
+ case op_getstatic_4:
+ {
+ jint fieldref_index = get2u (pc); pc += 2;
+ _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index];
+ PUSHI(*(jint*) (field->u.addr));
+ }
+ goto next_insn;
+
+ case op_getstatic_8:
+ {
+ jint fieldref_index = get2u (pc); pc += 2;
+ _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index];
+ PUSHL(*(jlong*) (field->u.addr));
+ }
+ goto next_insn;
+
+ case op_getstatic_a:
+ {
+ jint fieldref_index = get2u (pc); pc += 2;
+ _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index];
+ PUSHA(*(jobject*) (field->u.addr));
+ }
+ goto next_insn;
+
+ case op_putfield_1:
+ {
+ jint value = POPI();
+ jobject obj = POPA();
+ NULLCHECK(obj);
+ jint field_offset = get2u (pc); pc += 2;
+ *(jbyte*) ((char*)obj + field_offset) = value;
+ }
+ goto next_insn;
+
+ case op_putfield_2:
+ {
+ jint value = POPI();
+ jobject obj = POPA();
+ NULLCHECK(obj);
+ jint field_offset = get2u (pc); pc += 2;
+ *(jchar*) ((char*)obj + field_offset) = value;
+ }
+ goto next_insn;
+
+ case op_putfield_4:
+ {
+ jint value = POPI();
+ jobject obj = POPA();
+ NULLCHECK(obj);
+ jint field_offset = get2u (pc); pc += 2;
+ *(jint*) ((char*)obj + field_offset) = value;
+ }
+ goto next_insn;
+
+ case op_putfield_8:
+ {
+ jlong value = POPL();
+ jobject obj = POPA();
+ NULLCHECK(obj);
+ jint field_offset = get2u (pc); pc += 2;
+ *(jlong*) ((char*)obj + field_offset) = value;
+ }
+ goto next_insn;
+
+ case op_putfield_a:
+ {
+ jobject value = POPA();
+ jobject obj = POPA();
+ NULLCHECK(obj);
+ jint field_offset = get2u (pc); pc += 2;
+ *(jobject*) ((char*)obj + field_offset) = value;
+ }
+ goto next_insn;
+
+ case op_putstatic_1:
+ {
+ jint value = POPI();
+ jint fieldref_index = get2u (pc); pc += 2;
+ _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index];
+ *(jbyte*) (field->u.addr) = value;
+ }
+ goto next_insn;
+
+ case op_putstatic_2:
+ {
+ jint value = POPI();
+ jint fieldref_index = get2u (pc); pc += 2;
+ _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index];
+ *(jchar*) (field->u.addr) = value;
+ }
+ goto next_insn;
+
+ case op_putstatic_4:
+ {
+ jint value = POPI();
+ jint fieldref_index = get2u (pc); pc += 2;
+ _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index];
+ *(jint*) (field->u.addr) = value;
+ }
+ goto next_insn;
+
+ case op_putstatic_8:
+ {
+ jlong value = POPL();
+ jint fieldref_index = get2u (pc); pc += 2;
+ _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index];
+ *(jlong*) (field->u.addr) = value;
+ }
+ goto next_insn;
+
+ case op_putstatic_a:
+ {
+ jobject value = POPA();
+ jint fieldref_index = get2u (pc); pc += 2;
+ _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index];
+ *(jobject*) (field->u.addr) = value;
+ }
+ goto next_insn;
+
+ case op_invokespecial:
+ {
+ int index = get2u (pc); pc += 2;
+
+ rmeth = (_Jv_ResolvedMethod*)
+ _Jv_ResolvePoolEntry (defining_class, index);
+
+ sp -= rmeth->stack_item_count;
+
+ NULLCHECK(sp[0]);
+
+ fun = (void (*) (...))rmeth->method->ncode;
+ }
+ goto perform_invoke;
+
+ case op_invokestatic:
+ {
+ int index = get2u (pc); pc += 2;
+
+ rmeth = (_Jv_ResolvedMethod*)
+ _Jv_ResolvePoolEntry (defining_class, index);
+
+ sp -= rmeth->stack_item_count;
+
+ _Jv_InitClass (rmeth->klass);
+ fun = (void (*) (...))rmeth->method->ncode;
+ }
+ goto perform_invoke;
+
+ case op_invokeinterface:
+ {
+ int index = get2u (pc); pc += 2;
+
+ // invokeinterface has two unused bytes...
+ pc += 2;
+
+ rmeth = (_Jv_ResolvedMethod*)
+ _Jv_ResolvePoolEntry (defining_class, index);
+
+ sp -= rmeth->stack_item_count;
+ NULLCHECK(sp[0]);
+
+ jobject rcv = (jobject)sp[0];
+
+ fun = (void (*) (...))
+ _Jv_LookupInterfaceMethod (rcv->getClass (),
+ rmeth->method->name,
+ rmeth->method->signature);
+ }
+ goto perform_invoke;
+
+
+ case op_new:
+ {
+ int index = get2u (pc); pc += 2;
+ jclass klass = (jclass) _Jv_ResolvePoolEntry (defining_class,
+ index);
+ _Jv_InitClass (klass);
+ jobject res = _Jv_AllocObject (klass, klass->size_in_bytes);
+ PUSHA (res);
+ }
+ goto next_insn;
+
+ case op_newarray:
+ {
+ int atype = get1u (pc++);
+ int size = POPI();
+ jobject result = _Jv_NewArray (atype, size);
+ PUSHA (result);
+ }
+ goto next_insn;
+
+ case op_anewarray:
+ {
+ int index = get2u (pc); pc += 2;
+ jclass klass = (jclass) _Jv_ResolvePoolEntry (defining_class, index);
+ int size = POPI();
+ _Jv_InitClass (klass);
+ jobject result = _Jv_NewObjectArray (size, klass, 0);
+ PUSHA (result);
+ }
+ goto next_insn;
+
+ case op_arraylength:
+ {
+ __JArray *arr = (__JArray*)POPA();
+ PUSHI (arr->length);
+ }
+ goto next_insn;
+
+ case op_athrow:
+ {
+ jobject value = POPA();
+ TIME_SUSPEND;
+ JvThrow (value);
+ }
+ goto next_insn;
+
+ case op_checkcast:
+ {
+ jobject value = POPA();
+ jint index = get2u (pc); pc += 2;
+ jclass to = (jclass)_Jv_ResolvePoolEntry (defining_class,
+ index);
+
+ if (value != NULL && ! to->isInstance (value))
+ {
+ TIME_SUSPEND;
+ JvThrow (new java::lang::ClassCastException
+ (to->getName()));
+ }
+
+ PUSHA (value);
+ }
+ goto next_insn;
+
+ case op_instanceof:
+ {
+ jobject value = POPA();
+ jint index = get2u (pc); pc += 2;
+ jclass to = (jclass)_Jv_ResolvePoolEntry (defining_class,
+ index);
+ PUSHI (to->isInstance (value));
+ }
+ goto next_insn;
+
+ case op_monitorenter:
+ {
+ jobject value = POPA();
+ NULLCHECK(value);
+ _Jv_MonitorEnter (value);
+ }
+ goto next_insn;
+
+ case op_monitorexit:
+ {
+ jobject value = POPA();
+ NULLCHECK(value);
+ _Jv_MonitorExit (value);
+ }
+ goto next_insn;
+
+ case op_ifnull:
+ {
+ unsigned char* base_pc = pc-1;
+ jint offset = get2s (pc); pc += 2;
+ jobject val = POPA();
+ if (val == NULL)
+ pc = base_pc+offset;
+ }
+ goto next_insn;
+
+ case op_ifnonnull:
+ {
+ unsigned char* base_pc = pc-1;
+ jint offset = get2s (pc); pc += 2;
+ jobject val = POPA();
+ if (val != NULL)
+ pc = base_pc+offset;
+ }
+ goto next_insn;
+
+ case op_wide:
+ {
+ jint the_mod_op = get1u (pc++);
+ jint wide = get2u (pc); pc += 2;
+
+ switch (the_mod_op)
+ {
+ case op_istore:
+ STOREI (wide);
+ goto next_insn;
+
+ case op_fstore:
+ STOREF (wide);
+ goto next_insn;
+
+ case op_astore:
+ STOREA (wide);
+ goto next_insn;
+
+ case op_lload:
+ LOADL (wide);
+ goto next_insn;
+
+ case op_dload:
+ LOADD (wide);
+ goto next_insn;
+
+ case op_iload:
+ LOADI (wide);
+ goto next_insn;
+
+ case op_aload:
+ LOADA (wide);
+ goto next_insn;
+
+ case op_lstore:
+ STOREL (wide);
+ goto next_insn;
+
+ case op_dstore:
+ STORED (wide);
+ goto next_insn;
+
+ case op_ret:
+ pc = (unsigned char*) PEEKA (wide);
+ goto next_insn;
+
+ case op_iinc:
+ {
+ jint amount = get2s (pc); pc += 2;
+ jint value = PEEKI (wide);
+ POKEI (wide, value+amount);
+ }
+ goto next_insn;
+
+ default:
+ throw_internal_error ("illegal bytecode modified by wide");
+ }
+
+ }
+
+ case op_multianewarray:
+ {
+ int kind_index = get2u (pc); pc += 2;
+ int dim = get1u (pc); pc += 1;
+
+ jclass type = (jclass) _Jv_ResolvePoolEntry (defining_class,
+ kind_index);
+ _Jv_InitClass (type);
+ jint *sizes = (jint*) alloca (sizeof (jint)*dim);
+
+ for (int i = dim - 1; i >= 0; i--)
+ {
+ sizes[i] = POPI ();
+ }
+
+ jobject res = _Jv_NewMultiArray (type,dim, sizes);
+
+ PUSHA (res);
+ }
+ goto next_insn;
+
+ case op_goto_w:
+ {
+ unsigned char* base_pc = pc-1;
+ int offset = get4 (pc); pc += 4;
+ pc = base_pc+offset;
+ }
+ goto next_insn;
+
+ case op_jsr_w:
+ {
+ unsigned char* base_pc = pc-1;
+ int offset = get4 (pc); pc += 4;
+ PUSHA((jobject)pc);
+ pc = base_pc+offset;
+ }
+ goto next_insn;
+
+ default:
+ throw_internal_error ("opcode not implemented");
+
+ }
+ goto next_insn;
+}
+
+
+static void
+throw_internal_error (char *msg)
+{
+ JvThrow (new java::lang::InternalError (JvNewStringLatin1 (msg)));
+}
+
+static void
+throw_incompatible_class_change_error (jstring msg)
+{
+ JvThrow (new java::lang::IncompatibleClassChangeError (msg));
+}
+
+#if !HANDLE_SEGV
+static java::lang::NullPointerException *null_pointer_exc;
+static void
+throw_null_pointer_exception ()
+{
+ if (null_pointer_exc == NULL)
+ null_pointer_exc = new java::lang::NullPointerException;
+
+ JvThrow (null_pointer_exc);
+}
+#endif
+
+#if !HANDLE_FPE
+static java::lang::ArithmeticException *arithmetic_exc;
+static void
+throw_arithmetic_exception ()
+{
+ if (arithmetic_exc == NULL)
+ arithmetic_exc = new java::lang::ArithmeticException
+ (JvNewStringLatin1 ("/ by zero"));
+
+ JvThrow (arithmetic_exc);
+}
+#endif
+
+void
+jvdump(jobject o)
+{
+ _Jv_InterpMethod::dump_object(o);
+}
+
+/* FIXME: This is not finished! */
+void
+_Jv_InterpMethod::dump_object(jobject o)
+{
+ java::io::PrintStream *out = java::lang::System::out;
+
+ if (o == NULL)
+ {
+ out->println (JvNewStringLatin1 ("<null>"));
+ return;
+ }
+
+ jclass klass = o->getClass ();
+
+ out->print (klass->getName ());
+ out->print (JvNewStringLatin1 ("@0x"));
+ out->print (java::lang::Integer::toHexString ((jint)o));
+ out->print (JvNewStringLatin1 ("{"));
+#if 0
+ while (klass && klass != &ObjectClass)
+ {
+ _Jv_Field *fields = klass->fields;
+ int max = klass->field_count;
+
+ for (int i = 0; i < max; ++i)
+ {
+ out->print (_Jv_NewStringUTF (field->name->data));
+ out->print (JvNewStringLatin1 ("="));
+
+ if (JvFieldIsRef (field))
+ {
+ if (field->flags & STATIC)
+ out->print (JvGetSt)
+ }
+ field = field->getNextInstanceField ();
+
+ if (i+1 < max && klass->getSuperclass () != null)
+ out->print (JvNewStringLatin1 ("; "));
+ }
+
+ klass = klass->getSuperclass();
+ }
+#endif
+ out->print (JvNewStringLatin1 ("}\n"));
+
+}
+
+#endif // INTERPRETER