Commit 50ac2500 by Kyle Galloway

java-interp.h (_Jv_InterpMethod::run_debug): New method.

2006-08-15  Kyle Galloway  <kgallowa@redhat.com>

  * include/java-interp.h (_Jv_InterpMethod::run_debug): New method.
  * interpret.cc: Added placeholder for debug variable type info to STORE*
  macros.
  (_Jv_InterpMethod::run_debug): New method.
  (_Jv_InterpMethod::run_sync_object_debug): New method.
  (_Jv_InterpMethod::run_sync_class_debug): New method.
  (_Jv_InterpMethod::run_normal_debug): New method.
  (_Jv_InterpMethod::run_class_debug): New method.
  (_Jv_InterpMethod::ncode ()): Changed to select either debug or normal
  versions of these functions.
  * interpret-run.cc: New file, holds contents of old 	
  _Jv_InterpMethod::run method.
  * stacktrace.cc (_Jv_StackTrace::UnwindTraceFn): Changed to select
  appropriate function for debug or normal mode.

From-SVN: r116167
parent 4adb785d
...@@ -176,21 +176,31 @@ class _Jv_InterpMethod : public _Jv_MethodBase ...@@ -176,21 +176,31 @@ class _Jv_InterpMethod : public _Jv_MethodBase
static void run_synch_object (ffi_cif*, void*, ffi_raw*, void*); static void run_synch_object (ffi_cif*, void*, ffi_raw*, void*);
static void run_class (ffi_cif*, void*, ffi_raw*, void*); static void run_class (ffi_cif*, void*, ffi_raw*, void*);
static void run_synch_class (ffi_cif*, void*, ffi_raw*, void*); static void run_synch_class (ffi_cif*, void*, ffi_raw*, void*);
static void run_normal_debug (ffi_cif*, void*, ffi_raw*, void*);
static void run_synch_object_debug (ffi_cif*, void*, ffi_raw*, void*);
static void run_class_debug (ffi_cif*, void*, ffi_raw*, void*);
static void run_synch_class_debug (ffi_cif*, void*, ffi_raw*, void*);
static void run (void*, ffi_raw *, _Jv_InterpMethod *); static void run (void *, ffi_raw *, _Jv_InterpMethod *);
static void run_debug (void *, ffi_raw *, _Jv_InterpMethod *);
// Returns source file line number for given PC value, or -1 if line // Returns source file line number for given PC value, or -1 if line
// number info is unavailable. // number info is unavailable.
int get_source_line(pc_t mpc); int get_source_line(pc_t mpc);
#ifdef DIRECT_THREADED #ifdef DIRECT_THREADED
// Convenience function for indexing bytecode PC/insn slots in // Convenience function for indexing bytecode PC/insn slots in
// line tables for JDWP // line tables for JDWP
jlong insn_index (pc_t pc); jlong insn_index (pc_t pc);
#endif #endif
public: public:
/* Get the line table for this method. /* Get the line table for this method.
* start is the lowest index in the method * start is the lowest index in the method
* end is the highest index in the method * end is the highest index in the method
......
// interpret-run.cc - Code to interpret bytecode
/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation
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. */
/* This file is meant only to be included in interpret.cc, it should not be
* compiled directly. */
using namespace java::lang::reflect;
// FRAME_DESC registers this particular invocation as the top-most
// interpreter frame. This lets the stack tracing code (for
// Throwable) print information about the method being interpreted
// rather than about the interpreter itself. FRAME_DESC has a
// destructor so it cleans up automatically when the interpreter
// returns.
java::lang::Thread *thread = java::lang::Thread::currentThread();
_Jv_InterpFrame frame_desc (meth, thread);
_Jv_word stack[meth->max_stack];
_Jv_word *sp = stack;
_Jv_word locals[meth->max_locals];
#define INSN_LABEL(op) &&insn_##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, /* Unused. */
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),
#ifdef DIRECT_THREADED
0, // wide
#else
INSN_LABEL(wide),
#endif
INSN_LABEL(multianewarray),
INSN_LABEL(ifnull),
INSN_LABEL(ifnonnull),
INSN_LABEL(goto_w),
INSN_LABEL(jsr_w),
#ifdef DIRECT_THREADED
INSN_LABEL (ldc_class)
#else
0
#endif
};
pc_t pc;
#ifdef DIRECT_THREADED
#define NEXT_INSN goto *((pc++)->insn)
#define INTVAL() ((pc++)->int_val)
#define AVAL() ((pc++)->datum)
#define GET1S() INTVAL ()
#define GET2S() INTVAL ()
#define GET1U() INTVAL ()
#define GET2U() INTVAL ()
#define AVAL1U() AVAL ()
#define AVAL2U() AVAL ()
#define AVAL2UP() AVAL ()
#define SKIP_GOTO ++pc
#define GOTO_VAL() (insn_slot *) pc->datum
#define PCVAL(unionval) unionval.p
#define AMPAMP(label) &&label
// Compile if we must. NOTE: Double-check locking.
if (meth->prepared == NULL)
{
_Jv_MutexLock (&compile_mutex);
if (meth->prepared == NULL)
meth->compile (insn_target);
_Jv_MutexUnlock (&compile_mutex);
}
// If we're only compiling, stop here
if (args == NULL)
return;
pc = (insn_slot *) meth->prepared;
#else
#define NEXT_INSN goto *(insn_target[*pc++])
#define GET1S() get1s (pc++)
#define GET2S() (pc += 2, get2s (pc- 2))
#define GET1U() get1u (pc++)
#define GET2U() (pc += 2, get2u (pc - 2))
// Note that these could be more efficient when not handling 'ldc
// class'.
#define AVAL1U() \
({ int index = get1u (pc++); \
resolve_pool_entry (meth->defining_class, index).o; })
#define AVAL2U() \
({ int index = get2u (pc); pc += 2; \
resolve_pool_entry (meth->defining_class, index).o; })
// Note that we don't need to resolve the pool entry here as class
// constants are never wide.
#define AVAL2UP() ({ int index = get2u (pc); pc += 2; &pool_data[index]; })
#define SKIP_GOTO pc += 2
#define GOTO_VAL() pc - 1 + get2s (pc)
#define PCVAL(unionval) unionval.i
#define AMPAMP(label) NULL
pc = bytecode ();
#endif /* DIRECT_THREADED */
#define TAKE_GOTO pc = GOTO_VAL ()
/* Go straight at it! the ffi raw format matches the internal
stack representation exactly. At least, that's the idea.
*/
memcpy ((void*) locals, (void*) args, meth->args_raw_size);
_Jv_word *pool_data = meth->defining_class->constants.data;
/* These three are temporaries for common code used by several
instructions. */
void (*fun)();
_Jv_ResolvedMethod* rmeth;
int tmpval;
try
{
// We keep nop around. It is used if we're interpreting the
// bytecodes and not doing direct threading.
insn_nop:
NEXT_INSN;
/* 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 ());
NEXT_INSN;
insn_iload_1: // 0x1b
LOADI (1);
NEXT_INSN;
insn_invokevirtual: // 0xb6
{
SAVE_PC();
int index = GET2U ();
/* _Jv_Linker::resolve_pool_entry 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_Linker::resolve_pool_entry (meth->defining_class,
index)).rmethod;
sp -= rmeth->stack_item_count;
if (rmeth->method->accflags & Modifier::FINAL)
{
// We can't rely on NULLCHECK working if the method is final.
if (! sp[0].o)
throw_null_pointer_exception ();
// Final methods might not appear in the vtable.
fun = (void (*)()) rmeth->method->ncode;
}
else
{
NULLCHECK (sp[0].o);
jobject rcv = sp[0].o;
_Jv_VTable *table = *(_Jv_VTable**) rcv;
fun = (void (*)()) table->get_method (rmeth->method->index);
}
#ifdef DIRECT_THREADED
// Rewrite instruction so that we use a faster pre-resolved
// method.
pc[-2].insn = &&invokevirtual_resolved;
pc[-1].datum = rmeth;
#endif /* DIRECT_THREADED */
}
goto perform_invoke;
#ifdef DIRECT_THREADED
invokevirtual_resolved:
{
SAVE_PC();
rmeth = (_Jv_ResolvedMethod *) AVAL ();
sp -= rmeth->stack_item_count;
if (rmeth->method->accflags & Modifier::FINAL)
{
// We can't rely on NULLCHECK working if the method is final.
if (! sp[0].o)
throw_null_pointer_exception ();
// Final methods might not appear in the vtable.
fun = (void (*)()) rmeth->method->ncode;
}
else
{
jobject rcv = sp[0].o;
_Jv_VTable *table = *(_Jv_VTable**) rcv;
fun = (void (*)()) table->get_method (rmeth->method->index);
}
}
goto perform_invoke;
#endif /* DIRECT_THREADED */
perform_invoke:
{
/* here goes the magic again... */
ffi_cif *cif = &rmeth->cif;
ffi_raw *raw = (ffi_raw*) sp;
_Jv_value rvalue;
#if FFI_NATIVE_RAW_API
/* We assume that this is only implemented if it's correct */
/* to use it here. On a 64 bit machine, it never is. */
ffi_raw_call (cif, fun, (void*)&rvalue, raw);
#else
ffi_java_raw_call (cif, fun, (void*)&rvalue, raw);
#endif
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 (rvalue.object_value);
}
else if (rtype == FFI_TYPE_SINT32)
{
PUSHI (rvalue.int_value);
}
else if (rtype == FFI_TYPE_VOID)
{
/* skip */
}
else
{
switch (rtype)
{
case FFI_TYPE_SINT8:
PUSHI ((jbyte)(rvalue.int_value & 0xff));
break;
case FFI_TYPE_SINT16:
PUSHI ((jshort)(rvalue.int_value & 0xffff));
break;
case FFI_TYPE_UINT16:
PUSHI (rvalue.int_value & 0xffff);
break;
case FFI_TYPE_FLOAT:
PUSHF (rvalue.float_value);
break;
case FFI_TYPE_DOUBLE:
PUSHD (rvalue.double_value);
break;
case FFI_TYPE_SINT64:
PUSHL (rvalue.long_value);
break;
default:
throw_internal_error ("unknown return type in invokeXXX");
}
}
}
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:
// For direct threaded, bipush and sipush are the same.
#ifndef DIRECT_THREADED
PUSHI (GET1S ());
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_sipush:
PUSHI (GET2S ());
NEXT_INSN;
insn_ldc:
// For direct threaded, ldc and ldc_w are the same.
#ifndef DIRECT_THREADED
PUSHA ((jobject) AVAL1U ());
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_ldc_w:
PUSHA ((jobject) AVAL2U ());
NEXT_INSN;
#ifdef DIRECT_THREADED
// For direct threaded we have a separate 'ldc class' operation.
insn_ldc_class:
{
SAVE_PC();
// We could rewrite the instruction at this point.
int index = INTVAL ();
jobject k = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).o;
PUSHA (k);
}
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_ldc2_w:
{
void *where = AVAL2UP ();
memcpy (sp, where, 2*sizeof (_Jv_word));
sp += 2;
}
NEXT_INSN;
insn_lload:
LOADL (GET1U ());
NEXT_INSN;
insn_fload:
LOADF (GET1U ());
NEXT_INSN;
insn_dload:
LOADD (GET1U ());
NEXT_INSN;
insn_aload:
LOADA (GET1U ());
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:
{
jint index = POPI();
jintArray arr = (jintArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
PUSHI( elements(arr)[index] );
}
NEXT_INSN;
insn_laload:
{
jint index = POPI();
jlongArray arr = (jlongArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
PUSHL( elements(arr)[index] );
}
NEXT_INSN;
insn_faload:
{
jint index = POPI();
jfloatArray arr = (jfloatArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
PUSHF( elements(arr)[index] );
}
NEXT_INSN;
insn_daload:
{
jint index = POPI();
jdoubleArray arr = (jdoubleArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
PUSHD( elements(arr)[index] );
}
NEXT_INSN;
insn_aaload:
{
jint index = POPI();
jobjectArray arr = (jobjectArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
PUSHA( elements(arr)[index] );
}
NEXT_INSN;
insn_baload:
{
jint index = POPI();
jbyteArray arr = (jbyteArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
PUSHI( elements(arr)[index] );
}
NEXT_INSN;
insn_caload:
{
jint index = POPI();
jcharArray arr = (jcharArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
PUSHI( elements(arr)[index] );
}
NEXT_INSN;
insn_saload:
{
jint index = POPI();
jshortArray arr = (jshortArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
PUSHI( elements(arr)[index] );
}
NEXT_INSN;
insn_istore:
STOREI (GET1U ());
NEXT_INSN;
insn_lstore:
STOREL (GET1U ());
NEXT_INSN;
insn_fstore:
STOREF (GET1U ());
NEXT_INSN;
insn_dstore:
STORED (GET1U ());
NEXT_INSN;
insn_astore:
STOREA (GET1U ());
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:
{
jint value = POPI();
jint index = POPI();
jintArray arr = (jintArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
elements(arr)[index] = value;
}
NEXT_INSN;
insn_lastore:
{
jlong value = POPL();
jint index = POPI();
jlongArray arr = (jlongArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
elements(arr)[index] = value;
}
NEXT_INSN;
insn_fastore:
{
jfloat value = POPF();
jint index = POPI();
jfloatArray arr = (jfloatArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
elements(arr)[index] = value;
}
NEXT_INSN;
insn_dastore:
{
jdouble value = POPD();
jint index = POPI();
jdoubleArray arr = (jdoubleArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
elements(arr)[index] = value;
}
NEXT_INSN;
insn_aastore:
{
jobject value = POPA();
jint index = POPI();
jobjectArray arr = (jobjectArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
_Jv_CheckArrayStore (arr, value);
elements(arr)[index] = value;
}
NEXT_INSN;
insn_bastore:
{
jbyte value = (jbyte) POPI();
jint index = POPI();
jbyteArray arr = (jbyteArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
elements(arr)[index] = value;
}
NEXT_INSN;
insn_castore:
{
jchar value = (jchar) POPI();
jint index = POPI();
jcharArray arr = (jcharArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
elements(arr)[index] = value;
}
NEXT_INSN;
insn_sastore:
{
jshort value = (jshort) POPI();
jint index = POPI();
jshortArray arr = (jshortArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, 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();
jint res = _Jv_divI (value1, value2);
PUSHI (res);
}
NEXT_INSN;
insn_ldiv:
{
SAVE_PC();
jlong value2 = POPL();
jlong value1 = POPL();
jlong res = _Jv_divJ (value1, value2);
PUSHL (res);
}
NEXT_INSN;
insn_fdiv:
{
jfloat value2 = POPF();
jfloat value1 = POPF();
jfloat res = value1 / value2;
PUSHF (res);
}
NEXT_INSN;
insn_ddiv:
{
jdouble value2 = POPD();
jdouble value1 = POPD();
jdouble res = value1 / value2;
PUSHD (res);
}
NEXT_INSN;
insn_irem:
{
SAVE_PC();
jint value2 = POPI();
jint value1 = POPI();
jint res = _Jv_remI (value1, value2);
PUSHI (res);
}
NEXT_INSN;
insn_lrem:
{
SAVE_PC();
jlong value2 = POPL();
jlong value1 = POPL();
jlong res = _Jv_remJ (value1, value2);
PUSHL (res);
}
NEXT_INSN;
insn_frem:
{
jfloat value2 = POPF();
jfloat value1 = POPF();
jfloat res = __ieee754_fmod (value1, value2);
PUSHF (res);
}
NEXT_INSN;
insn_drem:
{
jdouble value2 = POPD();
jdouble value1 = POPD();
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);
_Jv_uint value = (_Jv_uint) POPI();
PUSHI ((jint) (value >> shift));
}
NEXT_INSN;
insn_lushr:
{
jint shift = (POPI() & 0x3f);
_Jv_ulong value = (_Jv_ulong) POPL();
PUSHL ((jlong) (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 ();
jint amount = GET1S ();
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:
{
using namespace java::lang;
jint value = convert (POPF (), Integer::MIN_VALUE, Integer::MAX_VALUE);
PUSHI(value);
}
NEXT_INSN;
insn_f2l:
{
using namespace java::lang;
jlong value = convert (POPF (), Long::MIN_VALUE, Long::MAX_VALUE);
PUSHL(value);
}
NEXT_INSN;
insn_f2d:
{ jdouble value = POPF (); PUSHD(value); }
NEXT_INSN;
insn_d2i:
{
using namespace java::lang;
jint value = convert (POPD (), Integer::MIN_VALUE, Integer::MAX_VALUE);
PUSHI(value);
}
NEXT_INSN;
insn_d2l:
{
using namespace java::lang;
jlong value = convert (POPD (), Long::MIN_VALUE, Long::MAX_VALUE);
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:
tmpval = -1;
goto fcmp;
insn_fcmpg:
tmpval = 1;
fcmp:
{
jfloat value2 = POPF ();
jfloat value1 = POPF ();
if (value1 > value2)
PUSHI (1);
else if (value1 == value2)
PUSHI (0);
else if (value1 < value2)
PUSHI (-1);
else
PUSHI (tmpval);
}
NEXT_INSN;
insn_dcmpl:
tmpval = -1;
goto dcmp;
insn_dcmpg:
tmpval = 1;
dcmp:
{
jdouble value2 = POPD ();
jdouble value1 = POPD ();
if (value1 > value2)
PUSHI (1);
else if (value1 == value2)
PUSHI (0);
else if (value1 < value2)
PUSHI (-1);
else
PUSHI (tmpval);
}
NEXT_INSN;
insn_ifeq:
{
if (POPI() == 0)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_ifne:
{
if (POPI() != 0)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_iflt:
{
if (POPI() < 0)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_ifge:
{
if (POPI() >= 0)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_ifgt:
{
if (POPI() > 0)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_ifle:
{
if (POPI() <= 0)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_if_icmpeq:
{
jint value2 = POPI();
jint value1 = POPI();
if (value1 == value2)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_if_icmpne:
{
jint value2 = POPI();
jint value1 = POPI();
if (value1 != value2)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_if_icmplt:
{
jint value2 = POPI();
jint value1 = POPI();
if (value1 < value2)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_if_icmpge:
{
jint value2 = POPI();
jint value1 = POPI();
if (value1 >= value2)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_if_icmpgt:
{
jint value2 = POPI();
jint value1 = POPI();
if (value1 > value2)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_if_icmple:
{
jint value2 = POPI();
jint value1 = POPI();
if (value1 <= value2)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_if_acmpeq:
{
jobject value2 = POPA();
jobject value1 = POPA();
if (value1 == value2)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_if_acmpne:
{
jobject value2 = POPA();
jobject value1 = POPA();
if (value1 != value2)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_goto_w:
#ifndef DIRECT_THREADED
// For direct threaded, goto and goto_w are the same.
pc = pc - 1 + get4 (pc);
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_goto:
TAKE_GOTO;
NEXT_INSN;
insn_jsr_w:
#ifndef DIRECT_THREADED
// For direct threaded, jsr and jsr_w are the same.
{
pc_t next = pc - 1 + get4 (pc);
pc += 4;
PUSHA ((jobject) pc);
pc = next;
}
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_jsr:
{
pc_t next = GOTO_VAL();
SKIP_GOTO;
PUSHA ((jobject) pc);
pc = next;
}
NEXT_INSN;
insn_ret:
{
jint index = GET1U ();
pc = (pc_t) PEEKA (index);
}
NEXT_INSN;
insn_tableswitch:
{
#ifdef DIRECT_THREADED
void *def = (pc++)->datum;
int index = POPI();
jint low = INTVAL ();
jint high = INTVAL ();
if (index < low || index > high)
pc = (insn_slot *) def;
else
pc = (insn_slot *) ((pc + index - low)->datum);
#else
pc_t base_pc = pc - 1;
int index = POPI ();
pc_t base = (pc_t) 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));
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
insn_lookupswitch:
{
#ifdef DIRECT_THREADED
void *def = (pc++)->insn;
int index = POPI();
jint npairs = INTVAL ();
int max = npairs - 1;
int min = 0;
// Simple binary search...
while (min < max)
{
int half = (min + max) / 2;
int match = pc[2 * half].int_val;
if (index == match)
{
// Found it.
pc = (insn_slot *) pc[2 * half + 1].datum;
NEXT_INSN;
}
else if (index < match)
// We can use HALF - 1 here because we check again on
// loop exit.
max = half - 1;
else
// We can use HALF + 1 here because we check again on
// loop exit.
min = half + 1;
}
if (index == pc[2 * min].int_val)
pc = (insn_slot *) pc[2 * min + 1].datum;
else
pc = (insn_slot *) def;
#else
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)
// We can use HALF - 1 here because we check again on
// loop exit.
max = half - 1;
else
// We can use HALF + 1 here because we check again on
// loop exit.
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;
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
insn_areturn:
*(jobject *) retp = POPA ();
return;
insn_lreturn:
*(jlong *) retp = POPL ();
return;
insn_freturn:
*(jfloat *) retp = POPF ();
return;
insn_dreturn:
*(jdouble *) retp = POPD ();
return;
insn_ireturn:
*(jint *) retp = POPI ();
return;
insn_return:
return;
insn_getstatic:
{
jint fieldref_index = GET2U ();
SAVE_PC(); // Constant pool resolution could throw.
_Jv_Linker::resolve_pool_entry (meth->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;
// We rewrite the instruction once we discover what it refers
// to.
void *newinsn = NULL;
if (type->isPrimitive ())
{
switch (type->size_in_bytes)
{
case 1:
PUSHI (*field->u.byte_addr);
newinsn = AMPAMP (getstatic_resolved_1);
break;
case 2:
if (type == JvPrimClass (char))
{
PUSHI (*field->u.char_addr);
newinsn = AMPAMP (getstatic_resolved_char);
}
else
{
PUSHI (*field->u.short_addr);
newinsn = AMPAMP (getstatic_resolved_short);
}
break;
case 4:
PUSHI(*field->u.int_addr);
newinsn = AMPAMP (getstatic_resolved_4);
break;
case 8:
PUSHL(*field->u.long_addr);
newinsn = AMPAMP (getstatic_resolved_8);
break;
}
}
else
{
PUSHA(*field->u.object_addr);
newinsn = AMPAMP (getstatic_resolved_obj);
}
#ifdef DIRECT_THREADED
pc[-2].insn = newinsn;
pc[-1].datum = field->u.addr;
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
#ifdef DIRECT_THREADED
getstatic_resolved_1:
PUSHI (*(jbyte *) AVAL ());
NEXT_INSN;
getstatic_resolved_char:
PUSHI (*(jchar *) AVAL ());
NEXT_INSN;
getstatic_resolved_short:
PUSHI (*(jshort *) AVAL ());
NEXT_INSN;
getstatic_resolved_4:
PUSHI (*(jint *) AVAL ());
NEXT_INSN;
getstatic_resolved_8:
PUSHL (*(jlong *) AVAL ());
NEXT_INSN;
getstatic_resolved_obj:
PUSHA (*(jobject *) AVAL ());
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_getfield:
{
SAVE_PC();
jint fieldref_index = GET2U ();
_Jv_Linker::resolve_pool_entry (meth->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;
jint field_offset = field->u.boffset;
jobject obj = POPA();
NULLCHECK(obj);
void *newinsn = NULL;
_Jv_value *val = (_Jv_value *) ((char *)obj + field_offset);
if (type->isPrimitive ())
{
switch (type->size_in_bytes)
{
case 1:
PUSHI (val->byte_value);
newinsn = AMPAMP (getfield_resolved_1);
break;
case 2:
if (type == JvPrimClass (char))
{
PUSHI (val->char_value);
newinsn = AMPAMP (getfield_resolved_char);
}
else
{
PUSHI (val->short_value);
newinsn = AMPAMP (getfield_resolved_short);
}
break;
case 4:
PUSHI (val->int_value);
newinsn = AMPAMP (getfield_resolved_4);
break;
case 8:
PUSHL (val->long_value);
newinsn = AMPAMP (getfield_resolved_8);
break;
}
}
else
{
PUSHA (val->object_value);
newinsn = AMPAMP (getfield_resolved_obj);
}
#ifdef DIRECT_THREADED
pc[-2].insn = newinsn;
pc[-1].int_val = field_offset;
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
#ifdef DIRECT_THREADED
getfield_resolved_1:
{
char *obj = (char *) POPA ();
NULLCHECK (obj);
PUSHI (*(jbyte *) (obj + INTVAL ()));
}
NEXT_INSN;
getfield_resolved_char:
{
char *obj = (char *) POPA ();
NULLCHECK (obj);
PUSHI (*(jchar *) (obj + INTVAL ()));
}
NEXT_INSN;
getfield_resolved_short:
{
char *obj = (char *) POPA ();
NULLCHECK (obj);
PUSHI (*(jshort *) (obj + INTVAL ()));
}
NEXT_INSN;
getfield_resolved_4:
{
char *obj = (char *) POPA ();
NULLCHECK (obj);
PUSHI (*(jint *) (obj + INTVAL ()));
}
NEXT_INSN;
getfield_resolved_8:
{
char *obj = (char *) POPA ();
NULLCHECK (obj);
PUSHL (*(jlong *) (obj + INTVAL ()));
}
NEXT_INSN;
getfield_resolved_obj:
{
char *obj = (char *) POPA ();
NULLCHECK (obj);
PUSHA (*(jobject *) (obj + INTVAL ()));
}
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_putstatic:
{
SAVE_PC();
jint fieldref_index = GET2U ();
_Jv_Linker::resolve_pool_entry (meth->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"));
void *newinsn = NULL;
if (type->isPrimitive ())
{
switch (type->size_in_bytes)
{
case 1:
{
jint value = POPI();
*field->u.byte_addr = value;
newinsn = AMPAMP (putstatic_resolved_1);
break;
}
case 2:
{
jint value = POPI();
*field->u.char_addr = value;
newinsn = AMPAMP (putstatic_resolved_2);
break;
}
case 4:
{
jint value = POPI();
*field->u.int_addr = value;
newinsn = AMPAMP (putstatic_resolved_4);
break;
}
case 8:
{
jlong value = POPL();
*field->u.long_addr = value;
newinsn = AMPAMP (putstatic_resolved_8);
break;
}
}
}
else
{
jobject value = POPA();
*field->u.object_addr = value;
newinsn = AMPAMP (putstatic_resolved_obj);
}
#ifdef DIRECT_THREADED
pc[-2].insn = newinsn;
pc[-1].datum = field->u.addr;
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
#ifdef DIRECT_THREADED
putstatic_resolved_1:
*(jbyte *) AVAL () = POPI ();
NEXT_INSN;
putstatic_resolved_2:
*(jchar *) AVAL () = POPI ();
NEXT_INSN;
putstatic_resolved_4:
*(jint *) AVAL () = POPI ();
NEXT_INSN;
putstatic_resolved_8:
*(jlong *) AVAL () = POPL ();
NEXT_INSN;
putstatic_resolved_obj:
*(jobject *) AVAL () = POPA ();
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_putfield:
{
SAVE_PC();
jint fieldref_index = GET2U ();
_Jv_Linker::resolve_pool_entry (meth->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"));
jint field_offset = field->u.boffset;
void *newinsn = NULL;
if (type->isPrimitive ())
{
switch (type->size_in_bytes)
{
case 1:
{
jint value = POPI();
jobject obj = POPA();
NULLCHECK(obj);
*(jbyte*) ((char*)obj + field_offset) = value;
newinsn = AMPAMP (putfield_resolved_1);
break;
}
case 2:
{
jint value = POPI();
jobject obj = POPA();
NULLCHECK(obj);
*(jchar*) ((char*)obj + field_offset) = value;
newinsn = AMPAMP (putfield_resolved_2);
break;
}
case 4:
{
jint value = POPI();
jobject obj = POPA();
NULLCHECK(obj);
*(jint*) ((char*)obj + field_offset) = value;
newinsn = AMPAMP (putfield_resolved_4);
break;
}
case 8:
{
jlong value = POPL();
jobject obj = POPA();
NULLCHECK(obj);
*(jlong*) ((char*)obj + field_offset) = value;
newinsn = AMPAMP (putfield_resolved_8);
break;
}
}
}
else
{
jobject value = POPA();
jobject obj = POPA();
NULLCHECK(obj);
*(jobject*) ((char*)obj + field_offset) = value;
newinsn = AMPAMP (putfield_resolved_obj);
}
#ifdef DIRECT_THREADED
pc[-2].insn = newinsn;
pc[-1].int_val = field_offset;
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
#ifdef DIRECT_THREADED
putfield_resolved_1:
{
jint val = POPI ();
char *obj = (char *) POPA ();
NULLCHECK (obj);
*(jbyte *) (obj + INTVAL ()) = val;
}
NEXT_INSN;
putfield_resolved_2:
{
jint val = POPI ();
char *obj = (char *) POPA ();
NULLCHECK (obj);
*(jchar *) (obj + INTVAL ()) = val;
}
NEXT_INSN;
putfield_resolved_4:
{
jint val = POPI ();
char *obj = (char *) POPA ();
NULLCHECK (obj);
*(jint *) (obj + INTVAL ()) = val;
}
NEXT_INSN;
putfield_resolved_8:
{
jlong val = POPL ();
char *obj = (char *) POPA ();
NULLCHECK (obj);
*(jlong *) (obj + INTVAL ()) = val;
}
NEXT_INSN;
putfield_resolved_obj:
{
jobject val = POPA ();
char *obj = (char *) POPA ();
NULLCHECK (obj);
*(jobject *) (obj + INTVAL ()) = val;
}
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_invokespecial:
{
SAVE_PC();
int index = GET2U ();
rmeth = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).rmethod;
sp -= rmeth->stack_item_count;
// We don't use NULLCHECK here because we can't rely on that
// working for <init>. So instead we do an explicit test.
if (! sp[0].o)
{
SAVE_PC();
throw_null_pointer_exception ();
}
fun = (void (*)()) rmeth->method->ncode;
#ifdef DIRECT_THREADED
// Rewrite instruction so that we use a faster pre-resolved
// method.
pc[-2].insn = &&invokespecial_resolved;
pc[-1].datum = rmeth;
#endif /* DIRECT_THREADED */
}
goto perform_invoke;
#ifdef DIRECT_THREADED
invokespecial_resolved:
{
SAVE_PC();
rmeth = (_Jv_ResolvedMethod *) AVAL ();
sp -= rmeth->stack_item_count;
// We don't use NULLCHECK here because we can't rely on that
// working for <init>. So instead we do an explicit test.
if (! sp[0].o)
{
throw_null_pointer_exception ();
}
fun = (void (*)()) rmeth->method->ncode;
}
goto perform_invoke;
#endif /* DIRECT_THREADED */
insn_invokestatic:
{
SAVE_PC();
int index = GET2U ();
rmeth = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).rmethod;
sp -= rmeth->stack_item_count;
fun = (void (*)()) rmeth->method->ncode;
#ifdef DIRECT_THREADED
// Rewrite instruction so that we use a faster pre-resolved
// method.
pc[-2].insn = &&invokestatic_resolved;
pc[-1].datum = rmeth;
#endif /* DIRECT_THREADED */
}
goto perform_invoke;
#ifdef DIRECT_THREADED
invokestatic_resolved:
{
SAVE_PC();
rmeth = (_Jv_ResolvedMethod *) AVAL ();
sp -= rmeth->stack_item_count;
fun = (void (*)()) rmeth->method->ncode;
}
goto perform_invoke;
#endif /* DIRECT_THREADED */
insn_invokeinterface:
{
SAVE_PC();
int index = GET2U ();
rmeth = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).rmethod;
sp -= rmeth->stack_item_count;
jobject rcv = sp[0].o;
NULLCHECK (rcv);
fun = (void (*)())
_Jv_LookupInterfaceMethod (rcv->getClass (),
rmeth->method->name,
rmeth->method->signature);
#ifdef DIRECT_THREADED
// Rewrite instruction so that we use a faster pre-resolved
// method.
pc[-2].insn = &&invokeinterface_resolved;
pc[-1].datum = rmeth;
#else
// Skip dummy bytes.
pc += 2;
#endif /* DIRECT_THREADED */
}
goto perform_invoke;
#ifdef DIRECT_THREADED
invokeinterface_resolved:
{
SAVE_PC();
rmeth = (_Jv_ResolvedMethod *) AVAL ();
sp -= rmeth->stack_item_count;
jobject rcv = sp[0].o;
NULLCHECK (rcv);
fun = (void (*)())
_Jv_LookupInterfaceMethod (rcv->getClass (),
rmeth->method->name,
rmeth->method->signature);
}
goto perform_invoke;
#endif /* DIRECT_THREADED */
insn_new:
{
SAVE_PC();
int index = GET2U ();
jclass klass = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).clazz;
/* VM spec, section 3.11.5 */
if ((klass->getModifiers() & Modifier::ABSTRACT)
|| klass->isInterface())
throw new java::lang::InstantiationException;
jobject res = _Jv_AllocObject (klass);
PUSHA (res);
#ifdef DIRECT_THREADED
pc[-2].insn = &&new_resolved;
pc[-1].datum = klass;
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
#ifdef DIRECT_THREADED
new_resolved:
{
jclass klass = (jclass) AVAL ();
jobject res = _Jv_AllocObject (klass);
PUSHA (res);
}
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_newarray:
{
int atype = GET1U ();
int size = POPI();
jobject result = _Jv_NewArray (atype, size);
PUSHA (result);
}
NEXT_INSN;
insn_anewarray:
{
SAVE_PC();
int index = GET2U ();
jclass klass = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).clazz;
int size = POPI();
jobject result = _Jv_NewObjectArray (size, klass, 0);
PUSHA (result);
#ifdef DIRECT_THREADED
pc[-2].insn = &&anewarray_resolved;
pc[-1].datum = klass;
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
#ifdef DIRECT_THREADED
anewarray_resolved:
{
jclass klass = (jclass) AVAL ();
int size = POPI ();
jobject result = _Jv_NewObjectArray (size, klass, 0);
PUSHA (result);
}
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_arraylength:
{
__JArray *arr = (__JArray*)POPA();
NULLARRAYCHECK (arr);
PUSHI (arr->length);
}
NEXT_INSN;
insn_athrow:
{
jobject value = POPA();
throw static_cast<jthrowable>(value);
}
NEXT_INSN;
insn_checkcast:
{
SAVE_PC();
jobject value = POPA();
jint index = GET2U ();
jclass to = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).clazz;
value = (jobject) _Jv_CheckCast (to, value);
PUSHA (value);
#ifdef DIRECT_THREADED
pc[-2].insn = &&checkcast_resolved;
pc[-1].datum = to;
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
#ifdef DIRECT_THREADED
checkcast_resolved:
{
SAVE_PC();
jobject value = POPA ();
jclass to = (jclass) AVAL ();
value = (jobject) _Jv_CheckCast (to, value);
PUSHA (value);
}
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_instanceof:
{
SAVE_PC();
jobject value = POPA();
jint index = GET2U ();
jclass to = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).clazz;
PUSHI (to->isInstance (value));
#ifdef DIRECT_THREADED
pc[-2].insn = &&instanceof_resolved;
pc[-1].datum = to;
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
#ifdef DIRECT_THREADED
instanceof_resolved:
{
jobject value = POPA ();
jclass to = (jclass) AVAL ();
PUSHI (to->isInstance (value));
}
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_monitorenter:
{
jobject value = POPA();
NULLCHECK(value);
_Jv_MonitorEnter (value);
}
NEXT_INSN;
insn_monitorexit:
{
jobject value = POPA();
NULLCHECK(value);
_Jv_MonitorExit (value);
}
NEXT_INSN;
insn_ifnull:
{
jobject val = POPA();
if (val == NULL)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_ifnonnull:
{
jobject val = POPA();
if (val != NULL)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_multianewarray:
{
SAVE_PC();
int kind_index = GET2U ();
int dim = GET1U ();
jclass type
= (_Jv_Linker::resolve_pool_entry (meth->defining_class,
kind_index)).clazz;
jint *sizes = (jint*) __builtin_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;
#ifndef DIRECT_THREADED
insn_wide:
{
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_fload:
LOADF (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");
}
}
#endif /* DIRECT_THREADED */
}
catch (java::lang::Throwable *ex)
{
#ifdef DIRECT_THREADED
void *logical_pc = (void *) ((insn_slot *) pc - 1);
#else
int logical_pc = pc - 1 - bytecode ();
#endif
_Jv_InterpException *exc = meth->exceptions ();
jclass exc_class = ex->getClass ();
for (int i = 0; i < meth->exc_count; i++)
{
if (PCVAL (exc[i].start_pc) <= logical_pc
&& logical_pc < PCVAL (exc[i].end_pc))
{
#ifdef DIRECT_THREADED
jclass handler = (jclass) exc[i].handler_type.p;
#else
jclass handler = NULL;
if (exc[i].handler_type.i != 0)
handler = (_Jv_Linker::resolve_pool_entry (defining_class,
exc[i].handler_type.i)).clazz;
#endif /* DIRECT_THREADED */
if (handler == NULL || handler->isAssignableFrom (exc_class))
{
#ifdef DIRECT_THREADED
pc = (insn_slot *) exc[i].handler_pc.p;
#else
pc = bytecode () + exc[i].handler_pc.i;
#endif /* DIRECT_THREADED */
sp = stack;
sp++->o = ex; // Push exception.
NEXT_INSN;
}
}
}
// No handler, so re-throw.
throw ex;
}
...@@ -37,6 +37,8 @@ details. */ ...@@ -37,6 +37,8 @@ details. */
#include <execution.h> #include <execution.h>
#include <java/lang/reflect/Modifier.h> #include <java/lang/reflect/Modifier.h>
#include <gnu/classpath/jdwp/Jdwp.h>
#ifdef INTERPRETER #ifdef INTERPRETER
// Execution engine for interpreted code. // Execution engine for interpreted code.
...@@ -152,24 +154,54 @@ convert (FROM val, TO min, TO max) ...@@ -152,24 +154,54 @@ convert (FROM val, TO min, TO max)
# define LOADD(I) LOADL(I) # define LOADD(I) LOADL(I)
#endif #endif
#define STOREA(I) locals[I].o = (--sp)->o #define STOREA(I) \
#define STOREI(I) locals[I].i = (--sp)->i do { \
#define STOREF(I) locals[I].f = (--sp)->f DEBUG_LOCALS_INSN(I, 'o'); \
locals[I].o = (--sp)->o; \
} while(0)
#define STOREI(I) \
do { \
DEBUG_LOCALS_INSN (I, 'i'); \
locals[I].i = (--sp)->i; \
} while(0)
#define STOREF(I) \
do { \
DEBUG_LOCALS_INSN (I, 'f'); \
locals[I].f = (--sp)->f; \
} while(0)
#if SIZEOF_VOID_P == 8 #if SIZEOF_VOID_P == 8
# define STOREL(I) (sp -= 2, locals[I].l = sp->l) # define STOREL(I) \
# define STORED(I) (sp -= 2, locals[I].d = sp->d) do { \
DEBUG_LOCALS_INSN (I, 'l'); \
(sp -= 2, locals[I].l = sp->l); \
} while(0)
# define STORED(I) \
do { \
DEBUG_LOCALS_INSN (I, 'd'); \
(sp -= 2, locals[I].d = sp->d); \
} while(0)
#else #else
# define STOREL(I) do { jint __idx = (I); \ # define STOREL(I) \
locals[__idx+1].ia[0] = (--sp)->ia[0]; \ do { DEBUG_LOCALS_INSN(I, 'l'); \
locals[__idx].ia[0] = (--sp)->ia[0]; \ jint __idx = (I); \
} while (0) locals[__idx+1].ia[0] = (--sp)->ia[0]; \
# define STORED(I) STOREL(I) locals[__idx].ia[0] = (--sp)->ia[0]; \
} while (0)
# define STORED(I) \
do { DEBUG_LOCALS_INSN(I, 'd'); \
jint __idx = (I); \
locals[__idx+1].ia[0] = (--sp)->ia[0]; \
locals[__idx].ia[0] = (--sp)->ia[0]; \
} while (0)
#endif #endif
#define PEEKI(I) (locals+(I))->i #define PEEKI(I) (locals+(I))->i
#define PEEKA(I) (locals+(I))->o #define PEEKA(I) (locals+(I))->o
#define POKEI(I,V) ((locals+(I))->i = (V)) #define POKEI(I,V) \
DEBUG_LOCALS_INSN(I,i) \
((locals+(I))->i = (V))
#define BINOPI(OP) { \ #define BINOPI(OP) { \
...@@ -258,6 +290,16 @@ _Jv_InterpMethod::run_normal (ffi_cif *, ...@@ -258,6 +290,16 @@ _Jv_InterpMethod::run_normal (ffi_cif *,
} }
void void
_Jv_InterpMethod::run_normal_debug (ffi_cif *,
void* ret,
ffi_raw * args,
void* __this)
{
_Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
run_debug (ret, args, _this);
}
void
_Jv_InterpMethod::run_synch_object (ffi_cif *, _Jv_InterpMethod::run_synch_object (ffi_cif *,
void* ret, void* ret,
ffi_raw * args, ffi_raw * args,
...@@ -272,6 +314,20 @@ _Jv_InterpMethod::run_synch_object (ffi_cif *, ...@@ -272,6 +314,20 @@ _Jv_InterpMethod::run_synch_object (ffi_cif *,
} }
void void
_Jv_InterpMethod::run_synch_object_debug (ffi_cif *,
void* ret,
ffi_raw * args,
void* __this)
{
_Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
jobject rcv = (jobject) args[0].ptr;
JvSynchronize mutex (rcv);
run_debug (ret, args, _this);
}
void
_Jv_InterpMethod::run_class (ffi_cif *, _Jv_InterpMethod::run_class (ffi_cif *,
void* ret, void* ret,
ffi_raw * args, ffi_raw * args,
...@@ -283,6 +339,17 @@ _Jv_InterpMethod::run_class (ffi_cif *, ...@@ -283,6 +339,17 @@ _Jv_InterpMethod::run_class (ffi_cif *,
} }
void void
_Jv_InterpMethod::run_class_debug (ffi_cif *,
void* ret,
ffi_raw * args,
void* __this)
{
_Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
_Jv_InitClass (_this->defining_class);
run_debug (ret, args, _this);
}
void
_Jv_InterpMethod::run_synch_class (ffi_cif *, _Jv_InterpMethod::run_synch_class (ffi_cif *,
void* ret, void* ret,
ffi_raw * args, ffi_raw * args,
...@@ -297,6 +364,21 @@ _Jv_InterpMethod::run_synch_class (ffi_cif *, ...@@ -297,6 +364,21 @@ _Jv_InterpMethod::run_synch_class (ffi_cif *,
run (ret, args, _this); run (ret, args, _this);
} }
void
_Jv_InterpMethod::run_synch_class_debug (ffi_cif *,
void* ret,
ffi_raw * args,
void* __this)
{
_Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
jclass sync = _this->defining_class;
_Jv_InitClass (sync);
JvSynchronize mutex (sync);
run_debug (ret, args, _this);
}
#ifdef DIRECT_THREADED #ifdef DIRECT_THREADED
// "Compile" a method by turning it from bytecode to direct-threaded // "Compile" a method by turning it from bytecode to direct-threaded
// code. // code.
...@@ -805,2714 +887,244 @@ _Jv_InterpMethod::compile (const void * const *insn_targets) ...@@ -805,2714 +887,244 @@ _Jv_InterpMethod::compile (const void * const *insn_targets)
void void
_Jv_InterpMethod::run (void *retp, ffi_raw *args, _Jv_InterpMethod *meth) _Jv_InterpMethod::run (void *retp, ffi_raw *args, _Jv_InterpMethod *meth)
{ {
using namespace java::lang::reflect; #undef DEBUG
#undef DEBUG_LOCALS_INSN
// FRAME_DESC registers this particular invocation as the top-most #define DEBUG_LOCALS_INSN(s, t) do {} while(0)
// interpreter frame. This lets the stack tracing code (for
// Throwable) print information about the method being interpreted
// rather than about the interpreter itself. FRAME_DESC has a
// destructor so it cleans up automatically when the interpreter
// returns.
java::lang::Thread *thread = java::lang::Thread::currentThread();
_Jv_InterpFrame frame_desc (meth, thread);
_Jv_word stack[meth->max_stack];
_Jv_word *sp = stack;
_Jv_word locals[meth->max_locals];
#define INSN_LABEL(op) &&insn_##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, /* Unused. */
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),
#ifdef DIRECT_THREADED
0, // wide
#else
INSN_LABEL(wide),
#endif
INSN_LABEL(multianewarray),
INSN_LABEL(ifnull),
INSN_LABEL(ifnonnull),
INSN_LABEL(goto_w),
INSN_LABEL(jsr_w),
#ifdef DIRECT_THREADED
INSN_LABEL (ldc_class)
#else
0
#endif
};
pc_t pc;
#ifdef DIRECT_THREADED
#define NEXT_INSN goto *((pc++)->insn)
#define INTVAL() ((pc++)->int_val)
#define AVAL() ((pc++)->datum)
#define GET1S() INTVAL ()
#define GET2S() INTVAL ()
#define GET1U() INTVAL ()
#define GET2U() INTVAL ()
#define AVAL1U() AVAL ()
#define AVAL2U() AVAL ()
#define AVAL2UP() AVAL ()
#define SKIP_GOTO ++pc
#define GOTO_VAL() (insn_slot *) pc->datum
#define PCVAL(unionval) unionval.p
#define AMPAMP(label) &&label
// Compile if we must. NOTE: Double-check locking.
if (meth->prepared == NULL)
{
_Jv_MutexLock (&compile_mutex);
if (meth->prepared == NULL)
meth->compile (insn_target);
_Jv_MutexUnlock (&compile_mutex);
}
// If we're only compiling, stop here
if (args == NULL)
return;
pc = (insn_slot *) meth->prepared; #include "interpret-run.cc"
}
#else void
_Jv_InterpMethod::run_debug (void *retp, ffi_raw *args, _Jv_InterpMethod *meth)
{
/* Used to keep track of local variable type
*
* Possible Types:
* o object
* i integer
* f float
* l long
* d double
*/
#define DEBUG
#undef DEBUG_LOCALS_INSN
#define DEBUG_LOCALS_INSN(s, t) do {} while(0)
#define NEXT_INSN goto *(insn_target[*pc++]) #include "interpret-run.cc"
}
#define GET1S() get1s (pc++)
#define GET2S() (pc += 2, get2s (pc- 2))
#define GET1U() get1u (pc++)
#define GET2U() (pc += 2, get2u (pc - 2))
// Note that these could be more efficient when not handling 'ldc
// class'.
#define AVAL1U() \
({ int index = get1u (pc++); \
resolve_pool_entry (meth->defining_class, index).o; })
#define AVAL2U() \
({ int index = get2u (pc); pc += 2; \
resolve_pool_entry (meth->defining_class, index).o; })
// Note that we don't need to resolve the pool entry here as class
// constants are never wide.
#define AVAL2UP() ({ int index = get2u (pc); pc += 2; &pool_data[index]; })
#define SKIP_GOTO pc += 2
#define GOTO_VAL() pc - 1 + get2s (pc)
#define PCVAL(unionval) unionval.i
#define AMPAMP(label) NULL
pc = bytecode ();
#endif /* DIRECT_THREADED */ static void
throw_internal_error (const char *msg)
{
throw new java::lang::InternalError (JvNewStringLatin1 (msg));
}
#define TAKE_GOTO pc = GOTO_VAL () static void
throw_incompatible_class_change_error (jstring msg)
{
throw new java::lang::IncompatibleClassChangeError (msg);
}
/* Go straight at it! the ffi raw format matches the internal static void
stack representation exactly. At least, that's the idea. throw_null_pointer_exception ()
*/ {
memcpy ((void*) locals, (void*) args, meth->args_raw_size); throw new java::lang::NullPointerException;
}
_Jv_word *pool_data = meth->defining_class->constants.data; /* Look up source code line number for given bytecode (or direct threaded
interpreter) PC. */
int
_Jv_InterpMethod::get_source_line(pc_t mpc)
{
int line = line_table_len > 0 ? line_table[0].line : -1;
for (int i = 1; i < line_table_len; i++)
if (line_table[i].pc > mpc)
break;
else
line = line_table[i].line;
/* These three are temporaries for common code used by several return line;
instructions. */ }
void (*fun)();
_Jv_ResolvedMethod* rmeth;
int tmpval;
try /** Do static initialization for fields with a constant initializer */
{ void
// We keep nop around. It is used if we're interpreting the _Jv_InitField (jobject obj, jclass klass, int index)
// bytecodes and not doing direct threading. {
insn_nop: using namespace java::lang::reflect;
NEXT_INSN;
/* The first few instructions here are ordered according to their if (obj != 0 && klass == 0)
frequency, in the hope that this will improve code locality a klass = obj->getClass ();
little. */
insn_aload_0: // 0x2a if (!_Jv_IsInterpretedClass (klass))
LOADA (0); return;
NEXT_INSN;
insn_iload: // 0x15 _Jv_InterpClass *iclass = (_Jv_InterpClass*)klass->aux_info;
LOADI (GET1U ());
NEXT_INSN;
insn_iload_1: // 0x1b _Jv_Field * field = (&klass->fields[0]) + index;
LOADI (1);
NEXT_INSN;
insn_invokevirtual: // 0xb6 if (index > klass->field_count)
{ throw_internal_error ("field out of range");
SAVE_PC();
int index = GET2U ();
/* _Jv_Linker::resolve_pool_entry returns immediately if the int init = iclass->field_initializers[index];
* value already is resolved. If we want to clutter up the if (init == 0)
* code here to gain a little performance, then we can check return;
* the corresponding bit JV_CONSTANT_ResolvedFlag in the tag
* directly. For now, I don't think it is worth it. */
rmeth = (_Jv_Linker::resolve_pool_entry (meth->defining_class, _Jv_Constants *pool = &klass->constants;
index)).rmethod; int tag = pool->tags[init];
sp -= rmeth->stack_item_count; if (! field->isResolved ())
throw_internal_error ("initializing unresolved field");
if (rmeth->method->accflags & Modifier::FINAL) if (obj==0 && ((field->flags & Modifier::STATIC) == 0))
{ throw_internal_error ("initializing non-static field with no object");
// We can't rely on NULLCHECK working if the method is final.
if (! sp[0].o)
throw_null_pointer_exception ();
// Final methods might not appear in the vtable. void *addr = 0;
fun = (void (*)()) rmeth->method->ncode;
}
else
{
NULLCHECK (sp[0].o);
jobject rcv = sp[0].o;
_Jv_VTable *table = *(_Jv_VTable**) rcv;
fun = (void (*)()) table->get_method (rmeth->method->index);
}
#ifdef DIRECT_THREADED if ((field->flags & Modifier::STATIC) != 0)
// Rewrite instruction so that we use a faster pre-resolved addr = (void*) field->u.addr;
// method. else
pc[-2].insn = &&invokevirtual_resolved; addr = (void*) (((char*)obj) + field->u.boffset);
pc[-1].datum = rmeth;
#endif /* DIRECT_THREADED */
}
goto perform_invoke;
#ifdef DIRECT_THREADED switch (tag)
invokevirtual_resolved: {
case JV_CONSTANT_String:
{ {
SAVE_PC(); jstring str;
rmeth = (_Jv_ResolvedMethod *) AVAL (); str = _Jv_NewStringUtf8Const (pool->data[init].utf8);
sp -= rmeth->stack_item_count; pool->data[init].string = str;
pool->tags[init] = JV_CONSTANT_ResolvedString;
if (rmeth->method->accflags & Modifier::FINAL)
{
// We can't rely on NULLCHECK working if the method is final.
if (! sp[0].o)
throw_null_pointer_exception ();
// Final methods might not appear in the vtable.
fun = (void (*)()) rmeth->method->ncode;
}
else
{
jobject rcv = sp[0].o;
_Jv_VTable *table = *(_Jv_VTable**) rcv;
fun = (void (*)()) table->get_method (rmeth->method->index);
}
} }
goto perform_invoke; /* fall through */
#endif /* DIRECT_THREADED */
case JV_CONSTANT_ResolvedString:
if (! (field->type == &java::lang::String::class$
|| field->type == &java::lang::Class::class$))
throw_class_format_error ("string initialiser to non-string field");
perform_invoke: *(jstring*)addr = pool->data[init].string;
break;
case JV_CONSTANT_Integer:
{ {
/* here goes the magic again... */ int value = pool->data[init].i;
ffi_cif *cif = &rmeth->cif;
ffi_raw *raw = (ffi_raw*) sp;
_Jv_value rvalue; if (field->type == JvPrimClass (boolean))
*(jboolean*)addr = (jboolean)value;
else if (field->type == JvPrimClass (byte))
*(jbyte*)addr = (jbyte)value;
else if (field->type == JvPrimClass (char))
*(jchar*)addr = (jchar)value;
#if FFI_NATIVE_RAW_API else if (field->type == JvPrimClass (short))
/* We assume that this is only implemented if it's correct */ *(jshort*)addr = (jshort)value;
/* to use it here. On a 64 bit machine, it never is. */
ffi_raw_call (cif, fun, (void*)&rvalue, raw); else if (field->type == JvPrimClass (int))
#else *(jint*)addr = (jint)value;
ffi_java_raw_call (cif, fun, (void*)&rvalue, raw);
#endif
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 (rvalue.object_value);
}
else if (rtype == FFI_TYPE_SINT32)
{
PUSHI (rvalue.int_value);
}
else if (rtype == FFI_TYPE_VOID)
{
/* skip */
}
else else
{ throw_class_format_error ("erroneous field initializer");
switch (rtype) }
{ break;
case FFI_TYPE_SINT8:
PUSHI ((jbyte)(rvalue.int_value & 0xff));
break;
case FFI_TYPE_SINT16:
PUSHI ((jshort)(rvalue.int_value & 0xffff));
break;
case FFI_TYPE_UINT16: case JV_CONSTANT_Long:
PUSHI (rvalue.int_value & 0xffff); if (field->type != JvPrimClass (long))
break; throw_class_format_error ("erroneous field initializer");
case FFI_TYPE_FLOAT: *(jlong*)addr = _Jv_loadLong (&pool->data[init]);
PUSHF (rvalue.float_value); break;
break;
case FFI_TYPE_DOUBLE: case JV_CONSTANT_Float:
PUSHD (rvalue.double_value); if (field->type != JvPrimClass (float))
break; throw_class_format_error ("erroneous field initializer");
case FFI_TYPE_SINT64: *(jfloat*)addr = pool->data[init].f;
PUSHL (rvalue.long_value); break;
break;
default: case JV_CONSTANT_Double:
throw_internal_error ("unknown return type in invokeXXX"); if (field->type != JvPrimClass (double))
} throw_class_format_error ("erroneous field initializer");
}
}
NEXT_INSN;
insn_aconst_null: *(jdouble*)addr = _Jv_loadDouble (&pool->data[init]);
PUSHA (NULL); break;
NEXT_INSN;
insn_iconst_m1: default:
PUSHI (-1); throw_class_format_error ("erroneous field initializer");
NEXT_INSN; }
}
insn_iconst_0: inline static unsigned char*
PUSHI (0); skip_one_type (unsigned char* ptr)
NEXT_INSN; {
int ch = *ptr++;
insn_iconst_1: while (ch == '[')
PUSHI (1); {
NEXT_INSN; ch = *ptr++;
}
if (ch == 'L')
{
do { ch = *ptr++; } while (ch != ';');
}
insn_iconst_2: return ptr;
PUSHI (2); }
NEXT_INSN;
insn_iconst_3: static ffi_type*
PUSHI (3); get_ffi_type_from_signature (unsigned char* ptr)
NEXT_INSN; {
switch (*ptr)
{
case 'L':
case '[':
return &ffi_type_pointer;
break;
insn_iconst_4: case 'Z':
PUSHI (4); // On some platforms a bool is a byte, on others an int.
NEXT_INSN; if (sizeof (jboolean) == sizeof (jbyte))
return &ffi_type_sint8;
else
{
JvAssert (sizeof (jbyte) == sizeof (jint));
return &ffi_type_sint32;
}
break;
insn_iconst_5: case 'B':
PUSHI (5); return &ffi_type_sint8;
NEXT_INSN; break;
case 'C':
return &ffi_type_uint16;
break;
case 'S':
return &ffi_type_sint16;
break;
case 'I':
return &ffi_type_sint32;
break;
case 'J':
return &ffi_type_sint64;
break;
case 'F':
return &ffi_type_float;
break;
case 'D':
return &ffi_type_double;
break;
insn_lconst_0: case 'V':
PUSHL (0); return &ffi_type_void;
NEXT_INSN; break;
}
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:
// For direct threaded, bipush and sipush are the same.
#ifndef DIRECT_THREADED
PUSHI (GET1S ());
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_sipush:
PUSHI (GET2S ());
NEXT_INSN;
insn_ldc:
// For direct threaded, ldc and ldc_w are the same.
#ifndef DIRECT_THREADED
PUSHA ((jobject) AVAL1U ());
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_ldc_w:
PUSHA ((jobject) AVAL2U ());
NEXT_INSN;
#ifdef DIRECT_THREADED
// For direct threaded we have a separate 'ldc class' operation.
insn_ldc_class:
{
SAVE_PC();
// We could rewrite the instruction at this point.
int index = INTVAL ();
jobject k = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).o;
PUSHA (k);
}
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_ldc2_w:
{
void *where = AVAL2UP ();
memcpy (sp, where, 2*sizeof (_Jv_word));
sp += 2;
}
NEXT_INSN;
insn_lload:
LOADL (GET1U ());
NEXT_INSN;
insn_fload:
LOADF (GET1U ());
NEXT_INSN;
insn_dload:
LOADD (GET1U ());
NEXT_INSN;
insn_aload:
LOADA (GET1U ());
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:
{
jint index = POPI();
jintArray arr = (jintArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
PUSHI( elements(arr)[index] );
}
NEXT_INSN;
insn_laload:
{
jint index = POPI();
jlongArray arr = (jlongArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
PUSHL( elements(arr)[index] );
}
NEXT_INSN;
insn_faload:
{
jint index = POPI();
jfloatArray arr = (jfloatArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
PUSHF( elements(arr)[index] );
}
NEXT_INSN;
insn_daload:
{
jint index = POPI();
jdoubleArray arr = (jdoubleArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
PUSHD( elements(arr)[index] );
}
NEXT_INSN;
insn_aaload:
{
jint index = POPI();
jobjectArray arr = (jobjectArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
PUSHA( elements(arr)[index] );
}
NEXT_INSN;
insn_baload:
{
jint index = POPI();
jbyteArray arr = (jbyteArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
PUSHI( elements(arr)[index] );
}
NEXT_INSN;
insn_caload:
{
jint index = POPI();
jcharArray arr = (jcharArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
PUSHI( elements(arr)[index] );
}
NEXT_INSN;
insn_saload:
{
jint index = POPI();
jshortArray arr = (jshortArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
PUSHI( elements(arr)[index] );
}
NEXT_INSN;
insn_istore:
STOREI (GET1U ());
NEXT_INSN;
insn_lstore:
STOREL (GET1U ());
NEXT_INSN;
insn_fstore:
STOREF (GET1U ());
NEXT_INSN;
insn_dstore:
STORED (GET1U ());
NEXT_INSN;
insn_astore:
STOREA (GET1U ());
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:
{
jint value = POPI();
jint index = POPI();
jintArray arr = (jintArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
elements(arr)[index] = value;
}
NEXT_INSN;
insn_lastore:
{
jlong value = POPL();
jint index = POPI();
jlongArray arr = (jlongArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
elements(arr)[index] = value;
}
NEXT_INSN;
insn_fastore:
{
jfloat value = POPF();
jint index = POPI();
jfloatArray arr = (jfloatArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
elements(arr)[index] = value;
}
NEXT_INSN;
insn_dastore:
{
jdouble value = POPD();
jint index = POPI();
jdoubleArray arr = (jdoubleArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
elements(arr)[index] = value;
}
NEXT_INSN;
insn_aastore:
{
jobject value = POPA();
jint index = POPI();
jobjectArray arr = (jobjectArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
_Jv_CheckArrayStore (arr, value);
elements(arr)[index] = value;
}
NEXT_INSN;
insn_bastore:
{
jbyte value = (jbyte) POPI();
jint index = POPI();
jbyteArray arr = (jbyteArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
elements(arr)[index] = value;
}
NEXT_INSN;
insn_castore:
{
jchar value = (jchar) POPI();
jint index = POPI();
jcharArray arr = (jcharArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, index);
elements(arr)[index] = value;
}
NEXT_INSN;
insn_sastore:
{
jshort value = (jshort) POPI();
jint index = POPI();
jshortArray arr = (jshortArray) POPA();
NULLARRAYCHECK (arr);
ARRAYBOUNDSCHECK (arr, 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();
jint res = _Jv_divI (value1, value2);
PUSHI (res);
}
NEXT_INSN;
insn_ldiv:
{
SAVE_PC();
jlong value2 = POPL();
jlong value1 = POPL();
jlong res = _Jv_divJ (value1, value2);
PUSHL (res);
}
NEXT_INSN;
insn_fdiv:
{
jfloat value2 = POPF();
jfloat value1 = POPF();
jfloat res = value1 / value2;
PUSHF (res);
}
NEXT_INSN;
insn_ddiv:
{
jdouble value2 = POPD();
jdouble value1 = POPD();
jdouble res = value1 / value2;
PUSHD (res);
}
NEXT_INSN;
insn_irem:
{
SAVE_PC();
jint value2 = POPI();
jint value1 = POPI();
jint res = _Jv_remI (value1, value2);
PUSHI (res);
}
NEXT_INSN;
insn_lrem:
{
SAVE_PC();
jlong value2 = POPL();
jlong value1 = POPL();
jlong res = _Jv_remJ (value1, value2);
PUSHL (res);
}
NEXT_INSN;
insn_frem:
{
jfloat value2 = POPF();
jfloat value1 = POPF();
jfloat res = __ieee754_fmod (value1, value2);
PUSHF (res);
}
NEXT_INSN;
insn_drem:
{
jdouble value2 = POPD();
jdouble value1 = POPD();
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);
_Jv_uint value = (_Jv_uint) POPI();
PUSHI ((jint) (value >> shift));
}
NEXT_INSN;
insn_lushr:
{
jint shift = (POPI() & 0x3f);
_Jv_ulong value = (_Jv_ulong) POPL();
PUSHL ((jlong) (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 ();
jint amount = GET1S ();
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:
{
using namespace java::lang;
jint value = convert (POPF (), Integer::MIN_VALUE, Integer::MAX_VALUE);
PUSHI(value);
}
NEXT_INSN;
insn_f2l:
{
using namespace java::lang;
jlong value = convert (POPF (), Long::MIN_VALUE, Long::MAX_VALUE);
PUSHL(value);
}
NEXT_INSN;
insn_f2d:
{ jdouble value = POPF (); PUSHD(value); }
NEXT_INSN;
insn_d2i:
{
using namespace java::lang;
jint value = convert (POPD (), Integer::MIN_VALUE, Integer::MAX_VALUE);
PUSHI(value);
}
NEXT_INSN;
insn_d2l:
{
using namespace java::lang;
jlong value = convert (POPD (), Long::MIN_VALUE, Long::MAX_VALUE);
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:
tmpval = -1;
goto fcmp;
insn_fcmpg:
tmpval = 1;
fcmp:
{
jfloat value2 = POPF ();
jfloat value1 = POPF ();
if (value1 > value2)
PUSHI (1);
else if (value1 == value2)
PUSHI (0);
else if (value1 < value2)
PUSHI (-1);
else
PUSHI (tmpval);
}
NEXT_INSN;
insn_dcmpl:
tmpval = -1;
goto dcmp;
insn_dcmpg:
tmpval = 1;
dcmp:
{
jdouble value2 = POPD ();
jdouble value1 = POPD ();
if (value1 > value2)
PUSHI (1);
else if (value1 == value2)
PUSHI (0);
else if (value1 < value2)
PUSHI (-1);
else
PUSHI (tmpval);
}
NEXT_INSN;
insn_ifeq:
{
if (POPI() == 0)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_ifne:
{
if (POPI() != 0)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_iflt:
{
if (POPI() < 0)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_ifge:
{
if (POPI() >= 0)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_ifgt:
{
if (POPI() > 0)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_ifle:
{
if (POPI() <= 0)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_if_icmpeq:
{
jint value2 = POPI();
jint value1 = POPI();
if (value1 == value2)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_if_icmpne:
{
jint value2 = POPI();
jint value1 = POPI();
if (value1 != value2)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_if_icmplt:
{
jint value2 = POPI();
jint value1 = POPI();
if (value1 < value2)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_if_icmpge:
{
jint value2 = POPI();
jint value1 = POPI();
if (value1 >= value2)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_if_icmpgt:
{
jint value2 = POPI();
jint value1 = POPI();
if (value1 > value2)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_if_icmple:
{
jint value2 = POPI();
jint value1 = POPI();
if (value1 <= value2)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_if_acmpeq:
{
jobject value2 = POPA();
jobject value1 = POPA();
if (value1 == value2)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_if_acmpne:
{
jobject value2 = POPA();
jobject value1 = POPA();
if (value1 != value2)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_goto_w:
#ifndef DIRECT_THREADED
// For direct threaded, goto and goto_w are the same.
pc = pc - 1 + get4 (pc);
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_goto:
TAKE_GOTO;
NEXT_INSN;
insn_jsr_w:
#ifndef DIRECT_THREADED
// For direct threaded, jsr and jsr_w are the same.
{
pc_t next = pc - 1 + get4 (pc);
pc += 4;
PUSHA ((jobject) pc);
pc = next;
}
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_jsr:
{
pc_t next = GOTO_VAL();
SKIP_GOTO;
PUSHA ((jobject) pc);
pc = next;
}
NEXT_INSN;
insn_ret:
{
jint index = GET1U ();
pc = (pc_t) PEEKA (index);
}
NEXT_INSN;
insn_tableswitch:
{
#ifdef DIRECT_THREADED
void *def = (pc++)->datum;
int index = POPI();
jint low = INTVAL ();
jint high = INTVAL ();
if (index < low || index > high)
pc = (insn_slot *) def;
else
pc = (insn_slot *) ((pc + index - low)->datum);
#else
pc_t base_pc = pc - 1;
int index = POPI ();
pc_t base = (pc_t) 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));
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
insn_lookupswitch:
{
#ifdef DIRECT_THREADED
void *def = (pc++)->insn;
int index = POPI();
jint npairs = INTVAL ();
int max = npairs - 1;
int min = 0;
// Simple binary search...
while (min < max)
{
int half = (min + max) / 2;
int match = pc[2 * half].int_val;
if (index == match)
{
// Found it.
pc = (insn_slot *) pc[2 * half + 1].datum;
NEXT_INSN;
}
else if (index < match)
// We can use HALF - 1 here because we check again on
// loop exit.
max = half - 1;
else
// We can use HALF + 1 here because we check again on
// loop exit.
min = half + 1;
}
if (index == pc[2 * min].int_val)
pc = (insn_slot *) pc[2 * min + 1].datum;
else
pc = (insn_slot *) def;
#else
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)
// We can use HALF - 1 here because we check again on
// loop exit.
max = half - 1;
else
// We can use HALF + 1 here because we check again on
// loop exit.
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;
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
insn_areturn:
*(jobject *) retp = POPA ();
return;
insn_lreturn:
*(jlong *) retp = POPL ();
return;
insn_freturn:
*(jfloat *) retp = POPF ();
return;
insn_dreturn:
*(jdouble *) retp = POPD ();
return;
insn_ireturn:
*(jint *) retp = POPI ();
return;
insn_return:
return;
insn_getstatic:
{
jint fieldref_index = GET2U ();
SAVE_PC(); // Constant pool resolution could throw.
_Jv_Linker::resolve_pool_entry (meth->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;
// We rewrite the instruction once we discover what it refers
// to.
void *newinsn = NULL;
if (type->isPrimitive ())
{
switch (type->size_in_bytes)
{
case 1:
PUSHI (*field->u.byte_addr);
newinsn = AMPAMP (getstatic_resolved_1);
break;
case 2:
if (type == JvPrimClass (char))
{
PUSHI (*field->u.char_addr);
newinsn = AMPAMP (getstatic_resolved_char);
}
else
{
PUSHI (*field->u.short_addr);
newinsn = AMPAMP (getstatic_resolved_short);
}
break;
case 4:
PUSHI(*field->u.int_addr);
newinsn = AMPAMP (getstatic_resolved_4);
break;
case 8:
PUSHL(*field->u.long_addr);
newinsn = AMPAMP (getstatic_resolved_8);
break;
}
}
else
{
PUSHA(*field->u.object_addr);
newinsn = AMPAMP (getstatic_resolved_obj);
}
#ifdef DIRECT_THREADED
pc[-2].insn = newinsn;
pc[-1].datum = field->u.addr;
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
#ifdef DIRECT_THREADED
getstatic_resolved_1:
PUSHI (*(jbyte *) AVAL ());
NEXT_INSN;
getstatic_resolved_char:
PUSHI (*(jchar *) AVAL ());
NEXT_INSN;
getstatic_resolved_short:
PUSHI (*(jshort *) AVAL ());
NEXT_INSN;
getstatic_resolved_4:
PUSHI (*(jint *) AVAL ());
NEXT_INSN;
getstatic_resolved_8:
PUSHL (*(jlong *) AVAL ());
NEXT_INSN;
getstatic_resolved_obj:
PUSHA (*(jobject *) AVAL ());
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_getfield:
{
SAVE_PC();
jint fieldref_index = GET2U ();
_Jv_Linker::resolve_pool_entry (meth->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;
jint field_offset = field->u.boffset;
jobject obj = POPA();
NULLCHECK(obj);
void *newinsn = NULL;
_Jv_value *val = (_Jv_value *) ((char *)obj + field_offset);
if (type->isPrimitive ())
{
switch (type->size_in_bytes)
{
case 1:
PUSHI (val->byte_value);
newinsn = AMPAMP (getfield_resolved_1);
break;
case 2:
if (type == JvPrimClass (char))
{
PUSHI (val->char_value);
newinsn = AMPAMP (getfield_resolved_char);
}
else
{
PUSHI (val->short_value);
newinsn = AMPAMP (getfield_resolved_short);
}
break;
case 4:
PUSHI (val->int_value);
newinsn = AMPAMP (getfield_resolved_4);
break;
case 8:
PUSHL (val->long_value);
newinsn = AMPAMP (getfield_resolved_8);
break;
}
}
else
{
PUSHA (val->object_value);
newinsn = AMPAMP (getfield_resolved_obj);
}
#ifdef DIRECT_THREADED
pc[-2].insn = newinsn;
pc[-1].int_val = field_offset;
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
#ifdef DIRECT_THREADED
getfield_resolved_1:
{
char *obj = (char *) POPA ();
NULLCHECK (obj);
PUSHI (*(jbyte *) (obj + INTVAL ()));
}
NEXT_INSN;
getfield_resolved_char:
{
char *obj = (char *) POPA ();
NULLCHECK (obj);
PUSHI (*(jchar *) (obj + INTVAL ()));
}
NEXT_INSN;
getfield_resolved_short:
{
char *obj = (char *) POPA ();
NULLCHECK (obj);
PUSHI (*(jshort *) (obj + INTVAL ()));
}
NEXT_INSN;
getfield_resolved_4:
{
char *obj = (char *) POPA ();
NULLCHECK (obj);
PUSHI (*(jint *) (obj + INTVAL ()));
}
NEXT_INSN;
getfield_resolved_8:
{
char *obj = (char *) POPA ();
NULLCHECK (obj);
PUSHL (*(jlong *) (obj + INTVAL ()));
}
NEXT_INSN;
getfield_resolved_obj:
{
char *obj = (char *) POPA ();
NULLCHECK (obj);
PUSHA (*(jobject *) (obj + INTVAL ()));
}
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_putstatic:
{
SAVE_PC();
jint fieldref_index = GET2U ();
_Jv_Linker::resolve_pool_entry (meth->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"));
void *newinsn = NULL;
if (type->isPrimitive ())
{
switch (type->size_in_bytes)
{
case 1:
{
jint value = POPI();
*field->u.byte_addr = value;
newinsn = AMPAMP (putstatic_resolved_1);
break;
}
case 2:
{
jint value = POPI();
*field->u.char_addr = value;
newinsn = AMPAMP (putstatic_resolved_2);
break;
}
case 4:
{
jint value = POPI();
*field->u.int_addr = value;
newinsn = AMPAMP (putstatic_resolved_4);
break;
}
case 8:
{
jlong value = POPL();
*field->u.long_addr = value;
newinsn = AMPAMP (putstatic_resolved_8);
break;
}
}
}
else
{
jobject value = POPA();
*field->u.object_addr = value;
newinsn = AMPAMP (putstatic_resolved_obj);
}
#ifdef DIRECT_THREADED
pc[-2].insn = newinsn;
pc[-1].datum = field->u.addr;
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
#ifdef DIRECT_THREADED
putstatic_resolved_1:
*(jbyte *) AVAL () = POPI ();
NEXT_INSN;
putstatic_resolved_2:
*(jchar *) AVAL () = POPI ();
NEXT_INSN;
putstatic_resolved_4:
*(jint *) AVAL () = POPI ();
NEXT_INSN;
putstatic_resolved_8:
*(jlong *) AVAL () = POPL ();
NEXT_INSN;
putstatic_resolved_obj:
*(jobject *) AVAL () = POPA ();
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_putfield:
{
SAVE_PC();
jint fieldref_index = GET2U ();
_Jv_Linker::resolve_pool_entry (meth->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"));
jint field_offset = field->u.boffset;
void *newinsn = NULL;
if (type->isPrimitive ())
{
switch (type->size_in_bytes)
{
case 1:
{
jint value = POPI();
jobject obj = POPA();
NULLCHECK(obj);
*(jbyte*) ((char*)obj + field_offset) = value;
newinsn = AMPAMP (putfield_resolved_1);
break;
}
case 2:
{
jint value = POPI();
jobject obj = POPA();
NULLCHECK(obj);
*(jchar*) ((char*)obj + field_offset) = value;
newinsn = AMPAMP (putfield_resolved_2);
break;
}
case 4:
{
jint value = POPI();
jobject obj = POPA();
NULLCHECK(obj);
*(jint*) ((char*)obj + field_offset) = value;
newinsn = AMPAMP (putfield_resolved_4);
break;
}
case 8:
{
jlong value = POPL();
jobject obj = POPA();
NULLCHECK(obj);
*(jlong*) ((char*)obj + field_offset) = value;
newinsn = AMPAMP (putfield_resolved_8);
break;
}
}
}
else
{
jobject value = POPA();
jobject obj = POPA();
NULLCHECK(obj);
*(jobject*) ((char*)obj + field_offset) = value;
newinsn = AMPAMP (putfield_resolved_obj);
}
#ifdef DIRECT_THREADED
pc[-2].insn = newinsn;
pc[-1].int_val = field_offset;
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
#ifdef DIRECT_THREADED
putfield_resolved_1:
{
jint val = POPI ();
char *obj = (char *) POPA ();
NULLCHECK (obj);
*(jbyte *) (obj + INTVAL ()) = val;
}
NEXT_INSN;
putfield_resolved_2:
{
jint val = POPI ();
char *obj = (char *) POPA ();
NULLCHECK (obj);
*(jchar *) (obj + INTVAL ()) = val;
}
NEXT_INSN;
putfield_resolved_4:
{
jint val = POPI ();
char *obj = (char *) POPA ();
NULLCHECK (obj);
*(jint *) (obj + INTVAL ()) = val;
}
NEXT_INSN;
putfield_resolved_8:
{
jlong val = POPL ();
char *obj = (char *) POPA ();
NULLCHECK (obj);
*(jlong *) (obj + INTVAL ()) = val;
}
NEXT_INSN;
putfield_resolved_obj:
{
jobject val = POPA ();
char *obj = (char *) POPA ();
NULLCHECK (obj);
*(jobject *) (obj + INTVAL ()) = val;
}
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_invokespecial:
{
SAVE_PC();
int index = GET2U ();
rmeth = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).rmethod;
sp -= rmeth->stack_item_count;
// We don't use NULLCHECK here because we can't rely on that
// working for <init>. So instead we do an explicit test.
if (! sp[0].o)
{
SAVE_PC();
throw_null_pointer_exception ();
}
fun = (void (*)()) rmeth->method->ncode;
#ifdef DIRECT_THREADED
// Rewrite instruction so that we use a faster pre-resolved
// method.
pc[-2].insn = &&invokespecial_resolved;
pc[-1].datum = rmeth;
#endif /* DIRECT_THREADED */
}
goto perform_invoke;
#ifdef DIRECT_THREADED
invokespecial_resolved:
{
SAVE_PC();
rmeth = (_Jv_ResolvedMethod *) AVAL ();
sp -= rmeth->stack_item_count;
// We don't use NULLCHECK here because we can't rely on that
// working for <init>. So instead we do an explicit test.
if (! sp[0].o)
{
throw_null_pointer_exception ();
}
fun = (void (*)()) rmeth->method->ncode;
}
goto perform_invoke;
#endif /* DIRECT_THREADED */
insn_invokestatic:
{
SAVE_PC();
int index = GET2U ();
rmeth = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).rmethod;
sp -= rmeth->stack_item_count;
fun = (void (*)()) rmeth->method->ncode;
#ifdef DIRECT_THREADED
// Rewrite instruction so that we use a faster pre-resolved
// method.
pc[-2].insn = &&invokestatic_resolved;
pc[-1].datum = rmeth;
#endif /* DIRECT_THREADED */
}
goto perform_invoke;
#ifdef DIRECT_THREADED
invokestatic_resolved:
{
SAVE_PC();
rmeth = (_Jv_ResolvedMethod *) AVAL ();
sp -= rmeth->stack_item_count;
fun = (void (*)()) rmeth->method->ncode;
}
goto perform_invoke;
#endif /* DIRECT_THREADED */
insn_invokeinterface:
{
SAVE_PC();
int index = GET2U ();
rmeth = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).rmethod;
sp -= rmeth->stack_item_count;
jobject rcv = sp[0].o;
NULLCHECK (rcv);
fun = (void (*)())
_Jv_LookupInterfaceMethod (rcv->getClass (),
rmeth->method->name,
rmeth->method->signature);
#ifdef DIRECT_THREADED
// Rewrite instruction so that we use a faster pre-resolved
// method.
pc[-2].insn = &&invokeinterface_resolved;
pc[-1].datum = rmeth;
#else
// Skip dummy bytes.
pc += 2;
#endif /* DIRECT_THREADED */
}
goto perform_invoke;
#ifdef DIRECT_THREADED
invokeinterface_resolved:
{
SAVE_PC();
rmeth = (_Jv_ResolvedMethod *) AVAL ();
sp -= rmeth->stack_item_count;
jobject rcv = sp[0].o;
NULLCHECK (rcv);
fun = (void (*)())
_Jv_LookupInterfaceMethod (rcv->getClass (),
rmeth->method->name,
rmeth->method->signature);
}
goto perform_invoke;
#endif /* DIRECT_THREADED */
insn_new:
{
SAVE_PC();
int index = GET2U ();
jclass klass = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).clazz;
/* VM spec, section 3.11.5 */
if ((klass->getModifiers() & Modifier::ABSTRACT)
|| klass->isInterface())
throw new java::lang::InstantiationException;
jobject res = _Jv_AllocObject (klass);
PUSHA (res);
#ifdef DIRECT_THREADED
pc[-2].insn = &&new_resolved;
pc[-1].datum = klass;
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
#ifdef DIRECT_THREADED
new_resolved:
{
jclass klass = (jclass) AVAL ();
jobject res = _Jv_AllocObject (klass);
PUSHA (res);
}
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_newarray:
{
int atype = GET1U ();
int size = POPI();
jobject result = _Jv_NewArray (atype, size);
PUSHA (result);
}
NEXT_INSN;
insn_anewarray:
{
SAVE_PC();
int index = GET2U ();
jclass klass = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).clazz;
int size = POPI();
jobject result = _Jv_NewObjectArray (size, klass, 0);
PUSHA (result);
#ifdef DIRECT_THREADED
pc[-2].insn = &&anewarray_resolved;
pc[-1].datum = klass;
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
#ifdef DIRECT_THREADED
anewarray_resolved:
{
jclass klass = (jclass) AVAL ();
int size = POPI ();
jobject result = _Jv_NewObjectArray (size, klass, 0);
PUSHA (result);
}
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_arraylength:
{
__JArray *arr = (__JArray*)POPA();
NULLARRAYCHECK (arr);
PUSHI (arr->length);
}
NEXT_INSN;
insn_athrow:
{
jobject value = POPA();
throw static_cast<jthrowable>(value);
}
NEXT_INSN;
insn_checkcast:
{
SAVE_PC();
jobject value = POPA();
jint index = GET2U ();
jclass to = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).clazz;
value = (jobject) _Jv_CheckCast (to, value);
PUSHA (value);
#ifdef DIRECT_THREADED
pc[-2].insn = &&checkcast_resolved;
pc[-1].datum = to;
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
#ifdef DIRECT_THREADED
checkcast_resolved:
{
SAVE_PC();
jobject value = POPA ();
jclass to = (jclass) AVAL ();
value = (jobject) _Jv_CheckCast (to, value);
PUSHA (value);
}
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_instanceof:
{
SAVE_PC();
jobject value = POPA();
jint index = GET2U ();
jclass to = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).clazz;
PUSHI (to->isInstance (value));
#ifdef DIRECT_THREADED
pc[-2].insn = &&instanceof_resolved;
pc[-1].datum = to;
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
#ifdef DIRECT_THREADED
instanceof_resolved:
{
jobject value = POPA ();
jclass to = (jclass) AVAL ();
PUSHI (to->isInstance (value));
}
NEXT_INSN;
#endif /* DIRECT_THREADED */
insn_monitorenter:
{
jobject value = POPA();
NULLCHECK(value);
_Jv_MonitorEnter (value);
}
NEXT_INSN;
insn_monitorexit:
{
jobject value = POPA();
NULLCHECK(value);
_Jv_MonitorExit (value);
}
NEXT_INSN;
insn_ifnull:
{
jobject val = POPA();
if (val == NULL)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_ifnonnull:
{
jobject val = POPA();
if (val != NULL)
TAKE_GOTO;
else
SKIP_GOTO;
}
NEXT_INSN;
insn_multianewarray:
{
SAVE_PC();
int kind_index = GET2U ();
int dim = GET1U ();
jclass type
= (_Jv_Linker::resolve_pool_entry (meth->defining_class,
kind_index)).clazz;
jint *sizes = (jint*) __builtin_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;
#ifndef DIRECT_THREADED
insn_wide:
{
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_fload:
LOADF (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");
}
}
#endif /* DIRECT_THREADED */
}
catch (java::lang::Throwable *ex)
{
#ifdef DIRECT_THREADED
void *logical_pc = (void *) ((insn_slot *) pc - 1);
#else
int logical_pc = pc - 1 - bytecode ();
#endif
_Jv_InterpException *exc = meth->exceptions ();
jclass exc_class = ex->getClass ();
for (int i = 0; i < meth->exc_count; i++)
{
if (PCVAL (exc[i].start_pc) <= logical_pc
&& logical_pc < PCVAL (exc[i].end_pc))
{
#ifdef DIRECT_THREADED
jclass handler = (jclass) exc[i].handler_type.p;
#else
jclass handler = NULL;
if (exc[i].handler_type.i != 0)
handler = (_Jv_Linker::resolve_pool_entry (defining_class,
exc[i].handler_type.i)).clazz;
#endif /* DIRECT_THREADED */
if (handler == NULL || handler->isAssignableFrom (exc_class))
{
#ifdef DIRECT_THREADED
pc = (insn_slot *) exc[i].handler_pc.p;
#else
pc = bytecode () + exc[i].handler_pc.i;
#endif /* DIRECT_THREADED */
sp = stack;
sp++->o = ex; // Push exception.
NEXT_INSN;
}
}
}
// No handler, so re-throw.
throw ex;
}
}
static void
throw_internal_error (const char *msg)
{
throw new java::lang::InternalError (JvNewStringLatin1 (msg));
}
static void
throw_incompatible_class_change_error (jstring msg)
{
throw new java::lang::IncompatibleClassChangeError (msg);
}
static void
throw_null_pointer_exception ()
{
throw new java::lang::NullPointerException;
}
/* Look up source code line number for given bytecode (or direct threaded
interpreter) PC. */
int
_Jv_InterpMethod::get_source_line(pc_t mpc)
{
int line = line_table_len > 0 ? line_table[0].line : -1;
for (int i = 1; i < line_table_len; i++)
if (line_table[i].pc > mpc)
break;
else
line = line_table[i].line;
return line;
}
/** Do static initialization for fields with a constant initializer */
void
_Jv_InitField (jobject obj, jclass klass, int index)
{
using namespace java::lang::reflect;
if (obj != 0 && klass == 0)
klass = obj->getClass ();
if (!_Jv_IsInterpretedClass (klass))
return;
_Jv_InterpClass *iclass = (_Jv_InterpClass*)klass->aux_info;
_Jv_Field * field = (&klass->fields[0]) + index;
if (index > klass->field_count)
throw_internal_error ("field out of range");
int init = iclass->field_initializers[index];
if (init == 0)
return;
_Jv_Constants *pool = &klass->constants;
int tag = pool->tags[init];
if (! field->isResolved ())
throw_internal_error ("initializing unresolved field");
if (obj==0 && ((field->flags & Modifier::STATIC) == 0))
throw_internal_error ("initializing non-static field with no object");
void *addr = 0;
if ((field->flags & Modifier::STATIC) != 0)
addr = (void*) field->u.addr;
else
addr = (void*) (((char*)obj) + field->u.boffset);
switch (tag)
{
case JV_CONSTANT_String:
{
jstring str;
str = _Jv_NewStringUtf8Const (pool->data[init].utf8);
pool->data[init].string = str;
pool->tags[init] = JV_CONSTANT_ResolvedString;
}
/* fall through */
case JV_CONSTANT_ResolvedString:
if (! (field->type == &java::lang::String::class$
|| field->type == &java::lang::Class::class$))
throw_class_format_error ("string initialiser to non-string field");
*(jstring*)addr = pool->data[init].string;
break;
case JV_CONSTANT_Integer:
{
int value = pool->data[init].i;
if (field->type == JvPrimClass (boolean))
*(jboolean*)addr = (jboolean)value;
else if (field->type == JvPrimClass (byte))
*(jbyte*)addr = (jbyte)value;
else if (field->type == JvPrimClass (char))
*(jchar*)addr = (jchar)value;
else if (field->type == JvPrimClass (short))
*(jshort*)addr = (jshort)value;
else if (field->type == JvPrimClass (int))
*(jint*)addr = (jint)value;
else
throw_class_format_error ("erroneous field initializer");
}
break;
case JV_CONSTANT_Long:
if (field->type != JvPrimClass (long))
throw_class_format_error ("erroneous field initializer");
*(jlong*)addr = _Jv_loadLong (&pool->data[init]);
break;
case JV_CONSTANT_Float:
if (field->type != JvPrimClass (float))
throw_class_format_error ("erroneous field initializer");
*(jfloat*)addr = pool->data[init].f;
break;
case JV_CONSTANT_Double:
if (field->type != JvPrimClass (double))
throw_class_format_error ("erroneous field initializer");
*(jdouble*)addr = _Jv_loadDouble (&pool->data[init]);
break;
default:
throw_class_format_error ("erroneous field initializer");
}
}
inline static unsigned char*
skip_one_type (unsigned char* ptr)
{
int ch = *ptr++;
while (ch == '[')
{
ch = *ptr++;
}
if (ch == 'L')
{
do { ch = *ptr++; } while (ch != ';');
}
return ptr;
}
static ffi_type*
get_ffi_type_from_signature (unsigned char* ptr)
{
switch (*ptr)
{
case 'L':
case '[':
return &ffi_type_pointer;
break;
case 'Z':
// On some platforms a bool is a byte, on others an int.
if (sizeof (jboolean) == sizeof (jbyte))
return &ffi_type_sint8;
else
{
JvAssert (sizeof (jbyte) == sizeof (jint));
return &ffi_type_sint32;
}
break;
case 'B':
return &ffi_type_sint8;
break;
case 'C':
return &ffi_type_uint16;
break;
case 'S':
return &ffi_type_sint16;
break;
case 'I':
return &ffi_type_sint32;
break;
case 'J':
return &ffi_type_sint64;
break;
case 'F':
return &ffi_type_float;
break;
case 'D':
return &ffi_type_double;
break;
case 'V':
return &ffi_type_void;
break;
}
throw_internal_error ("unknown type in signature"); throw_internal_error ("unknown type in signature");
} }
...@@ -3654,16 +1266,36 @@ _Jv_InterpMethod::ncode () ...@@ -3654,16 +1266,36 @@ _Jv_InterpMethod::ncode ()
if ((self->accflags & Modifier::SYNCHRONIZED) != 0) if ((self->accflags & Modifier::SYNCHRONIZED) != 0)
{ {
if (staticp) if (staticp)
fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class; {
if (::gnu::classpath::jdwp::Jdwp::isDebugging)
fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class_debug;
else
fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class;
}
else else
fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object; {
if (::gnu::classpath::jdwp::Jdwp::isDebugging)
fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object_debug;
else
fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object;
}
} }
else else
{ {
if (staticp) if (staticp)
fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class; {
if (::gnu::classpath::jdwp::Jdwp::isDebugging)
fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class_debug;
else
fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class;
}
else else
fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal; {
if (::gnu::classpath::jdwp::Jdwp::isDebugging)
fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal_debug;
else
fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal;
}
} }
FFI_PREP_RAW_CLOSURE (&closure->closure, FFI_PREP_RAW_CLOSURE (&closure->closure,
......
...@@ -24,6 +24,7 @@ details. */ ...@@ -24,6 +24,7 @@ details. */
#include <java/security/AccessController.h> #include <java/security/AccessController.h>
#include <java/util/ArrayList.h> #include <java/util/ArrayList.h>
#include <java/util/IdentityHashMap.h> #include <java/util/IdentityHashMap.h>
#include <gnu/classpath/jdwp/Jdwp.h>
#include <gnu/java/lang/MainThread.h> #include <gnu/java/lang/MainThread.h>
#include <gnu/gcj/runtime/NameFinder.h> #include <gnu/gcj/runtime/NameFinder.h>
#include <gnu/gcj/runtime/StringBuffer.h> #include <gnu/gcj/runtime/StringBuffer.h>
...@@ -113,7 +114,13 @@ _Jv_StackTrace::UnwindTraceFn (struct _Unwind_Context *context, void *state_ptr) ...@@ -113,7 +114,13 @@ _Jv_StackTrace::UnwindTraceFn (struct _Unwind_Context *context, void *state_ptr)
// correspondance between call frames in the interpreted stack and occurances // correspondance between call frames in the interpreted stack and occurances
// of _Jv_InterpMethod::run() on the native stack. // of _Jv_InterpMethod::run() on the native stack.
#ifdef INTERPRETER #ifdef INTERPRETER
void *interp_run = (void *) &_Jv_InterpMethod::run; void *interp_run = NULL;
if (::gnu::classpath::jdwp::Jdwp::isDebugging)
interp_run = (void *) &_Jv_InterpMethod::run_debug;
else
interp_run = (void *) &_Jv_InterpMethod::run;
if (func_addr == UNWRAP_FUNCTION_DESCRIPTOR (interp_run)) if (func_addr == UNWRAP_FUNCTION_DESCRIPTOR (interp_run))
{ {
state->frames[pos].type = frame_interpreter; state->frames[pos].type = frame_interpreter;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment