// interpret.cc - Code for the interpreter
-/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation
+/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation
This file is part of libgcj.
#include <execution.h>
#include <java/lang/reflect/Modifier.h>
+#include <jvmti.h>
+#include "jvmti-int.h"
+
#include <gnu/classpath/jdwp/Jdwp.h>
+#include <gnu/gcj/jvmti/Breakpoint.h>
+#include <gnu/gcj/jvmti/BreakpointManager.h>
+#include <gnu/gcj/jvmti/ExceptionEvent.h>
#ifdef INTERPRETER
void _Jv_InitInterpreter() {}
#endif
+// The breakpoint instruction. For the direct threaded case,
+// _Jv_InterpMethod::compile will initialize breakpoint_insn
+// the first time it is called.
+#ifdef DIRECT_THREADED
+insn_slot _Jv_InterpMethod::bp_insn_slot;
+pc_t _Jv_InterpMethod::breakpoint_insn = NULL;
+#else
+unsigned char _Jv_InterpMethod::bp_insn_opcode
+ = static_cast<unsigned char> (op_breakpoint);
+pc_t _Jv_InterpMethod::breakpoint_insn = &_Jv_InterpMethod::bp_insn_opcode;
+#endif
+
extern "C" double __ieee754_fmod (double,double);
static inline void dupx (_Jv_word *sp, int n, int x)
# define LOADD(I) LOADL(I)
#endif
-#define STOREA(I) \
-do { \
-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)
+#define STOREA(I) \
+ do { \
+ 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
-# define STOREL(I) \
-do { \
-DEBUG_LOCALS_INSN (I, 'l'); \
-(sp -= 2, locals[I].l = sp->l); \
-} while(0)
+# define STOREL(I) \
+ 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)
+ do { \
+ DEBUG_LOCALS_INSN (I, 'd'); \
+ (sp -= 2, locals[I].d = sp->d); \
+ } while (0)
#else
-# define STOREL(I) \
-do { DEBUG_LOCALS_INSN(I, 'l'); \
- jint __idx = (I); \
- locals[__idx+1].ia[0] = (--sp)->ia[0]; \
- 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)
+# define STOREL(I) \
+ do { \
+ DEBUG_LOCALS_INSN (I, 'l'); \
+ jint __idx = (I); \
+ locals[__idx+1].ia[0] = (--sp)->ia[0]; \
+ 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
#define PEEKI(I) (locals+(I))->i
#define PEEKA(I) (locals+(I))->o
-#define POKEI(I,V) \
-DEBUG_LOCALS_INSN(I,'i'); \
-((locals+(I))->i = (V))
+#define POKEI(I,V) \
+ DEBUG_LOCALS_INSN(I,'i'); \
+ ((locals+(I))->i = (V))
#define BINOPI(OP) { \
PUSHD(value1 OP value2); \
}
-static inline jint get1s(unsigned char* loc) {
+static inline jint
+get1s (unsigned char* loc)
+{
return *(signed char*)loc;
}
-static inline jint get1u(unsigned char* loc) {
+static inline jint
+get1u (unsigned char* loc)
+{
return *loc;
}
-static inline jint get2s(unsigned char* loc) {
+static inline jint
+get2s(unsigned char* loc)
+{
return (((jint)*(signed char*)loc) << 8) | ((jint)*(loc+1));
}
-static inline jint get2u(unsigned char* loc) {
+static inline jint
+get2u (unsigned char* loc)
+{
return (((jint)(*loc)) << 8) | ((jint)*(loc+1));
}
-static jint get4(unsigned char* loc) {
+static jint
+get4 (unsigned char* loc)
+{
return (((jint)(loc[0])) << 24)
| (((jint)(loc[1])) << 16)
| (((jint)(loc[2])) << 8)
#ifdef HANDLE_SEGV
#define NULLARRAYCHECK(X) SAVE_PC()
#else
-#define NULLARRAYCHECK(X) \
- do { SAVE_PC(); if ((X)==NULL) { throw_null_pointer_exception (); } } while (0)
+#define NULLARRAYCHECK(X) \
+ do \
+ { \
+ SAVE_PC(); \
+ if ((X) == NULL) { throw_null_pointer_exception (); } \
+ } while (0)
#endif
-#define ARRAYBOUNDSCHECK(array, index) \
- do \
- { \
- if (((unsigned) index) >= (unsigned) (array->length)) \
- _Jv_ThrowBadArrayIndex (index); \
- } \
- while (0)
+#define ARRAYBOUNDSCHECK(array, index) \
+ do \
+ { \
+ if (((unsigned) index) >= (unsigned) (array->length)) \
+ _Jv_ThrowBadArrayIndex (index); \
+ } while (0)
void
_Jv_InterpMethod::run_normal (ffi_cif *,
- void* ret,
- ffi_raw * args,
- void* __this)
+ void *ret,
+ ffi_raw *args,
+ void *__this)
{
_Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
run (ret, args, _this);
void
_Jv_InterpMethod::run_normal_debug (ffi_cif *,
- void* ret,
- ffi_raw * args,
- void* __this)
+ 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 *,
- void* ret,
- ffi_raw * args,
- void* __this)
+ void *ret,
+ ffi_raw *args,
+ void *__this)
{
_Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
void
_Jv_InterpMethod::run_synch_object_debug (ffi_cif *,
- void* ret,
- ffi_raw * args,
- void* __this)
+ void *ret,
+ ffi_raw *args,
+ void *__this)
{
_Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
void
_Jv_InterpMethod::run_class (ffi_cif *,
- void* ret,
- ffi_raw * args,
- void* __this)
+ void *ret,
+ ffi_raw *args,
+ void *__this)
{
_Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
_Jv_InitClass (_this->defining_class);
void
_Jv_InterpMethod::run_class_debug (ffi_cif *,
- void* ret,
- ffi_raw * args,
- void* __this)
+ void *ret,
+ ffi_raw *args,
+ void *__this)
{
_Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
_Jv_InitClass (_this->defining_class);
void
_Jv_InterpMethod::run_synch_class (ffi_cif *,
- void* ret,
- ffi_raw * args,
- void* __this)
+ void *ret,
+ ffi_raw *args,
+ void *__this)
{
_Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
void
_Jv_InterpMethod::run_synch_class_debug (ffi_cif *,
- void* ret,
- ffi_raw * args,
- void* __this)
+ void *ret,
+ ffi_raw *args,
+ void *__this)
{
_Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
case op_getstatic_4:
case op_getstatic_8:
case op_getstatic_a:
+ case op_breakpoint:
default:
// Fail somehow.
break;
}
prepared = insns;
+
+ if (breakpoint_insn == NULL)
+ {
+ bp_insn_slot.insn = const_cast<void *> (insn_targets[op_breakpoint]);
+ breakpoint_insn = &bp_insn_slot;
+ }
}
#endif /* DIRECT_THREADED */
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)
* caller.
*/
-static int
-init_cif (_Jv_Utf8Const* signature,
- int arg_count,
- jboolean staticp,
- ffi_cif *cif,
- ffi_type **arg_types,
- ffi_type **rtype_p)
+int
+_Jv_init_cif (_Jv_Utf8Const* signature,
+ int arg_count,
+ jboolean staticp,
+ ffi_cif *cif,
+ ffi_type **arg_types,
+ ffi_type **rtype_p)
{
unsigned char *ptr = (unsigned char*) signature->chars();
(ncode_closure*)_Jv_AllocBytes (sizeof (ncode_closure)
+ arg_count * sizeof (ffi_type*));
- init_cif (self->signature,
- arg_count,
- staticp,
- &closure->cif,
- &closure->arg_types[0],
- NULL);
+ _Jv_init_cif (self->signature,
+ arg_count,
+ staticp,
+ &closure->cif,
+ &closure->arg_types[0],
+ NULL);
ffi_closure_fun fun;
{
if (staticp)
{
- 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;
+ if (JVMTI::enabled)
+ fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class_debug;
+ else
+ fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class;
}
else
{
- 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;
- }
+ if (JVMTI::enabled)
+ fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object_debug;
+ else
+ fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object;
+ }
}
else
{
if (staticp)
{
- if (::gnu::classpath::jdwp::Jdwp::isDebugging)
- fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class_debug;
- else
- fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class;
+ if (JVMTI::enabled)
+ fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class_debug;
+ else
+ fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class;
}
else
{
- if (::gnu::classpath::jdwp::Jdwp::isDebugging)
- fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal_debug;
- else
- fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal;
+ if (JVMTI::enabled)
+ fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal_debug;
+ else
+ fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal;
}
}
return -1;
}
+// Method to check if an exception is caught at some location in a method
+// (meth). Returns true if this method (meth) contains a catch block for the
+// exception (ex). False otherwise. If there is a catch block, it sets the pc
+// to the location of the beginning of the catch block.
+jboolean
+_Jv_InterpMethod::check_handler (pc_t *pc, _Jv_InterpMethod *meth,
+ java::lang::Throwable *ex)
+{
+#ifdef DIRECT_THREADED
+ void *logical_pc = (void *) ((insn_slot *) (*pc) - 1);
+#else
+ int logical_pc = (*pc) - 1 - meth->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 (meth->defining_class,
+ ex$
+#endif /* DIRECT_THREADED */
+ if (handler == NULL || handler->isAssignableFrom (exc_class))
+ {
+#ifdef DIRECT_THREADED
+ (*pc) = (insn_slot *) exc[i].handler_pc.p;
+#else
+ (*pc) = meth->bytecode () + exc[i].handler_pc.i;
+#endif /* DIRECT_THREADED */
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
void
_Jv_InterpMethod::get_line_table (jlong& start, jlong& end,
jintArray& line_numbers,
#endif // !DIRECT_THREADED
}
+int
+_Jv_InterpMethod::get_local_var_table (char **name, char **sig,
+ char **generic_sig, jlong *startloc,
+ jint *length, jint *slot,
+ int table_slot)
+{
+ if (local_var_table == NULL)
+ return -2;
+ if (table_slot >= local_var_table_len)
+ return -1;
+ else
+ {
+ *name = local_var_table[table_slot].name;
+ *sig = local_var_table[table_slot].descriptor;
+ *generic_sig = local_var_table[table_slot].descriptor;
+
+ *startloc = static_cast<jlong>
+ (local_var_table[table_slot].bytecode_start_pc);
+ *length = static_cast<jint> (local_var_table[table_slot].length);
+ *slot = static_cast<jint> (local_var_table[table_slot].slot);
+ }
+ return local_var_table_len - table_slot -1;
+}
+
+pc_t
+_Jv_InterpMethod::install_break (jlong index)
+{
+ return set_insn (index, breakpoint_insn);
+}
+
+pc_t
+_Jv_InterpMethod::get_insn (jlong index)
+{
+ pc_t code;
+
+#ifdef DIRECT_THREADED
+ if (index >= number_insn_slots || index < 0)
+ return NULL;
+
+ code = prepared;
+#else // !DIRECT_THREADED
+ if (index >= code_length || index < 0)
+ return NULL;
+
+ code = reinterpret_cast<pc_t> (bytecode ());
+#endif // !DIRECT_THREADED
+
+ return &code[index];
+}
+
+pc_t
+_Jv_InterpMethod::set_insn (jlong index, pc_t insn)
+{
+#ifdef DIRECT_THREADED
+ if (index >= number_insn_slots || index < 0)
+ return NULL;
+
+ pc_t code = prepared;
+ code[index].insn = insn->insn;
+#else // !DIRECT_THREADED
+ if (index >= code_length || index < 0)
+ return NULL;
+
+ pc_t code = reinterpret_cast<pc_t> (bytecode ());
+ code[index] = *insn;
+#endif // !DIRECT_THREADED
+
+ return &code[index];
+}
+
void *
_Jv_JNIMethod::ncode ()
{
+ arg_count * sizeof (ffi_type*));
ffi_type *rtype;
- init_cif (self->signature,
- arg_count,
- staticp,
- &closure->cif,
- &closure->arg_types[0],
- &rtype);
+ _Jv_init_cif (self->signature,
+ arg_count,
+ staticp,
+ &closure->cif,
+ &closure->arg_types[0],
+ &rtype);
ffi_closure_fun fun;
+ arg_count*sizeof (ffi_type*));
result->stack_item_count
- = init_cif (method->signature,
- arg_count,
- staticp,
- &result->cif,
- &result->arg_types[0],
- NULL);
+ = _Jv_init_cif (method->signature,
+ arg_count,
+ staticp,
+ &result->cif,
+ &result->arg_types[0],
+ NULL);
result->method = method;
result->klass = klass;
_Jv_CompileMethod (_Jv_InterpMethod* method)
{
if (method->prepared == NULL)
- _Jv_InterpMethod::run (NULL, NULL, method);
+ {
+ if (JVMTI::enabled)
+ _Jv_InterpMethod::run_debug (NULL, NULL, method);
+ else
+ _Jv_InterpMethod::run (NULL, NULL, method);
+ }
}
#endif // DIRECT_THREADED