* compiled directly. */
using namespace java::lang::reflect;
+
+ pc_t pc = NULL;
// FRAME_DESC registers this particular invocation as the top-most
// interpreter frame. This lets the stack tracing code (for
// destructor so it cleans up automatically when the interpreter
// returns.
java::lang::Thread *thread = java::lang::Thread::currentThread();
+
+#ifdef __GCJ_DEBUG
+ _Jv_InterpFrame frame_desc (meth, thread, NULL, &pc);
+#else
_Jv_InterpFrame frame_desc (meth, thread);
+#endif
+
+#ifdef DIRECT_THREADED
+ ThreadCountAdjuster adj (meth, &frame_desc);
+#endif // DIRECT_THREADED
_Jv_word stack[meth->max_stack];
_Jv_word *sp = stack;
_Jv_word locals[meth->max_locals];
+#ifdef __GCJ_DEBUG
+ // This is the information needed to get and set local variables with
+ // proper type checking.
+ frame_desc.locals = locals;
+ char locals_type[meth->max_locals];
+ frame_desc.locals_type = locals_type;
+
+ // Set all slots as invalid until they are written to.
+ memset (locals_type, 'x', meth->max_locals);
+
+ // We need to set the local variable types for the method arguments since
+ // they are valid at invocation.
+
+ _Jv_Method *method = meth->get_method ();
+ int type_ctr = 0;
+
+ // If the method is non-static, we need to set the type for the "this" pointer.
+ if ((method->accflags & java::lang::reflect::Modifier::STATIC) == 0)
+ {
+ if (args)
+ {
+ // Set the "this" pointer for this frame.
+ _Jv_word *this_ptr = reinterpret_cast<_Jv_word *> (args);
+ frame_desc.obj_ptr = this_ptr[0].o;
+ }
+
+ frame_desc.locals_type[0] = 'o';
+ type_ctr++;
+ }
+
+ // Now parse the method signature to set the types of the other arguments.
+ int sig_len = method->signature->len ();
+ char *signature = method->signature->chars ();
+ for (int i = 1; signature[i] != ')' && i <= sig_len; i++)
+ {
+ if (signature[i] == 'Z' || signature[i] == 'B' || signature[i] == 'C'
+ || signature[i] == 'S' || signature[i] == 'I')
+ {
+ frame_desc.locals_type[type_ctr] = 'i';
+ type_ctr++;
+ continue;
+ }
+ else if (signature[i] == 'F')
+ {
+ frame_desc.locals_type[type_ctr] = 'f';
+ type_ctr++;
+ continue;
+ }
+ else if (signature[i] == 'J')
+ {
+ frame_desc.locals_type[type_ctr] = 'l';
+ frame_desc.locals_type[type_ctr+1] = 'x';
+ type_ctr += 2;
+ continue;
+ }
+ else if (signature[i] == 'D')
+ {
+ frame_desc.locals_type[type_ctr] = 'd';
+ frame_desc.locals_type[type_ctr+1] = 'x';
+ type_ctr += 2;
+ continue;
+ }
+ else if (signature[i] == 'L')
+ {
+ frame_desc.locals_type[type_ctr] = 'o';
+ type_ctr++;
+ while (signature[i] != ';')
+ i++;
+ continue;
+ }
+ else if (signature[i] == '[')
+ {
+ frame_desc.locals_type[type_ctr] = 'o';
+ type_ctr++;
+
+ // Ignore multi-dimensional arrays.
+ while (signature[i] == '[')
+ i++;
+
+ // Check for an object array
+ if (signature[i] == 'L')
+ {
+ while (signature[i] != ';')
+ i++;
+ }
+ continue;
+ }
+ }
+#endif /* __GCJ_DEBUG */
+
#define INSN_LABEL(op) &&insn_##op
static const void *const insn_target[] =
#endif
};
- pc_t pc;
-
#ifdef DIRECT_THREADED
-#ifdef DEBUG
+#ifdef __GCJ_DEBUG
#undef NEXT_INSN
#define NEXT_INSN \
do \
{ \
+ pc_t insn = pc++; \
if (JVMTI_REQUESTED_EVENT (SingleStep)) \
{ \
JNIEnv *env = _Jv_GetCurrentJNIEnv (); \
jmethodID method = meth->self; \
- jlocation loc = meth->insn_index (pc); \
+ jlocation loc = meth->insn_index (insn); \
_Jv_JVMTI_PostEvent (JVMTI_EVENT_SINGLE_STEP, thread, \
env, method, loc); \
} \
- goto *((pc++)->insn); \
+ goto *(insn->insn); \
} \
while (0)
-#else
+
+// We fail to rewrite a breakpoint if there is another thread
+// currently executing this method. This is a bug, but there's
+// nothing else we can do that doesn't cause a data race.
+#undef REWRITE_INSN
+#define REWRITE_INSN(INSN,SLOT,VALUE) \
+ do \
+ { \
+ _Jv_MutexLock (&rewrite_insn_mutex); \
+ if (meth->thread_count <= 1) \
+ { \
+ if (pc[-2].insn == breakpoint_insn->insn) \
+ { \
+ using namespace ::gnu::gcj::jvmti; \
+ jlocation location = meth->insn_index (pc - 2); \
+ _Jv_RewriteBreakpointInsn (meth->self, location, (pc_t) INSN); \
+ } \
+ else \
+ pc[-2].insn = INSN; \
+ \
+ pc[-1].SLOT = VALUE; \
+ } \
+ _Jv_MutexUnlock (&rewrite_insn_mutex); \
+ } \
+ while (0)
+
+#undef INTERP_REPORT_EXCEPTION
+#define INTERP_REPORT_EXCEPTION(Jthrowable) REPORT_EXCEPTION (Jthrowable)
+#else // !__GCJ_DEBUG
#undef NEXT_INSN
#define NEXT_INSN goto *((pc++)->insn)
-#endif
+
+// Rewriting a multi-word instruction in the presence of multiple
+// threads is a data race if a thread reads part of an instruction
+// while some other thread is rewriting that instruction. We detect
+// more than one thread executing a method and don't rewrite the
+// instruction. A thread entering a method blocks on
+// rewrite_insn_mutex until the write is complete.
+#define REWRITE_INSN(INSN,SLOT,VALUE) \
+ do { \
+ _Jv_MutexLock (&rewrite_insn_mutex); \
+ if (meth->thread_count <= 1) \
+ { \
+ pc[-2].insn = INSN; \
+ pc[-1].SLOT = VALUE; \
+ } \
+ _Jv_MutexUnlock (&rewrite_insn_mutex); \
+ } \
+ while (0)
+
+#undef INTERP_REPORT_EXCEPTION
+#define INTERP_REPORT_EXCEPTION(Jthrowable) /* not needed when not debugging */
+#endif // !__GCJ_DEBUG
#define INTVAL() ((pc++)->int_val)
#define AVAL() ((pc++)->datum)
#else
-#ifdef DEBUG
+#ifdef __GCJ_DEBUG
#define NEXT_INSN \
do \
{ \
*/
memcpy ((void*) locals, (void*) args, meth->args_raw_size);
-#ifdef DEBUG
- // Get the object pointer for this method, after checking that it is
- // non-static.
- _Jv_Method *method = meth->get_method ();
-
- if ((method->accflags & java::lang::reflect::Modifier::STATIC) == 0)
- frame_desc.obj_ptr = locals[0].o;
-#endif
-
_Jv_word *pool_data = meth->defining_class->constants.data;
/* These three are temporaries for common code used by several
#ifdef DIRECT_THREADED
// Rewrite instruction so that we use a faster pre-resolved
// method.
- pc[-2].insn = &&invokevirtual_resolved;
- pc[-1].datum = rmeth;
+ REWRITE_INSN (&&invokevirtual_resolved, datum, rmeth);
#endif /* DIRECT_THREADED */
}
goto perform_invoke;
}
else
{
+ NULLCHECK (sp[0].o);
jobject rcv = sp[0].o;
_Jv_VTable *table = *(_Jv_VTable**) rcv;
fun = (void (*)()) table->get_method (rmeth->method->index);
{
/* here goes the magic again... */
ffi_cif *cif = &rmeth->cif;
- ffi_raw *raw = (ffi_raw*) sp;
+ INTERP_FFI_RAW_TYPE *raw = (INTERP_FFI_RAW_TYPE *) sp;
_Jv_value rvalue;
}
#ifdef DIRECT_THREADED
- pc[-2].insn = newinsn;
- pc[-1].datum = field->u.addr;
+ REWRITE_INSN (newinsn, datum, field->u.addr);
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
}
#ifdef DIRECT_THREADED
- pc[-2].insn = newinsn;
- pc[-1].int_val = field_offset;
+ REWRITE_INSN (newinsn, int_val, field_offset);
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
}
#ifdef DIRECT_THREADED
- pc[-2].insn = newinsn;
- pc[-1].datum = field->u.addr;
+ REWRITE_INSN (newinsn, datum, field->u.addr);
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
}
#ifdef DIRECT_THREADED
- pc[-2].insn = newinsn;
- pc[-1].int_val = field_offset;
+ REWRITE_INSN (newinsn, int_val, field_offset);
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
#ifdef DIRECT_THREADED
// Rewrite instruction so that we use a faster pre-resolved
// method.
- pc[-2].insn = &&invokespecial_resolved;
- pc[-1].datum = rmeth;
+ REWRITE_INSN (&&invokespecial_resolved, datum, rmeth);
#endif /* DIRECT_THREADED */
}
goto perform_invoke;
#ifdef DIRECT_THREADED
// Rewrite instruction so that we use a faster pre-resolved
// method.
- pc[-2].insn = &&invokestatic_resolved;
- pc[-1].datum = rmeth;
+ REWRITE_INSN (&&invokestatic_resolved, datum, rmeth);
#endif /* DIRECT_THREADED */
}
goto perform_invoke;
#ifdef DIRECT_THREADED
// Rewrite instruction so that we use a faster pre-resolved
// method.
- pc[-2].insn = &&invokeinterface_resolved;
- pc[-1].datum = rmeth;
+ REWRITE_INSN (&&invokeinterface_resolved, datum, rmeth);
#else
// Skip dummy bytes.
pc += 2;
/* VM spec, section 3.11.5 */
if ((klass->getModifiers() & Modifier::ABSTRACT)
|| klass->isInterface())
- throw new java::lang::InstantiationException;
+ {
+ jthrowable t = new java::lang::InstantiationException;
+ INTERP_REPORT_EXCEPTION (t);
+ throw t;
+ }
jobject res = _Jv_AllocObject (klass);
PUSHA (res);
#ifdef DIRECT_THREADED
- pc[-2].insn = &&new_resolved;
- pc[-1].datum = klass;
+ REWRITE_INSN (&&new_resolved, datum, klass);
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
PUSHA (result);
#ifdef DIRECT_THREADED
- pc[-2].insn = &&anewarray_resolved;
- pc[-1].datum = klass;
+ REWRITE_INSN (&&anewarray_resolved, datum, klass);
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
insn_athrow:
{
jobject value = POPA();
- throw static_cast<jthrowable>(value);
+ jthrowable t = static_cast<jthrowable> (value);
+ INTERP_REPORT_EXCEPTION (t);
+ throw t;
}
NEXT_INSN;
PUSHA (value);
#ifdef DIRECT_THREADED
- pc[-2].insn = &&checkcast_resolved;
- pc[-1].datum = to;
+ REWRITE_INSN (&&checkcast_resolved, datum, to);
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
PUSHI (to->isInstance (value));
#ifdef DIRECT_THREADED
- pc[-2].insn = &&instanceof_resolved;
- pc[-1].datum = to;
+ REWRITE_INSN (&&instanceof_resolved, datum, to);
#endif /* DIRECT_THREADED */
}
NEXT_INSN;
insn_breakpoint:
{
- JvAssert (JVMTI_REQUESTED_EVENT (Breakpoint));
-
- // Send JVMTI notification
using namespace ::java::lang;
jmethodID method = meth->self;
jlocation location = meth->insn_index (pc - 1);
- Thread *thread = Thread::currentThread ();
- JNIEnv *jni_env = _Jv_GetCurrentJNIEnv ();
- _Jv_JVMTI_PostEvent (JVMTI_EVENT_BREAKPOINT, thread, jni_env,
- method, location);
-
- // Continue execution
using namespace gnu::gcj::jvmti;
Breakpoint *bp
= BreakpointManager::getBreakpoint (reinterpret_cast<jlong> (method),
location);
JvAssert (bp != NULL);
+ // Save the insn here since the breakpoint could be removed
+ // before the JVMTI notification returns.
pc_t opc = reinterpret_cast<pc_t> (bp->getInsn ());
+ bp->execute ();
+
+ // Continue execution
#ifdef DIRECT_THREADED
goto *(opc->insn);
#else
}
catch (java::lang::Throwable *ex)
{
-#ifdef DIRECT_THREADED
- void *logical_pc = (void *) ((insn_slot *) pc - 1);
-#else
- int logical_pc = pc - 1 - meth->bytecode ();
+ // Check if the exception is handled and, if so, set the pc to the start
+ // of the appropriate catch block.
+ if (meth->check_handler (&pc, meth, ex))
+ {
+ sp = stack;
+ sp++->o = ex; // Push exception.
+#ifdef __GCJ_DEBUG
+ if (JVMTI_REQUESTED_EVENT (ExceptionCatch))
+ {
+ using namespace gnu::gcj::jvmti;
+ jlong catch_meth = reinterpret_cast<jlong> (meth->get_method ());
+ jlong catch_loc = meth->insn_index (pc);
+ _Jv_JVMTI_PostEvent (JVMTI_EVENT_EXCEPTION_CATCH, thread,
+ _Jv_GetCurrentJNIEnv (), catch_meth,
+ catch_loc, ex);
+ }
#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,
- 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 = meth->bytecode () + exc[i].handler_pc.i;
-#endif /* DIRECT_THREADED */
- sp = stack;
- sp++->o = ex; // Push exception.
- NEXT_INSN;
- }
- }
- }
+ NEXT_INSN;
+ }
// No handler, so re-throw.
throw ex;