X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=libjava%2Finterpret-run.cc;h=a4c2d4dab43b614543070e7739661d1cfa21a54c;hp=b8c88af78278c865f27cba843f6f6002d6365fb5;hb=9cecf767f073a1b553c04e7884cc37db12fbe2d0;hpb=3bbb4ded802b98bd51ad6837b638bbf02d56c4cf diff --git a/libjava/interpret-run.cc b/libjava/interpret-run.cc index b8c88af7827..a4c2d4dab43 100644 --- a/libjava/interpret-run.cc +++ b/libjava/interpret-run.cc @@ -12,6 +12,8 @@ details. */ * 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 @@ -20,14 +22,23 @@ details. */ // 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 DEBUG +#ifdef __GCJ_DEBUG // This is the information needed to get and set local variables with // proper type checking. frame_desc.locals = locals; @@ -115,7 +126,7 @@ details. */ continue; } } -#endif /* DEBUG */ +#endif /* __GCJ_DEBUG */ #define INSN_LABEL(op) &&insn_##op @@ -334,30 +345,78 @@ details. */ #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) @@ -391,7 +450,7 @@ details. */ #else -#ifdef DEBUG +#ifdef __GCJ_DEBUG #define NEXT_INSN \ do \ { \ @@ -506,8 +565,7 @@ details. */ #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; @@ -530,6 +588,7 @@ details. */ } else { + NULLCHECK (sp[0].o); jobject rcv = sp[0].o; _Jv_VTable *table = *(_Jv_VTable**) rcv; fun = (void (*)()) table->get_method (rmeth->method->index); @@ -542,7 +601,7 @@ details. */ { /* 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; @@ -1841,8 +1900,7 @@ details. */ } #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; @@ -1932,8 +1990,7 @@ details. */ } #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; @@ -2048,8 +2105,7 @@ details. */ } #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; @@ -2147,8 +2203,7 @@ details. */ } #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; @@ -2223,8 +2278,7 @@ details. */ #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; @@ -2261,8 +2315,7 @@ details. */ #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; @@ -2300,8 +2353,7 @@ details. */ #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; @@ -2334,13 +2386,16 @@ details. */ /* 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; @@ -2375,8 +2430,7 @@ details. */ 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; @@ -2403,7 +2457,9 @@ details. */ insn_athrow: { jobject value = POPA(); - throw static_cast(value); + jthrowable t = static_cast (value); + INTERP_REPORT_EXCEPTION (t); + throw t; } NEXT_INSN; @@ -2420,8 +2476,7 @@ details. */ 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; @@ -2448,8 +2503,7 @@ details. */ 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; @@ -2591,27 +2645,23 @@ details. */ 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 (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 (bp->getInsn ()); + bp->execute (); + + // Continue execution #ifdef DIRECT_THREADED goto *(opc->insn); #else @@ -2621,38 +2671,26 @@ details. */ } catch (java::lang::Throwable *ex) { -#ifdef DEBUG - // This needs to be done before the pc is changed. - jlong throw_loc = meth->insn_index (pc); -#endif // 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 DEBUG - if (JVMTI_REQUESTED_EVENT (Exception)) +#ifdef __GCJ_DEBUG + if (JVMTI_REQUESTED_EVENT (ExceptionCatch)) { using namespace gnu::gcj::jvmti; - jlong throw_meth = reinterpret_cast (meth->get_method ()); + jlong catch_meth = reinterpret_cast (meth->get_method ()); jlong catch_loc = meth->insn_index (pc); - ExceptionEvent::postExceptionEvent (thread, throw_meth, - throw_loc, ex, throw_meth, - catch_loc); + _Jv_JVMTI_PostEvent (JVMTI_EVENT_EXCEPTION_CATCH, thread, + _Jv_GetCurrentJNIEnv (), catch_meth, + catch_loc, ex); } #endif NEXT_INSN; } -#ifdef DEBUG - if (JVMTI_REQUESTED_EVENT (Exception)) - { - using namespace gnu::gcj::jvmti; - jlong throw_meth = reinterpret_cast (meth->get_method ()); - ExceptionEvent::postExceptionEvent (thread, throw_meth, throw_loc, - ex, NULL, NULL); - } -#endif + // No handler, so re-throw. throw ex; }