gcc/libjava/interpret.cc
Anthony Green 58eb6e7cef [multiple changes]
1999-08-09  Anthony Green  <green@cygnus.com>

        * gij.cc: New file.

        * include/config.h.in: Rebuilt.
        * acconfig.h: Add INTERPRETER.

        * configure: Rebuilt.

        * Makefile.in: Rebuilt.
        * Makefile.am (libffi_files): Identify the libffi object files for
        inclusion in libgcj.
        (LIBFFIINCS): Define.

        * interpret.cc (gnu::gcj::runtime::MethodInvocation::continue1):
        Dummy definition for configurations without an interpreter.

        * java/net/natPlainSocketImpl.cc (getOption): Disamiguate call to
        java::lang::Boolean constructor.

        * include/java-interp.h: Always include java-cpool.h.

        * java/lang/natClassLoader.cc (getVMClassLoader0): Always return 0
        when INTERPRETER not defined.

        * java/lang/Class.h (finalize): Define.

        * gnu/gcj/util/path/DirectoryPathEntry.java (getURL): Catch
        IOException from File.getCanonicalPath.
        (getStream): Likewise.

        * NEWS: More news.
        * THANKS: More thanks.

1999-08-09  Kresten Krab Thorup  <krab@gnu.org>

        * resolve.cc (get_ffi_type_from_signature): Generate uint16 for
        jchar type.
        (_Jv_PrepareClass): Allow non-abstract classes to
        have abstract subclasses.
        (_Jv_ResolvePoolEntry): Revert subclass check for protected
        fields and methods.
        * interpret.cc (continue1/perform_invoke): Don't sign extend
        uint16 return val.
        (continue1/lshl,lshr): Push long, not int.
        (continue1/ulshr): Use UINT64, not long long.
        * defineclass.cc (handleFieldsEnd): Handle case when all fields
        are static.
        * java/lang/natClass.cc (forName): Add call to _Jv_InitClass.
        * java/lang/FirstThread.java (run): Add top-level exception
        handler.
        (run0): Renamed from run.

1999-08-08  Kresten Krab Thorup  <krab@gnu.org>

        * configure.in (--with-interpreter): Added.
        * include/config.h.in (INTERPRETER): Added.

        * java/lang/ClassLoader.java: File replaced.
        * java/lang/VMClassLoader.java: New file.
        * java/lang/natClassLoader.cc: New file.
        * gnu/gcj/runtime/MethodInvocation.java: New file.
        * gnu/gcj/util/path/SearchPath.java: New file.
        * gnu/gcj/util/path/PathEntry.java: New file.
        * gnu/gcj/util/path/DirectoryPathEntry.java: New file.
        * gnu/gcj/util/path/ZipPathEntry.java: New file.
        * gnu/gcj/util/path/URLPathEntry.java: New file.
        * gnu/gcj/util/path/CacheEntry.java: New file.
        * include/java-interp.h: New file.
        * include/java-cpool.h: New file.
        * include/java-insns.h: New file.
        * defineclass.cc: New file.
        * interpret.cc: New file.
        * resolve.cc: New file.

        * java/lang/natClass.cc (loaded_classes, _Jv_RegisterClass,
        _Jv_RegisterClasses, _Jv_FindClassInCache, _Jv_FindClass,
        _Jv_NewClass, _Jv_FindArrayClass): Moved to natClassLoader.cc.
        (finalize): New.
        (STATE_NOTHING, STATE_RESOLVED, STATE_IN_PROGRESS, STATE_DONE,
        STATE_ERROR): Moved to java/lang/Class.h and renamed with JV_
        prefix.
        (initializeClass): Use new JV_ prefixed names.  Also, call
        ClassLoader::resolveClass instead of _Jv_ResolveClass.

        * java/lang/Class.h (JV_STATE_PRELOADING, JV_STATE_LOADING,
        JV_STATE_LOADED, JV_STATE_COMPILED, JV_STATE_PREPARED,
        JV_STATE_LINKED): New.
        (_Jv_WaitForState, _Jv_RegisterInitiatingLoader,
        _Jv_UnregisterClass, _Jv_InternClassStrings): New friends.
        (_Jv_IsInterpretedClass, _Jv_InitField, _Jv_LookupDeclaredMethod,
        _Jv_DetermineVTableIndex, _Jv_ResolvePoolEntry, _Jv_PrepareClass,
        _Jv_ClassReader, _Jv_InterpClass, _Jv_InterpMethod,
        _Jv_InterpMethodInvocation): New friends for interpreter.
        (finalize): New.
        (CONSTANT_Class, CONSTANT_String, etc.): Moved to
        include/java-cpool.h and renamed with JV_ prefix.

        * include/jvm.h (_Jv_makeUtf8Const, _Jv_makeUtf8TypeConst): New
        decls.
        (_Jv_UnregisterClass): New decl.

        * java/lang/natClassLoader.cc (_Jv_FindArrayClass): Added
        class loader argument.
        (_Jv_FindClass): Use class loader.

        * prims.cc (_Jv_makeUtf8Const): New function.
        (_Jv_NewObjectArray): Change use of _Jv_FindArrayClass.
        (_Jv_NewPrimArray): Ditto.
        (_Jv_FindClassFromSignature): Ditto.
        * java/lang/reflect/natArray.cc (newInstance): Ditto.
        * java/lang/reflect/natMethod.cc (getType): Ditto.

        * include/java-field.h (_Jv_Field::isRef): Make robust for
        non-resolved contexts.

        * boehm.cc (_Jv_MarkObj): Mark interpreter-related fields.
        Also, don't mark class->next field.

        * java/lang/VirtualMachineError.java: Added FIXME note.

        * configure.in (INTERPSPEC): New spec.
        * libgcj.spec.in: Added INTERPSPEC.
        * Makefile.am: Added gcjh friends for java/lang/VMClassLoader and
        gnu/gcj/runtime/MethodInvocation.
        (libgcj_la_SOURCES): Added resolve.cc defineclass.cc interpret.cc.
        (ordinary_java_source_files): Added above mentioned java classes.

        * configure: Rebuilt.
        * Makefile.in: Rebuilt.

From-SVN: r28597
1999-08-08 14:06:23 +00:00

2450 lines
49 KiB
C++

// 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