aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Haley <aph@redhat.com>2008-09-23 13:51:58 +0000
committerAndrew Haley <aph@redhat.com>2008-09-23 13:51:58 +0000
commit051008685ad9572eef4e38b46583ffe5695f5d6a (patch)
tree5aa7ac0da62ededbaab14350de950b012a5759a3
parentbe85a99f4e682552ffe3794a3893d233a2e20deb (diff)
2008-09-17 Andrew Haley <aph@redhat.com>
PR libgcj/8995: * defineclass.cc (_Jv_ClassReader::handleCodeAttribute): Initialize thread_count. * include/java-interp.h (_Jv_InterpMethod::thread_count): New field. (_Jv_InterpMethod::rewrite_insn_mutex): New mutex. (_Jv_InterpFrame:: _Jv_InterpFrame): Pass frame_type. * interpret.cc (ThreadCountAdjuster): New class. (_Jv_InterpMethod::thread_count): New field. (_Jv_InitInterpreter): Initialize rewrite_insn_mutex. Increment and decrement thread_count field in methods. * interpret-run.cc (REWRITE_INSN): Check thread_count <= 1. (REWRITE_INSN): Likewise. Declare a ThreadCountAdjuster. * java/lang/reflect/natVMProxy.cc (run_proxy): Initialize frame type as frame_proxy. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@140593 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--libjava/ChangeLog21
-rw-r--r--libjava/defineclass.cc4
-rw-r--r--libjava/include/java-interp.h86
-rw-r--r--libjava/interpret-run.cc67
-rw-r--r--libjava/interpret.cc5
-rw-r--r--libjava/java/lang/reflect/natVMProxy.cc3
6 files changed, 155 insertions, 31 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index 728dc982b3a..4bf454731af 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,24 @@
+2008-09-17 Andrew Haley <aph@redhat.com>
+
+ PR libgcj/8995:
+
+ * defineclass.cc (_Jv_ClassReader::handleCodeAttribute):
+ Initialize thread_count.
+ * include/java-interp.h (_Jv_InterpMethod::thread_count): New
+ field.
+ (_Jv_InterpMethod::rewrite_insn_mutex): New mutex.
+ (_Jv_InterpFrame:: _Jv_InterpFrame): Pass frame_type.
+ * interpret.cc
+ (ThreadCountAdjuster): New class.
+ (_Jv_InterpMethod::thread_count): New field.
+ (_Jv_InitInterpreter): Initialize rewrite_insn_mutex.
+ Increment and decrement thread_count field in methods.
+ * interpret-run.cc (REWRITE_INSN): Check thread_count <= 1.
+ (REWRITE_INSN): Likewise.
+ Declare a ThreadCountAdjuster.
+ * java/lang/reflect/natVMProxy.cc (run_proxy): Initialize frame
+ type as frame_proxy.
+
2008-09-05 David Daney <ddaney@avtrex.com>
* configure.ac (reduced-reflection): New AC_ARG_ENABLE.
diff --git a/libjava/defineclass.cc b/libjava/defineclass.cc
index 3416c468071..4c4e0a7f45d 100644
--- a/libjava/defineclass.cc
+++ b/libjava/defineclass.cc
@@ -1682,7 +1682,9 @@ void _Jv_ClassReader::handleCodeAttribute
method->prepared = NULL;
method->line_table_len = 0;
method->line_table = NULL;
-
+#ifdef DIRECT_THREADED
+ method->thread_count = 0;
+#endif
// grab the byte code!
memcpy ((void*) method->bytecode (),
diff --git a/libjava/include/java-interp.h b/libjava/include/java-interp.h
index c6d9955f4bf..c088e9f010d 100644
--- a/libjava/include/java-interp.h
+++ b/libjava/include/java-interp.h
@@ -175,6 +175,17 @@ class _Jv_InterpMethod : public _Jv_MethodBase
static pc_t breakpoint_insn;
#ifdef DIRECT_THREADED
static insn_slot bp_insn_slot;
+
+public:
+ // Mutex to prevent a data race between threads when rewriting
+ // instructions. See interpret-run.cc for an explanation of its use.
+ static _Jv_Mutex_t rewrite_insn_mutex;
+
+ // The count of threads executing this method.
+ long thread_count;
+
+private:
+
#else
static unsigned char bp_insn_opcode;
#endif
@@ -455,9 +466,10 @@ public:
jobject obj_ptr;
_Jv_InterpFrame (void *meth, java::lang::Thread *thr, jclass proxyCls = NULL,
- pc_t *pc = NULL)
+ pc_t *pc = NULL,
+ _Jv_FrameType frame_type = frame_interpreter)
: _Jv_Frame (reinterpret_cast<_Jv_MethodBase *> (meth), thr,
- frame_interpreter)
+ frame_type)
{
next_interp = (_Jv_InterpFrame *) thr->interp_frame;
proxyClass = proxyCls;
@@ -501,6 +513,76 @@ public:
}
};
+#ifdef DIRECT_THREADED
+// This class increments and decrements the thread_count field in an
+// interpreted method. On entry to the interpreter a
+// ThreadCountAdjuster is created when increments the thread_count in
+// the current method and uses the next_interp field in the frame to
+// find the previous method and decrement its thread_count.
+class ThreadCountAdjuster
+{
+
+ // A class used to handle the rewrite_insn_mutex while we're
+ // adjusting the thread_count in a method. Unlocking the mutex in a
+ // destructor ensures that it's unlocked even if (for example) a
+ // segfault occurs in the critical section.
+ class MutexLock
+ {
+ private:
+ _Jv_Mutex_t *mutex;
+ public:
+ MutexLock (_Jv_Mutex_t *m)
+ {
+ mutex = m;
+ _Jv_MutexLock (mutex);
+ }
+ ~MutexLock ()
+ {
+ _Jv_MutexUnlock (mutex);
+ }
+ };
+
+ _Jv_InterpMethod *method;
+ _Jv_InterpMethod *next_method;
+
+public:
+
+ ThreadCountAdjuster (_Jv_InterpMethod *m, _Jv_InterpFrame *fr)
+ {
+ MutexLock lock (&::_Jv_InterpMethod::rewrite_insn_mutex);
+
+ method = m;
+ next_method = NULL;
+
+ _Jv_InterpFrame *next_interp = fr->next_interp;
+
+ // Record the fact that we're executing this method and that
+ // we're no longer executing the method that called us.
+ method->thread_count++;
+
+ if (next_interp && next_interp->frame_type == frame_interpreter)
+ {
+ next_method
+ = reinterpret_cast<_Jv_InterpMethod *> (next_interp->meth);
+ next_method->thread_count--;
+ }
+ }
+
+ ~ThreadCountAdjuster ()
+ {
+ MutexLock lock (&::_Jv_InterpMethod::rewrite_insn_mutex);
+
+ // We're going to return to the method that called us, so bump its
+ // thread_count and decrement our own.
+
+ method->thread_count--;
+
+ if (next_method)
+ next_method->thread_count++;
+ }
+};
+#endif // DIRECT_THREADED
+
#endif /* INTERPRETER */
#endif /* __JAVA_INTERP_H__ */
diff --git a/libjava/interpret-run.cc b/libjava/interpret-run.cc
index 2934b9b8956..059195360ed 100644
--- a/libjava/interpret-run.cc
+++ b/libjava/interpret-run.cc
@@ -29,6 +29,10 @@ details. */
_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;
@@ -361,20 +365,29 @@ details. */
} \
while (0)
+// 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 { \
- 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; \
+ 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; \
- } \
+ pc[-1].SLOT = VALUE; \
+ } \
+ _Jv_MutexUnlock (&rewrite_insn_mutex); \
+ } \
while (0)
#undef INTERP_REPORT_EXCEPTION
@@ -383,23 +396,23 @@ details. */
#undef NEXT_INSN
#define NEXT_INSN goto *((pc++)->insn)
-// REWRITE_INSN does nothing.
-//
// Rewriting a multi-word instruction in the presence of multiple
-// threads leads to a data race if a thread reads part of an
-// instruction while some other thread is rewriting that instruction.
-// For example, an invokespecial instruction may be rewritten to
-// invokespecial_resolved and its operand changed from an index to a
-// pointer while another thread is executing invokespecial. This
-// other thread then reads the pointer that is now the operand of
-// invokespecial_resolved and tries to use it as an index.
-//
-// Fixing this requires either spinlocks, a more elaborate data
-// structure, or even per-thread allocated pages. It's clear from the
-// locking in meth->compile below that the presence of multiple
-// threads was contemplated when this code was written, but the full
-// consequences were not fully appreciated.
-#define REWRITE_INSN(INSN,SLOT,VALUE)
+// 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 */
diff --git a/libjava/interpret.cc b/libjava/interpret.cc
index 6153c542036..dc1114f65f1 100644
--- a/libjava/interpret.cc
+++ b/libjava/interpret.cc
@@ -78,10 +78,15 @@ static void find_catch_location (jthrowable, jthread, jmethodID *, jlong *);
// the Class monitor as user code in another thread could hold it.
static _Jv_Mutex_t compile_mutex;
+// See class ThreadCountAdjuster and REWRITE_INSN for how this is
+// used.
+_Jv_Mutex_t _Jv_InterpMethod::rewrite_insn_mutex;
+
void
_Jv_InitInterpreter()
{
_Jv_MutexInit (&compile_mutex);
+ _Jv_MutexInit (&_Jv_InterpMethod::rewrite_insn_mutex);
}
#else
void _Jv_InitInterpreter() {}
diff --git a/libjava/java/lang/reflect/natVMProxy.cc b/libjava/java/lang/reflect/natVMProxy.cc
index a1b7dfcc398..4c3fd74f91c 100644
--- a/libjava/java/lang/reflect/natVMProxy.cc
+++ b/libjava/java/lang/reflect/natVMProxy.cc
@@ -350,7 +350,8 @@ run_proxy (ffi_cif *cif,
// than about Proxy.class itself. FRAME_DESC has a destructor so it
// cleans up automatically when this proxy invocation returns.
Thread *thread = Thread::currentThread();
- _Jv_InterpFrame frame_desc (self->self, thread, proxyClass);
+ _Jv_InterpFrame frame_desc (self->self, thread, proxyClass,
+ NULL, frame_proxy);
// The method to invoke is saved in $Proxy0.m[method_index].
// FIXME: We could somewhat improve efficiency by storing a pointer