summaryrefslogtreecommitdiffstats
path: root/vm/interp
diff options
context:
space:
mode:
authorbuzbee <buzbee@google.com>2011-03-28 18:12:30 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-03-28 18:12:30 -0700
commit9d755ce64ea9714b2c01473b7f4c21747a5f39c1 (patch)
tree1d4a47680518dbadfeabb853eec7e53ef09b2ee7 /vm/interp
parentedb595d5ee6d5b2eddf9b897efc4ccbf56ee6c12 (diff)
parent94d65255849ce9f195c971f726e8b09449ba4d14 (diff)
downloadandroid_dalvik-9d755ce64ea9714b2c01473b7f4c21747a5f39c1.tar.gz
android_dalvik-9d755ce64ea9714b2c01473b7f4c21747a5f39c1.tar.bz2
android_dalvik-9d755ce64ea9714b2c01473b7f4c21747a5f39c1.zip
Merge "Add safepoint callback for gc" into dalvik-dev
Diffstat (limited to 'vm/interp')
-rw-r--r--vm/interp/Interp.c63
-rw-r--r--vm/interp/Interp.h16
-rw-r--r--vm/interp/InterpState.h5
3 files changed, 77 insertions, 7 deletions
diff --git a/vm/interp/Interp.c b/vm/interp/Interp.c
index 9df0d230e..98f478ee8 100644
--- a/vm/interp/Interp.c
+++ b/vm/interp/Interp.c
@@ -1552,6 +1552,35 @@ void dvmUpdateAllInterpBreak(int newBreak, int newMode, bool enable)
}
/*
+ * Arm a safepoint callback for a thread. If funct is null,
+ * clear any pending callback.
+ * TODO: only gc is currently using this feature, and will have
+ * at most a single outstanding callback request. Until we need
+ * something more capable and flexible, enforce this limit.
+ */
+void dvmArmSafePointCallback(Thread* thread, SafePointCallback funct,
+ void* arg)
+{
+ dvmLockMutex(&thread->callbackMutex);
+ if ((funct == NULL) || (thread->callback == NULL)) {
+ thread->callback = funct;
+ thread->callbackArg = arg;
+ dvmUpdateInterpBreak(thread, kInterpSafePointCallback,
+ kSubModeNormal, (funct != NULL));
+ } else {
+ // Already armed. Different?
+ if ((funct != thread->callback) ||
+ (arg != thread->callbackArg)) {
+ // Yes - report failure and die
+ LOGE("ArmSafePointCallback failed, thread %d", thread->threadId);
+ dvmUnlockMutex(&thread->callbackMutex);
+ dvmAbort();
+ }
+ }
+ dvmUnlockMutex(&thread->callbackMutex);
+}
+
+/*
* One-time initialization at thread creation. Here we initialize
* useful constants.
*/
@@ -1604,7 +1633,7 @@ void dvmInitInterpreterState(Thread* self)
* count profiling, JIT trace building, etc. Dalvik PC has been exported
* prior to call, but Thread copy of dPC & fp are not current.
*/
-void dvmCheckBefore(const u2 *pc, const u4 *fp, Thread* self)
+void dvmCheckBefore(const u2 *pc, u4 *fp, Thread* self)
{
const Method* method = self->interpSave.method;
assert(self->interpBreak.ctl.breakFlags != 0);
@@ -1637,14 +1666,38 @@ void dvmCheckBefore(const u2 *pc, const u4 *fp, Thread* self)
}
#endif
- /* Suspend pending? */
- if (self->interpBreak.ctl.suspendCount) {
+ /* Safe point handling */
+ if (self->interpBreak.ctl.suspendCount ||
+ (self->interpBreak.ctl.breakFlags & kInterpSafePointCallback)) {
// Are we are a safe point?
int flags;
flags = dexGetFlagsFromOpcode(dexOpcodeFromCodeUnit(*pc));
if (flags & VERIFY_GC_INST_MASK) {
- dvmExportPC(pc, fp);
- dvmCheckSuspendPending(self);
+ // Yes, at a safe point. Pending callback?
+ if (self->interpBreak.ctl.breakFlags & kInterpSafePointCallback) {
+ SafePointCallback callback;
+ void* arg;
+ // Get consistent funct/arg pair
+ dvmLockMutex(&self->callbackMutex);
+ callback = self->callback;
+ arg = self->callbackArg;
+ dvmUnlockMutex(&self->callbackMutex);
+ // Update Thread structure
+ self->interpSave.pc = pc;
+ self->interpSave.fp = fp;
+ if (callback != NULL) {
+ // Do the callback
+ if (!callback(self,arg)) {
+ // disarm
+ dvmArmSafePointCallback(self, NULL, NULL);
+ }
+ }
+ }
+ // Need to suspend?
+ if (self->interpBreak.ctl.suspendCount) {
+ dvmExportPC(pc, fp);
+ dvmCheckSuspendPending(self);
+ }
}
}
diff --git a/vm/interp/Interp.h b/vm/interp/Interp.h
index 9e059f923..b6919af15 100644
--- a/vm/interp/Interp.h
+++ b/vm/interp/Interp.h
@@ -79,7 +79,7 @@ void dvmFlushBreakpoints(ClassObject* clazz);
*/
void dvmUpdateDebugger(const Method* method, const u2* pc, const u4* fp,
bool methodEntry, Thread* self);
-void dvmCheckBefore(const u2 *dPC, const u4 *fp, Thread* self);
+void dvmCheckBefore(const u2 *dPC, u4 *fp, Thread* self);
void dvmReportExceptionThrow(Thread* self, const Method* curMethod,
const u2* pc, void* fp);
void dvmReportPreNativeInvoke(const u2* pc, Thread* self,
@@ -101,6 +101,20 @@ void dvmAddToSuspendCounts(Thread* thread, int delta, int dbgDelta);
*/
void dvmUpdateAllInterpBreak(int newBreak, int newMode, bool enable);
+/*
+ * Register a callback to occur at the next safe point for a single thread.
+ * If funct is NULL, the previous registration is cancelled.
+ *
+ * The callback prototype is:
+ * bool funct(Thread* thread, void* arg)
+ *
+ * If funct returns false, the callback will be disarmed. If true,
+ * it will stay in effect.
+ */
+void dvmArmSafePointCallback(Thread* thread, SafePointCallback funct,
+ void* arg);
+
+
#ifndef DVM_NO_ASM_INTERP
extern void* dvmAsmInstructionStart[];
extern void* dvmAsmAltInstructionStart[];
diff --git a/vm/interp/InterpState.h b/vm/interp/InterpState.h
index 2294a8132..6f8647682 100644
--- a/vm/interp/InterpState.h
+++ b/vm/interp/InterpState.h
@@ -71,11 +71,14 @@ typedef enum InterpBreakFlags {
kInterpDebugBreak = 0x04,
kInterpEmulatorTraceBreak = 0x08,
kInterpSingleStep = 0x10,
+ kInterpSafePointCallback = 0x20,
#if defined(WITH_JIT)
- kInterpJitBreak = 0x20,
+ kInterpJitBreak = 0x40,
#endif
} InterpBreakFlags;
+typedef bool (*SafePointCallback)(struct Thread* thread, void* arg);
+
/*
* Identify which break and submode flags should be local
* to an interpreter activation.