gcc/libjava/interpret.cc

2681 lines
52 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> */
#include <config.h>
#pragma implementation "java-interp.h"
#include <jvm.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>
#ifndef INTERPRETER
#include <gnu/gcj/runtime/MethodInvocation.h>
/* This should never happen. */
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 _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 (_Jv_word *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];
}
};
#define PUSHA(V) (sp++)->o = (V)
#define PUSHI(V) (sp++)->i = (V)
#define PUSHF(V) (sp++)->f = (V)
#define PUSHL(V) ({ _Jv_word2 w2; w2.l=(V); \
(sp++)->ia[0] = w2.ia[0]; \
(sp++)->ia[0] = w2.ia[1]; })
#define PUSHD(V) ({ _Jv_word2 w2; w2.d=(V); \
(sp++)->ia[0] = w2.ia[0]; \
(sp++)->ia[0] = w2.ia[1]; })
#define POPA() ((--sp)->o)
#define POPI() ((jint) (--sp)->i) // cast since it may be promoted
#define POPF() ((jfloat) (--sp)->f)
#define POPL() ({ _Jv_word2 w2; \
w2.ia[1] = (--sp)->ia[0]; \
w2.ia[0] = (--sp)->ia[0]; w2.l; })
#define POPD() ({ _Jv_word2 w2; \
w2.ia[1] = (--sp)->ia[0]; \
w2.ia[0] = (--sp)->ia[0]; w2.d; })
#define LOADA(I) (sp++)->o = locals[I].o
#define LOADI(I) (sp++)->i = locals[I].i
#define LOADF(I) (sp++)->f = locals[I].f
#define LOADL(I) ({ jint __idx = (I); \
(sp++)->ia[0] = locals[__idx].ia[0]; \
(sp++)->ia[0] = locals[__idx+1].ia[0]; \
})
#define LOADD(I) LOADL(I)
#define STOREA(I) locals[I].o = (--sp)->o
#define STOREI(I) locals[I].i = (--sp)->i
#define STOREF(I) locals[I].f = (--sp)->f
#define STOREL(I) ({ jint __idx = (I); \
locals[__idx+1].ia[0] = (--sp)->ia[0]; \
locals[__idx].ia[0] = (--sp)->ia[0]; \
})
#define STORED(I) STOREL(I)
#define PEEKI(I) (locals+(I))->i
#define PEEKA(I) (locals+(I))->o
#define POKEI(I,V) ((locals+(I))->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,
ffi_raw *args,
_Jv_InterpMethodInvocation *inv)
{
inv->running = this;
inv->pc = bytecode ();
inv->sp = inv->stack_base ();
_Jv_word *locals = inv->local_base ();
/* Go straight at it! the ffi raw format matches the internal
stack representation exactly. At leat, that's the idea.
*/
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 */
_Jv_word *sp = 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 = (_Jv_ResolvePoolEntry (defining_class,
exc[i].handler_type)).clazz;
else
handler = NULL;
if (handler==NULL || handler->isAssignableFrom (exc_class))
{
inv->pc = bytecode () + exc[i].handler_pc;
inv->sp = inv->stack_base (); // reset stack
(inv->sp++)->o = ex; // push exception
return true;
}
}
}
return false;
}
void _Jv_InterpMethod::run_normal (ffi_cif* cif,
void* ret,
ffi_raw * 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 (_Jv_word));
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,
ffi_raw * args,
void* __this)
{
_Jv_InterpMethod* _this = (_Jv_InterpMethod*)__this;
jobject rcv = (jobject)args[0].ptr;
int storage_size = _this->max_stack+_this->max_locals;
_Jv_InterpMethodInvocation* inv = (_Jv_InterpMethodInvocation*)
alloca (sizeof (_Jv_InterpMethodInvocation)
+ storage_size * sizeof (_Jv_word));
_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,
ffi_raw * 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 (_Jv_word));
_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 inv->pc 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 __i386__
#define PC_REGISTER_ASM asm("%esi")
#else
#define PC_REGISTER_ASM
#endif
void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv)
{
using namespace java::lang::reflect;
register _Jv_word *sp = inv->sp;
register unsigned char *pc PC_REGISTER_ASM = inv->pc;
_Jv_word *locals = inv->local_base ();
_Jv_word *pool_data = defining_class->constants.data;
/* these two are used in the invokeXXX instructions */
void (*fun)(...);
_Jv_ResolvedMethod* rmeth;
#define INSN_LABEL(op) &&insn_##op
#define GOTO_INSN(op) goto *(insn_target[op])
static const void *const insn_target[] =
{
INSN_LABEL(nop),
INSN_LABEL(aconst_null),
INSN_LABEL(iconst_m1),
INSN_LABEL(iconst_0),
INSN_LABEL(iconst_1),
INSN_LABEL(iconst_2),
INSN_LABEL(iconst_3),
INSN_LABEL(iconst_4),
INSN_LABEL(iconst_5),
INSN_LABEL(lconst_0),
INSN_LABEL(lconst_1),
INSN_LABEL(fconst_0),
INSN_LABEL(fconst_1),
INSN_LABEL(fconst_2),
INSN_LABEL(dconst_0),
INSN_LABEL(dconst_1),
INSN_LABEL(bipush),
INSN_LABEL(sipush),
INSN_LABEL(ldc),
INSN_LABEL(ldc_w),
INSN_LABEL(ldc2_w),
INSN_LABEL(iload),
INSN_LABEL(lload),
INSN_LABEL(fload),
INSN_LABEL(dload),
INSN_LABEL(aload),
INSN_LABEL(iload_0),
INSN_LABEL(iload_1),
INSN_LABEL(iload_2),
INSN_LABEL(iload_3),
INSN_LABEL(lload_0),
INSN_LABEL(lload_1),
INSN_LABEL(lload_2),
INSN_LABEL(lload_3),
INSN_LABEL(fload_0),
INSN_LABEL(fload_1),
INSN_LABEL(fload_2),
INSN_LABEL(fload_3),
INSN_LABEL(dload_0),
INSN_LABEL(dload_1),
INSN_LABEL(dload_2),
INSN_LABEL(dload_3),
INSN_LABEL(aload_0),
INSN_LABEL(aload_1),
INSN_LABEL(aload_2),
INSN_LABEL(aload_3),
INSN_LABEL(iaload),
INSN_LABEL(laload),
INSN_LABEL(faload),
INSN_LABEL(daload),
INSN_LABEL(aaload),
INSN_LABEL(baload),
INSN_LABEL(caload),
INSN_LABEL(saload),
INSN_LABEL(istore),
INSN_LABEL(lstore),
INSN_LABEL(fstore),
INSN_LABEL(dstore),
INSN_LABEL(astore),
INSN_LABEL(istore_0),
INSN_LABEL(istore_1),
INSN_LABEL(istore_2),
INSN_LABEL(istore_3),
INSN_LABEL(lstore_0),
INSN_LABEL(lstore_1),
INSN_LABEL(lstore_2),
INSN_LABEL(lstore_3),
INSN_LABEL(fstore_0),
INSN_LABEL(fstore_1),
INSN_LABEL(fstore_2),
INSN_LABEL(fstore_3),
INSN_LABEL(dstore_0),
INSN_LABEL(dstore_1),
INSN_LABEL(dstore_2),
INSN_LABEL(dstore_3),
INSN_LABEL(astore_0),
INSN_LABEL(astore_1),
INSN_LABEL(astore_2),
INSN_LABEL(astore_3),
INSN_LABEL(iastore),
INSN_LABEL(lastore),
INSN_LABEL(fastore),
INSN_LABEL(dastore),
INSN_LABEL(aastore),
INSN_LABEL(bastore),
INSN_LABEL(castore),
INSN_LABEL(sastore),
INSN_LABEL(pop),
INSN_LABEL(pop2),
INSN_LABEL(dup),
INSN_LABEL(dup_x1),
INSN_LABEL(dup_x2),
INSN_LABEL(dup2),
INSN_LABEL(dup2_x1),
INSN_LABEL(dup2_x2),
INSN_LABEL(swap),
INSN_LABEL(iadd),
INSN_LABEL(ladd),
INSN_LABEL(fadd),
INSN_LABEL(dadd),
INSN_LABEL(isub),
INSN_LABEL(lsub),
INSN_LABEL(fsub),
INSN_LABEL(dsub),
INSN_LABEL(imul),
INSN_LABEL(lmul),
INSN_LABEL(fmul),
INSN_LABEL(dmul),
INSN_LABEL(idiv),
INSN_LABEL(ldiv),
INSN_LABEL(fdiv),
INSN_LABEL(ddiv),
INSN_LABEL(irem),
INSN_LABEL(lrem),
INSN_LABEL(frem),
INSN_LABEL(drem),
INSN_LABEL(ineg),
INSN_LABEL(lneg),
INSN_LABEL(fneg),
INSN_LABEL(dneg),
INSN_LABEL(ishl),
INSN_LABEL(lshl),
INSN_LABEL(ishr),
INSN_LABEL(lshr),
INSN_LABEL(iushr),
INSN_LABEL(lushr),
INSN_LABEL(iand),
INSN_LABEL(land),
INSN_LABEL(ior),
INSN_LABEL(lor),
INSN_LABEL(ixor),
INSN_LABEL(lxor),
INSN_LABEL(iinc),
INSN_LABEL(i2l),
INSN_LABEL(i2f),
INSN_LABEL(i2d),
INSN_LABEL(l2i),
INSN_LABEL(l2f),
INSN_LABEL(l2d),
INSN_LABEL(f2i),
INSN_LABEL(f2l),
INSN_LABEL(f2d),
INSN_LABEL(d2i),
INSN_LABEL(d2l),
INSN_LABEL(d2f),
INSN_LABEL(i2b),
INSN_LABEL(i2c),
INSN_LABEL(i2s),
INSN_LABEL(lcmp),
INSN_LABEL(fcmpl),
INSN_LABEL(fcmpg),
INSN_LABEL(dcmpl),
INSN_LABEL(dcmpg),
INSN_LABEL(ifeq),
INSN_LABEL(ifne),
INSN_LABEL(iflt),
INSN_LABEL(ifge),
INSN_LABEL(ifgt),
INSN_LABEL(ifle),
INSN_LABEL(if_icmpeq),
INSN_LABEL(if_icmpne),
INSN_LABEL(if_icmplt),
INSN_LABEL(if_icmpge),
INSN_LABEL(if_icmpgt),
INSN_LABEL(if_icmple),
INSN_LABEL(if_acmpeq),
INSN_LABEL(if_acmpne),
INSN_LABEL(goto),
INSN_LABEL(jsr),
INSN_LABEL(ret),
INSN_LABEL(tableswitch),
INSN_LABEL(lookupswitch),
INSN_LABEL(ireturn),
INSN_LABEL(lreturn),
INSN_LABEL(freturn),
INSN_LABEL(dreturn),
INSN_LABEL(areturn),
INSN_LABEL(return),
INSN_LABEL(getstatic),
INSN_LABEL(putstatic),
INSN_LABEL(getfield),
INSN_LABEL(putfield),
INSN_LABEL(invokevirtual),
INSN_LABEL(invokespecial),
INSN_LABEL(invokestatic),
INSN_LABEL(invokeinterface),
0, /* op_xxxunusedxxx1, */
INSN_LABEL(new),
INSN_LABEL(newarray),
INSN_LABEL(anewarray),
INSN_LABEL(arraylength),
INSN_LABEL(athrow),
INSN_LABEL(checkcast),
INSN_LABEL(instanceof),
INSN_LABEL(monitorenter),
INSN_LABEL(monitorexit),
INSN_LABEL(wide),
INSN_LABEL(multianewarray),
INSN_LABEL(ifnull),
INSN_LABEL(ifnonnull),
INSN_LABEL(goto_w),
INSN_LABEL(jsr_w),
INSN_LABEL(putfield_1),
INSN_LABEL(putfield_2),
INSN_LABEL(putfield_4),
INSN_LABEL(putfield_8),
INSN_LABEL(putfield_a),
INSN_LABEL(putstatic_1),
INSN_LABEL(putstatic_2),
INSN_LABEL(putstatic_4),
INSN_LABEL(putstatic_8),
INSN_LABEL(putstatic_a),
INSN_LABEL(getfield_1),
INSN_LABEL(getfield_2s),
INSN_LABEL(getfield_2u),
INSN_LABEL(getfield_4),
INSN_LABEL(getfield_8),
INSN_LABEL(getfield_a),
INSN_LABEL(getstatic_1),
INSN_LABEL(getstatic_2s),
INSN_LABEL(getstatic_2u),
INSN_LABEL(getstatic_4),
INSN_LABEL(getstatic_8),
INSN_LABEL(getstatic_a),
};
#define SAVE_PC inv->pc = pc-1
/* If the macro INLINE_SWITCH is not defined, then the main loop
operates as one big (normal) switch statement. If it is defined,
then the case selection is performed `inline' in the end of the
code for each case. The latter saves a native branch instruction
for each java-instruction, but expands the code size somewhat.
NOTE: On i386 defining INLINE_SWITCH improves over all
performance approximately seven percent, but it may be different
for other machines. At some point, this may be made into a proper
configuration parameter. */
#define INLINE_SWITCH
#ifdef INLINE_SWITCH
#define NEXT_INSN GOTO_INSN(*pc++)
NEXT_INSN;
#else
#define NEXT_INSN goto next_insn
next_insn:
GOTO_INSN (*pc++);
#endif
/* The first few instructions here are ordered according to their
frequency, in the hope that this will improve code locality a
little. */
insn_aload_0: // 0x2a
LOADA(0);
NEXT_INSN;
insn_iload: // 0x15
LOADI (get1u (pc++));
NEXT_INSN;
insn_getfield_4: // 0xd8
SAVE_PC;
{
jobject obj = POPA();
NULLCHECK(obj);
jint field_offset = get2u (pc); pc += 2;
PUSHI (*(jint*) ((char*)obj + field_offset));
}
NEXT_INSN;
insn_iload_1: // 0x1b
LOADI (1);
NEXT_INSN;
insn_getfield_a: // 0xda
SAVE_PC;
{
jobject obj = POPA();
NULLCHECK(obj);
jint field_offset = get2u (pc); pc += 2;
PUSHA(*(jobject*) ((char*)obj + field_offset));
}
NEXT_INSN;
insn_invokevirtual: // 0xb6
SAVE_PC;
{
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_ResolvePoolEntry (defining_class, index)).rmethod;
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 = sp[0].o;
_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;
ffi_raw *raw = (ffi_raw*) sp;
jdouble rvalue;
ffi_raw_call (cif, fun, (void*)&rvalue, raw);
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");
}
}
NEXT_INSN;
insn_nop:
NEXT_INSN;
insn_aconst_null:
PUSHA (NULL);
NEXT_INSN;
insn_iconst_m1:
PUSHI (-1);
NEXT_INSN;
insn_iconst_0:
PUSHI (0);
NEXT_INSN;
insn_iconst_1:
PUSHI (1);
NEXT_INSN;
insn_iconst_2:
PUSHI (2);
NEXT_INSN;
insn_iconst_3:
PUSHI (3);
NEXT_INSN;
insn_iconst_4:
PUSHI (4);
NEXT_INSN;
insn_iconst_5:
PUSHI (5);
NEXT_INSN;
insn_lconst_0:
PUSHL (0);
NEXT_INSN;
insn_lconst_1:
PUSHL (1);
NEXT_INSN;
insn_fconst_0:
PUSHF (0);
NEXT_INSN;
insn_fconst_1:
PUSHF (1);
NEXT_INSN;
insn_fconst_2:
PUSHF (2);
NEXT_INSN;
insn_dconst_0:
PUSHD (0);
NEXT_INSN;
insn_dconst_1:
PUSHD (1);
NEXT_INSN;
insn_bipush:
PUSHI (get1s(pc++));
NEXT_INSN;
insn_sipush:
PUSHI (get2s(pc)); pc += 2;
NEXT_INSN;
insn_ldc:
{
int index = get1u (pc++);
PUSHA(pool_data[index].o);
}
NEXT_INSN;
insn_ldc_w:
{
int index = get2u (pc); pc += 2;
PUSHA(pool_data[index].o);
}
NEXT_INSN;
insn_ldc2_w:
{
int index = get2u (pc); pc += 2;
memcpy (sp, &pool_data[index], 2*sizeof (_Jv_word));
sp += 2;
}
NEXT_INSN;
insn_lload:
LOADL (get1u (pc++));
NEXT_INSN;
insn_fload:
LOADF (get1u (pc++));
NEXT_INSN;
insn_dload:
LOADD (get1u (pc++));
NEXT_INSN;
insn_aload:
LOADA (get1u (pc++));
NEXT_INSN;
insn_iload_0:
LOADI (0);
NEXT_INSN;
insn_iload_2:
LOADI (2);
NEXT_INSN;
insn_iload_3:
LOADI (3);
NEXT_INSN;
insn_lload_0:
LOADL (0);
NEXT_INSN;
insn_lload_1:
LOADL (1);
NEXT_INSN;
insn_lload_2:
LOADL (2);
NEXT_INSN;
insn_lload_3:
LOADL (3);
NEXT_INSN;
insn_fload_0:
LOADF (0);
NEXT_INSN;
insn_fload_1:
LOADF (1);
NEXT_INSN;
insn_fload_2:
LOADF (2);
NEXT_INSN;
insn_fload_3:
LOADF (3);
NEXT_INSN;
insn_dload_0:
LOADD (0);
NEXT_INSN;
insn_dload_1:
LOADD (1);
NEXT_INSN;
insn_dload_2:
LOADD (2);
NEXT_INSN;
insn_dload_3:
LOADD (3);
NEXT_INSN;
insn_aload_1:
LOADA(1);
NEXT_INSN;
insn_aload_2:
LOADA(2);
NEXT_INSN;
insn_aload_3:
LOADA(3);
NEXT_INSN;
insn_iaload:
SAVE_PC;
{
jint index = POPI();
jintArray arr = (jintArray) POPA();
NULLCHECK (arr);
if (index < 0 || index >= arr->length)
{
_Jv_ThrowBadArrayIndex (index);
}
PUSHI( elements(arr)[index] );
}
NEXT_INSN;
insn_laload:
SAVE_PC;
{
jint index = POPI();
jlongArray arr = (jlongArray) POPA();
NULLCHECK (arr);
if (index < 0 || index >= arr->length)
{
_Jv_ThrowBadArrayIndex (index);
}
PUSHL( elements(arr)[index] );
}
NEXT_INSN;
insn_faload:
SAVE_PC;
{
jint index = POPI();
jfloatArray arr = (jfloatArray) POPA();
NULLCHECK (arr);
if (index < 0 || index >= arr->length)
{
_Jv_ThrowBadArrayIndex (index);
}
PUSHF( elements(arr)[index] );
}
NEXT_INSN;
insn_daload:
SAVE_PC;
{
jint index = POPI();
jdoubleArray arr = (jdoubleArray) POPA();
NULLCHECK (arr);
if (index < 0 || index >= arr->length)
{
_Jv_ThrowBadArrayIndex (index);
}
PUSHD( elements(arr)[index] );
}
NEXT_INSN;
insn_aaload:
SAVE_PC;
{
jint index = POPI();
jobjectArray arr = (jobjectArray) POPA();
NULLCHECK (arr);
if (index < 0 || index >= arr->length)
{
_Jv_ThrowBadArrayIndex (index);
}
PUSHA( elements(arr)[index] );
}
NEXT_INSN;
insn_baload:
SAVE_PC;
{
jint index = POPI();
jbyteArray arr = (jbyteArray) POPA();
NULLCHECK (arr);
if (index < 0 || index >= arr->length)
{
_Jv_ThrowBadArrayIndex (index);
}
PUSHI( elements(arr)[index] );
}
NEXT_INSN;
insn_caload:
SAVE_PC;
{
jint index = POPI();
jcharArray arr = (jcharArray) POPA();
NULLCHECK (arr);
if (index < 0 || index >= arr->length)
{
_Jv_ThrowBadArrayIndex (index);
}
PUSHI( elements(arr)[index] );
}
NEXT_INSN;
insn_saload:
SAVE_PC;
{
jint index = POPI();
jshortArray arr = (jshortArray) POPA();
NULLCHECK (arr);
if (index < 0 || index >= arr->length)
{
_Jv_ThrowBadArrayIndex (index);
}
PUSHI( elements(arr)[index] );
}
NEXT_INSN;
insn_istore:
STOREI (get1u (pc++));
NEXT_INSN;
insn_lstore:
STOREL (get1u (pc++));
NEXT_INSN;
insn_fstore:
STOREF (get1u (pc++));
NEXT_INSN;
insn_dstore:
STORED (get1u (pc++));
NEXT_INSN;
insn_astore:
STOREI (get1u (pc++));
NEXT_INSN;
insn_istore_0:
STOREI (0);
NEXT_INSN;
insn_istore_1:
STOREI (1);
NEXT_INSN;
insn_istore_2:
STOREI (2);
NEXT_INSN;
insn_istore_3:
STOREI (3);
NEXT_INSN;
insn_lstore_0:
STOREL (0);
NEXT_INSN;
insn_lstore_1:
STOREL (1);
NEXT_INSN;
insn_lstore_2:
STOREL (2);
NEXT_INSN;
insn_lstore_3:
STOREL (3);
NEXT_INSN;
insn_fstore_0:
STOREF (0);
NEXT_INSN;
insn_fstore_1:
STOREF (1);
NEXT_INSN;
insn_fstore_2:
STOREF (2);
NEXT_INSN;
insn_fstore_3:
STOREF (3);
NEXT_INSN;
insn_dstore_0:
STORED (0);
NEXT_INSN;
insn_dstore_1:
STORED (1);
NEXT_INSN;
insn_dstore_2:
STORED (2);
NEXT_INSN;
insn_dstore_3:
STORED (3);
NEXT_INSN;
insn_astore_0:
STOREA(0);
NEXT_INSN;
insn_astore_1:
STOREA(1);
NEXT_INSN;
insn_astore_2:
STOREA(2);
NEXT_INSN;
insn_astore_3:
STOREA(3);
NEXT_INSN;
insn_iastore:
SAVE_PC;
{
jint value = POPI();
jint index = POPI();
jintArray arr = (jintArray) POPA();
NULLCHECK (arr);
if (index < 0 || index >= arr->length)
{
_Jv_ThrowBadArrayIndex (index);
}
elements(arr)[index] = value;
}
NEXT_INSN;
insn_lastore:
SAVE_PC;
{
jlong value = POPL();
jint index = POPI();
jlongArray arr = (jlongArray) POPA();
NULLCHECK (arr);
if (index < 0 || index >= arr->length)
{
_Jv_ThrowBadArrayIndex (index);
}
elements(arr)[index] = value;
}
NEXT_INSN;
insn_fastore:
SAVE_PC;
{
jfloat value = POPF();
jint index = POPI();
jfloatArray arr = (jfloatArray) POPA();
NULLCHECK (arr);
if (index < 0 || index >= arr->length)
{
_Jv_ThrowBadArrayIndex (index);
}
elements(arr)[index] = value;
}
NEXT_INSN;
insn_dastore:
SAVE_PC;
{
jdouble value = POPD();
jint index = POPI();
jdoubleArray arr = (jdoubleArray) POPA();
NULLCHECK (arr);
if (index < 0 || index >= arr->length)
{
_Jv_ThrowBadArrayIndex (index);
}
elements(arr)[index] = value;
}
NEXT_INSN;
insn_aastore:
SAVE_PC;
{
jobject value = POPA();
jint index = POPI();
jobjectArray arr = (jobjectArray) POPA();
NULLCHECK (arr);
if (index < 0 || index >= arr->length)
{
_Jv_ThrowBadArrayIndex (index);
}
_Jv_CheckArrayStore (arr, value);
elements(arr)[index] = value;
}
NEXT_INSN;
insn_bastore:
SAVE_PC;
{
jbyte value = (jbyte) POPI();
jint index = POPI();
jbyteArray arr = (jbyteArray) POPA();
NULLCHECK (arr);
if (index < 0 || index >= arr->length)
{
_Jv_ThrowBadArrayIndex (index);
}
elements(arr)[index] = value;
}
NEXT_INSN;
insn_castore:
SAVE_PC;
{
jchar value = (jchar) POPI();
jint index = POPI();
jcharArray arr = (jcharArray) POPA();
NULLCHECK (arr);
if (index < 0 || index >= arr->length)
{
_Jv_ThrowBadArrayIndex (index);
}
elements(arr)[index] = value;
}
NEXT_INSN;
insn_sastore:
SAVE_PC;
{
jshort value = (jshort) POPI();
jint index = POPI();
jshortArray arr = (jshortArray) POPA();
NULLCHECK (arr);
if (index < 0 || index >= arr->length)
{
_Jv_ThrowBadArrayIndex (index);
}
elements(arr)[index] = value;
}
NEXT_INSN;
insn_pop:
sp -= 1;
NEXT_INSN;
insn_pop2:
sp -= 2;
NEXT_INSN;
insn_dup:
sp[0] = sp[-1];
sp += 1;
NEXT_INSN;
insn_dup_x1:
dupx (sp, 1, 1); sp+=1;
NEXT_INSN;
insn_dup_x2:
dupx (sp, 1, 2); sp+=1;
NEXT_INSN;
insn_dup2:
sp[0] = sp[-2];
sp[1] = sp[-1];
sp += 2;
NEXT_INSN;
insn_dup2_x1:
dupx (sp, 2, 1); sp+=2;
NEXT_INSN;
insn_dup2_x2:
dupx (sp, 2, 2); sp+=2;
NEXT_INSN;
insn_swap:
{
jobject tmp1 = POPA();
jobject tmp2 = POPA();
PUSHA (tmp1);
PUSHA (tmp2);
}
NEXT_INSN;
insn_iadd:
BINOPI(+);
NEXT_INSN;
insn_ladd:
BINOPL(+);
NEXT_INSN;
insn_fadd:
BINOPF(+);
NEXT_INSN;
insn_dadd:
BINOPD(+);
NEXT_INSN;
insn_isub:
BINOPI(-);
NEXT_INSN;
insn_lsub:
BINOPL(-);
NEXT_INSN;
insn_fsub:
BINOPF(-);
NEXT_INSN;
insn_dsub:
BINOPD(-);
NEXT_INSN;
insn_imul:
BINOPI(*);
NEXT_INSN;
insn_lmul:
BINOPL(*);
NEXT_INSN;
insn_fmul:
BINOPF(*);
NEXT_INSN;
insn_dmul:
BINOPD(*);
NEXT_INSN;
insn_idiv:
SAVE_PC;
{
jint value2 = POPI();
jint value1 = POPI();
ZEROCHECK (value2);
jint res = value1 / value2;
PUSHI (res);
}
NEXT_INSN;
insn_ldiv:
SAVE_PC;
{
jlong value2 = POPL();
jlong value1 = POPL();
ZEROCHECK (value2);
jlong res = value1 / value2;
PUSHL (res);
}
NEXT_INSN;
insn_fdiv:
SAVE_PC;
{
jfloat value2 = POPF();
jfloat value1 = POPF();
ZEROCHECK (value2);
jfloat res = value1 / value2;
PUSHF (res);
}
NEXT_INSN;
insn_ddiv:
SAVE_PC;
{
jdouble value2 = POPD();
jdouble value1 = POPD();
ZEROCHECK (value2);
jdouble res = value1 / value2;
PUSHD (res);
}
NEXT_INSN;
insn_irem:
SAVE_PC;
{
jint value2 = POPI();
jint value1 = POPI();
ZEROCHECK (value2);
jint res = value1 % value2;
PUSHI (res);
}
NEXT_INSN;
insn_lrem:
SAVE_PC;
{
jlong value2 = POPL();
jlong value1 = POPL();
ZEROCHECK (value2);
jlong res = value1 % value2;
PUSHL (res);
}
NEXT_INSN;
insn_frem:
SAVE_PC;
{
jfloat value2 = POPF();
jfloat value1 = POPF();
ZEROCHECK (value2);
jfloat res = __ieee754_fmod (value1, value2);
PUSHF (res);
}
NEXT_INSN;
insn_drem:
SAVE_PC;
{
jdouble value2 = POPD();
jdouble value1 = POPD();
ZEROCHECK (value2);
jdouble res = __ieee754_fmod (value1, value2);
PUSHD (res);
}
NEXT_INSN;
insn_ineg:
{
jint value = POPI();
PUSHI (value * -1);
}
NEXT_INSN;
insn_lneg:
{
jlong value = POPL();
PUSHL (value * -1);
}
NEXT_INSN;
insn_fneg:
{
jfloat value = POPF();
PUSHF (value * -1);
}
NEXT_INSN;
insn_dneg:
{
jdouble value = POPD();
PUSHD (value * -1);
}
NEXT_INSN;
insn_ishl:
{
jint shift = (POPI() & 0x1f);
jint value = POPI();
PUSHI (value << shift);
}
NEXT_INSN;
insn_lshl:
{
jint shift = (POPI() & 0x3f);
jlong value = POPL();
PUSHL (value << shift);
}
NEXT_INSN;
insn_ishr:
{
jint shift = (POPI() & 0x1f);
jint value = POPI();
PUSHI (value >> shift);
}
NEXT_INSN;
insn_lshr:
{
jint shift = (POPI() & 0x3f);
jlong value = POPL();
PUSHL (value >> shift);
}
NEXT_INSN;
insn_iushr:
{
jint shift = (POPI() & 0x1f);
unsigned long value = POPI();
PUSHI ((jint) (value >> shift));
}
NEXT_INSN;
insn_lushr:
{
jint shift = (POPI() & 0x3f);
UINT64 value = (UINT64) POPL();
PUSHL ((value >> shift));
}
NEXT_INSN;
insn_iand:
BINOPI (&);
NEXT_INSN;
insn_land:
BINOPL (&);
NEXT_INSN;
insn_ior:
BINOPI (|);
NEXT_INSN;
insn_lor:
BINOPL (|);
NEXT_INSN;
insn_ixor:
BINOPI (^);
NEXT_INSN;
insn_lxor:
BINOPL (^);
NEXT_INSN;
insn_iinc:
{
jint index = get1u (pc++);
jint amount = get1s (pc++);
locals[index].i += amount;
}
NEXT_INSN;
insn_i2l:
{jlong value = POPI(); PUSHL (value);}
NEXT_INSN;
insn_i2f:
{jfloat value = POPI(); PUSHF (value);}
NEXT_INSN;
insn_i2d:
{jdouble value = POPI(); PUSHD (value);}
NEXT_INSN;
insn_l2i:
{jint value = POPL(); PUSHI (value);}
NEXT_INSN;
insn_l2f:
{jfloat value = POPL(); PUSHF (value);}
NEXT_INSN;
insn_l2d:
{jdouble value = POPL(); PUSHD (value);}
NEXT_INSN;
insn_f2i:
{ jint value = (jint)POPF (); PUSHI(value); }
NEXT_INSN;
insn_f2l:
{ jlong value = (jlong)POPF (); PUSHL(value); }
NEXT_INSN;
insn_f2d:
{ jdouble value = POPF (); PUSHD(value); }
NEXT_INSN;
insn_d2i:
{ jint value = (jint)POPD (); PUSHI(value); }
NEXT_INSN;
insn_d2l:
{ jlong value = (jlong)POPD (); PUSHL(value); }
NEXT_INSN;
insn_d2f:
{ jfloat value = POPD (); PUSHF(value); }
NEXT_INSN;
insn_i2b:
{ jbyte value = POPI (); PUSHI(value); }
NEXT_INSN;
insn_i2c:
{ jchar value = POPI (); PUSHI(value); }
NEXT_INSN;
insn_i2s:
{ jshort value = POPI (); PUSHI(value); }
NEXT_INSN;
insn_lcmp:
{
jlong value2 = POPL ();
jlong value1 = POPL ();
if (value1 > value2)
{ PUSHI (1); }
else if (value1 == value2)
{ PUSHI (0); }
else
{ PUSHI (-1); }
}
NEXT_INSN;
insn_fcmpl:
insn_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 ((*(pc-1)) == op_fcmpg)
PUSHI (1);
else
PUSHI (-1);
}
NEXT_INSN;
insn_dcmpl:
insn_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 ((*(pc-1)) == op_dcmpg)
PUSHI (1);
else
PUSHI (-1);
}
NEXT_INSN;
insn_ifeq:
{
jint offset = get2s (pc);
if (POPI() == 0)
pc = pc-1+offset;
else
pc = pc+2;
}
NEXT_INSN;
insn_ifne:
{
jint offset = get2s (pc);
if (POPI() != 0)
pc = pc-1+offset;
else
pc = pc+2;
}
NEXT_INSN;
insn_iflt:
{
jint offset = get2s (pc);
if (POPI() < 0)
pc = pc-1+offset;
else
pc = pc+2;
}
NEXT_INSN;
insn_ifge:
{
jint offset = get2s (pc);
if (POPI() >= 0)
pc = pc-1+offset;
else
pc = pc+2;
}
NEXT_INSN;
insn_ifgt:
{
jint offset = get2s (pc);
if (POPI() > 0)
pc = pc-1+offset;
else
pc = pc+2;
}
NEXT_INSN;
insn_ifle:
{
jint offset = get2s (pc);
if (POPI() <= 0)
pc = pc-1+offset;
else
pc = pc+2;
}
NEXT_INSN;
insn_if_icmpeq:
{
jint offset = get2s (pc);
jint value2 = POPI();
jint value1 = POPI();
if (value1 == value2)
pc = pc-1+offset;
else
pc = pc+2;
}
NEXT_INSN;
insn_if_icmpne:
{
jint offset = get2s (pc);
jint value2 = POPI();
jint value1 = POPI();
if (value1 != value2)
pc = pc-1+offset;
else
pc = pc+2;
}
NEXT_INSN;
insn_if_icmplt:
{
jint offset = get2s (pc);
jint value2 = POPI();
jint value1 = POPI();
if (value1 < value2)
pc = pc-1+offset;
else
pc = pc+2;
}
NEXT_INSN;
insn_if_icmpge:
{
jint offset = get2s (pc);
jint value2 = POPI();
jint value1 = POPI();
if (value1 >= value2)
pc = pc-1+offset;
else
pc = pc+2;
}
NEXT_INSN;
insn_if_icmpgt:
{
jint offset = get2s (pc);
jint value2 = POPI();
jint value1 = POPI();
if (value1 > value2)
pc = pc-1+offset;
else
pc = pc+2;
}
NEXT_INSN;
insn_if_icmple:
{
jint offset = get2s (pc);
jint value2 = POPI();
jint value1 = POPI();
if (value1 <= value2)
pc = pc-1+offset;
else
pc = pc+2;
}
NEXT_INSN;
insn_if_acmpeq:
{
jint offset = get2s (pc);
jobject value2 = POPA();
jobject value1 = POPA();
if (value1 == value2)
pc = pc-1+offset;
else
pc = pc+2;
}
NEXT_INSN;
insn_if_acmpne:
{
jint offset = get2s (pc);
jobject value2 = POPA();
jobject value1 = POPA();
if (value1 != value2)
pc = pc-1+offset;
else
pc = pc+2;
}
NEXT_INSN;
insn_goto:
{
jint offset = get2s (pc);
pc = pc-1+offset;
}
NEXT_INSN;
insn_jsr:
{
unsigned char *base_pc = pc-1;
jint offset = get2s (pc); pc += 2;
PUSHA ((jobject)pc);
pc = base_pc+offset;
}
NEXT_INSN;
insn_ret:
{
jint index = get1u (pc);
pc = (unsigned char*) PEEKA (index);
}
NEXT_INSN;
insn_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));
}
NEXT_INSN;
insn_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;
}
NEXT_INSN;
/* on return, just save the sp and return to caller */
insn_ireturn:
insn_lreturn:
insn_freturn:
insn_dreturn:
insn_areturn:
insn_return:
inv->sp = sp;
return;
insn_getstatic:
SAVE_PC;
{
unsigned char *base_pc = pc-1;
jint fieldref_index = get2u (pc); pc += 2;
_Jv_ResolvePoolEntry (defining_class, fieldref_index);
_Jv_Field *field = pool_data[fieldref_index].field;
if ((field->flags & Modifier::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;
}
NEXT_INSN;
insn_getfield:
SAVE_PC;
{
unsigned char *base_pc = pc-1;
jint fieldref_index = get2u (pc); pc += 2;
_Jv_ResolvePoolEntry (defining_class, fieldref_index);
_Jv_Field *field = pool_data[fieldref_index].field;
if ((field->flags & Modifier::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;
}
NEXT_INSN;
insn_putstatic:
SAVE_PC;
{
unsigned char* base_pc = pc-1;
jint fieldref_index = get2u (pc); pc += 2;
_Jv_ResolvePoolEntry (defining_class, fieldref_index);
_Jv_Field *field = pool_data[fieldref_index].field;
jclass type = field->type;
// ResolvePoolEntry cannot check this
if ((field->flags & Modifier::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;
}
NEXT_INSN;
insn_putfield:
SAVE_PC;
{
unsigned char* base_pc = pc-1;
jint fieldref_index = get2u (pc); pc += 2;
_Jv_ResolvePoolEntry (defining_class, fieldref_index);
_Jv_Field *field = pool_data[fieldref_index].field;
jclass type = field->type;
if ((field->flags & Modifier::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;
}
NEXT_INSN;
insn_getfield_1:
SAVE_PC;
{
jobject obj = POPA();
NULLCHECK(obj);
jint field_offset = get2u (pc); pc += 2;
PUSHI (*(jbyte*) ((char*)obj + field_offset));
}
NEXT_INSN;
insn_getfield_2s:
SAVE_PC;
{
jobject obj = POPA();
NULLCHECK(obj);
jint field_offset = get2u (pc); pc += 2;
PUSHI (*(jshort*) ((char*)obj + field_offset));
}
NEXT_INSN;
insn_getfield_2u:
SAVE_PC;
{
jobject obj = POPA();
NULLCHECK(obj);
jint field_offset = get2u (pc); pc += 2;
PUSHI (*(jchar*) ((char*)obj + field_offset));
}
NEXT_INSN;
insn_getfield_8:
SAVE_PC;
{
jobject obj = POPA();
NULLCHECK(obj);
jint field_offset = get2u (pc); pc += 2;
PUSHL(*(jlong*) ((char*)obj + field_offset));
}
NEXT_INSN;
insn_getstatic_1:
{
jint fieldref_index = get2u (pc); pc += 2;
_Jv_Field *field = pool_data[fieldref_index].field;
PUSHI (*(jbyte*) (field->u.addr));
}
NEXT_INSN;
insn_getstatic_2s:
{
jint fieldref_index = get2u (pc); pc += 2;
_Jv_Field *field = pool_data[fieldref_index].field;
PUSHI(*(jshort*) (field->u.addr));
}
NEXT_INSN;
insn_getstatic_2u:
{
jint fieldref_index = get2u (pc); pc += 2;
_Jv_Field *field = pool_data[fieldref_index].field;
PUSHI(*(jchar*) (field->u.addr));
}
NEXT_INSN;
insn_getstatic_4:
{
jint fieldref_index = get2u (pc); pc += 2;
_Jv_Field *field = pool_data[fieldref_index].field;
PUSHI(*(jint*) (field->u.addr));
}
NEXT_INSN;
insn_getstatic_8:
{
jint fieldref_index = get2u (pc); pc += 2;
_Jv_Field *field = pool_data[fieldref_index].field;
PUSHL(*(jlong*) (field->u.addr));
}
NEXT_INSN;
insn_getstatic_a:
{
jint fieldref_index = get2u (pc); pc += 2;
_Jv_Field *field = pool_data[fieldref_index].field;
PUSHA(*(jobject*) (field->u.addr));
}
NEXT_INSN;
insn_putfield_1:
SAVE_PC;
{
jint value = POPI();
jobject obj = POPA();
NULLCHECK(obj);
jint field_offset = get2u (pc); pc += 2;
*(jbyte*) ((char*)obj + field_offset) = value;
}
NEXT_INSN;
insn_putfield_2:
SAVE_PC;
{
jint value = POPI();
jobject obj = POPA();
NULLCHECK(obj);
jint field_offset = get2u (pc); pc += 2;
*(jchar*) ((char*)obj + field_offset) = value;
}
NEXT_INSN;
insn_putfield_4:
SAVE_PC;
{
jint value = POPI();
jobject obj = POPA();
NULLCHECK(obj);
jint field_offset = get2u (pc); pc += 2;
*(jint*) ((char*)obj + field_offset) = value;
}
NEXT_INSN;
insn_putfield_8:
SAVE_PC;
{
jlong value = POPL();
jobject obj = POPA();
NULLCHECK(obj);
jint field_offset = get2u (pc); pc += 2;
*(jlong*) ((char*)obj + field_offset) = value;
}
NEXT_INSN;
insn_putfield_a:
SAVE_PC;
{
jobject value = POPA();
jobject obj = POPA();
NULLCHECK(obj);
jint field_offset = get2u (pc); pc += 2;
*(jobject*) ((char*)obj + field_offset) = value;
}
NEXT_INSN;
insn_putstatic_1:
{
jint value = POPI();
jint fieldref_index = get2u (pc); pc += 2;
_Jv_Field *field = pool_data[fieldref_index].field;
*(jbyte*) (field->u.addr) = value;
}
NEXT_INSN;
insn_putstatic_2:
{
jint value = POPI();
jint fieldref_index = get2u (pc); pc += 2;
_Jv_Field *field = pool_data[fieldref_index].field;
*(jchar*) (field->u.addr) = value;
}
NEXT_INSN;
insn_putstatic_4:
{
jint value = POPI();
jint fieldref_index = get2u (pc); pc += 2;
_Jv_Field *field = pool_data[fieldref_index].field;
*(jint*) (field->u.addr) = value;
}
NEXT_INSN;
insn_putstatic_8:
{
jlong value = POPL();
jint fieldref_index = get2u (pc); pc += 2;
_Jv_Field *field = pool_data[fieldref_index].field;
*(jlong*) (field->u.addr) = value;
}
NEXT_INSN;
insn_putstatic_a:
{
jobject value = POPA();
jint fieldref_index = get2u (pc); pc += 2;
_Jv_Field *field = pool_data[fieldref_index].field;
*(jobject*) (field->u.addr) = value;
}
NEXT_INSN;
insn_invokespecial:
SAVE_PC;
{
int index = get2u (pc); pc += 2;
rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod;
sp -= rmeth->stack_item_count;
NULLCHECK(sp[0]);
fun = (void (*) (...))rmeth->method->ncode;
}
goto perform_invoke;
insn_invokestatic:
SAVE_PC;
{
int index = get2u (pc); pc += 2;
rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod;
sp -= rmeth->stack_item_count;
_Jv_InitClass (rmeth->klass);
fun = (void (*) (...))rmeth->method->ncode;
}
goto perform_invoke;
insn_invokeinterface:
SAVE_PC;
{
int index = get2u (pc); pc += 2;
// invokeinterface has two unused bytes...
pc += 2;
rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod;
sp -= rmeth->stack_item_count;
NULLCHECK(sp[0]);
jobject rcv = sp[0].o;
fun = (void (*) (...))
_Jv_LookupInterfaceMethod (rcv->getClass (),
rmeth->method->name,
rmeth->method->signature);
}
goto perform_invoke;
insn_new:
SAVE_PC;
{
int index = get2u (pc); pc += 2;
jclass klass = (_Jv_ResolvePoolEntry (defining_class, index)).clazz;
_Jv_InitClass (klass);
jobject res = _Jv_AllocObject (klass, klass->size_in_bytes);
PUSHA (res);
}
NEXT_INSN;
insn_newarray:
SAVE_PC;
{
int atype = get1u (pc++);
int size = POPI();
jobject result = _Jv_NewArray (atype, size);
PUSHA (result);
}
NEXT_INSN;
insn_anewarray:
SAVE_PC;
{
int index = get2u (pc); pc += 2;
jclass klass = (_Jv_ResolvePoolEntry (defining_class, index)).clazz;
int size = POPI();
_Jv_InitClass (klass);
jobject result = _Jv_NewObjectArray (size, klass, 0);
PUSHA (result);
}
NEXT_INSN;
insn_arraylength:
SAVE_PC;
{
__JArray *arr = (__JArray*)POPA();
PUSHI (arr->length);
}
NEXT_INSN;
insn_athrow:
SAVE_PC;
{
jobject value = POPA();
JvThrow (value);
}
NEXT_INSN;
insn_checkcast:
SAVE_PC;
{
jobject value = POPA();
jint index = get2u (pc); pc += 2;
jclass to = (_Jv_ResolvePoolEntry (defining_class, index)).clazz;
if (value != NULL && ! to->isInstance (value))
{
JvThrow (new java::lang::ClassCastException
(to->getName()));
}
PUSHA (value);
}
NEXT_INSN;
insn_instanceof:
SAVE_PC;
{
jobject value = POPA();
jint index = get2u (pc); pc += 2;
jclass to = (_Jv_ResolvePoolEntry (defining_class, index)).clazz;
PUSHI (to->isInstance (value));
}
NEXT_INSN;
insn_monitorenter:
SAVE_PC;
{
jobject value = POPA();
NULLCHECK(value);
_Jv_MonitorEnter (value);
}
NEXT_INSN;
insn_monitorexit:
SAVE_PC;
{
jobject value = POPA();
NULLCHECK(value);
_Jv_MonitorExit (value);
}
NEXT_INSN;
insn_ifnull:
{
unsigned char* base_pc = pc-1;
jint offset = get2s (pc); pc += 2;
jobject val = POPA();
if (val == NULL)
pc = base_pc+offset;
}
NEXT_INSN;
insn_ifnonnull:
{
unsigned char* base_pc = pc-1;
jint offset = get2s (pc); pc += 2;
jobject val = POPA();
if (val != NULL)
pc = base_pc+offset;
}
NEXT_INSN;
insn_wide:
SAVE_PC;
{
jint the_mod_op = get1u (pc++);
jint wide = get2u (pc); pc += 2;
switch (the_mod_op)
{
case op_istore:
STOREI (wide);
NEXT_INSN;
case op_fstore:
STOREF (wide);
NEXT_INSN;
case op_astore:
STOREA (wide);
NEXT_INSN;
case op_lload:
LOADL (wide);
NEXT_INSN;
case op_dload:
LOADD (wide);
NEXT_INSN;
case op_iload:
LOADI (wide);
NEXT_INSN;
case op_aload:
LOADA (wide);
NEXT_INSN;
case op_lstore:
STOREL (wide);
NEXT_INSN;
case op_dstore:
STORED (wide);
NEXT_INSN;
case op_ret:
pc = (unsigned char*) PEEKA (wide);
NEXT_INSN;
case op_iinc:
{
jint amount = get2s (pc); pc += 2;
jint value = PEEKI (wide);
POKEI (wide, value+amount);
}
NEXT_INSN;
default:
throw_internal_error ("illegal bytecode modified by wide");
}
}
insn_multianewarray:
SAVE_PC;
{
int kind_index = get2u (pc); pc += 2;
int dim = get1u (pc); pc += 1;
jclass type
= (_Jv_ResolvePoolEntry (defining_class, kind_index)).clazz;
_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);
}
NEXT_INSN;
insn_goto_w:
{
unsigned char* base_pc = pc-1;
int offset = get4 (pc); pc += 4;
pc = base_pc+offset;
}
NEXT_INSN;
insn_jsr_w:
{
unsigned char* base_pc = pc-1;
int offset = get4 (pc); pc += 4;
PUSHA((jobject)pc);
pc = base_pc+offset;
}
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
#endif // INTERPRETER