aboutsummaryrefslogtreecommitdiffstats
path: root/emulator/qtools/callstack.h
diff options
context:
space:
mode:
Diffstat (limited to 'emulator/qtools/callstack.h')
-rw-r--r--emulator/qtools/callstack.h250
1 files changed, 123 insertions, 127 deletions
diff --git a/emulator/qtools/callstack.h b/emulator/qtools/callstack.h
index b73efea..8982330 100644
--- a/emulator/qtools/callstack.h
+++ b/emulator/qtools/callstack.h
@@ -32,7 +32,9 @@ class StackFrame {
typedef SYM symbol_type;
static const uint32_t kCausedException = 0x01;
static const uint32_t kInterpreted = 0x02;
- static const uint32_t kPopBarrier = (kCausedException | kInterpreted);
+ static const uint32_t kStartNative = 0x04;
+ static const uint32_t kPopBarrier = (kCausedException | kInterpreted
+ | kStartNative);
symbol_type *function; // the symbol for the function we entered
uint32_t addr; // return address when this function returns
@@ -43,7 +45,7 @@ class StackFrame {
template <class FRAME, class BASE = CallStackBase>
class CallStack : public BASE {
- public:
+public:
typedef FRAME frame_type;
typedef typename FRAME::symbol_type symbol_type;
typedef typename FRAME::symbol_type::region_type region_type;
@@ -57,7 +59,7 @@ class CallStack : public BASE {
void threadStart(uint64_t time);
void threadStop(uint64_t time);
- // Set to true if you don't want to see any Java methods
+ // Set to true if you don't want to see any Java methods ever
void setNativeOnly(bool nativeOnly) {
mNativeOnly = nativeOnly;
}
@@ -66,38 +68,36 @@ class CallStack : public BASE {
uint64_t getGlobalTime(uint64_t time) { return time + mSkippedTime; }
void showStack(FILE *stream);
- void showSnapshotStack(FILE *stream);
int mNumFrames;
FRAME *mFrames;
int mTop; // index of the next stack frame to write
- private:
- enum Action { NONE, PUSH, POP };
+private:
+ enum Action { NONE, PUSH, POP, NATIVE_PUSH };
Action getAction(BBEvent *event, symbol_type *function);
- Action getMethodAction(BBEvent *event, symbol_type *function);
+ void doMethodAction(BBEvent *event, symbol_type *function);
+ void doMethodPop(BBEvent *event, uint32_t addr, const uint32_t flags);
void doSimplePush(symbol_type *function, uint32_t addr,
- uint64_t time);
+ uint64_t time, int flags);
void doSimplePop(uint64_t time);
void doPush(BBEvent *event, symbol_type *function);
void doPop(BBEvent *event, symbol_type *function, Action methodAction);
- void transitionToJava();
- void transitionFromJava(uint64_t time);
-
TraceReaderType *mTrace;
+
+ // This is a global switch that disables Java methods from appearing
+ // on the stack.
bool mNativeOnly;
+
+ // This keeps track of whether native frames are currently allowed on the
+ // stack.
+ bool mAllowNativeFrames;
symbol_type mDummyFunction;
region_type mDummyRegion;
- int mJavaTop;
-
- int mSnapshotNumFrames;
- FRAME *mSnapshotFrames;
- int mSnapshotTop; // index of the next stack frame to write
-
symbol_type *mPrevFunction;
BBEvent mPrevEvent;
@@ -125,10 +125,7 @@ CallStack<FRAME, BASE>::CallStack(int id, int numFrames, TraceReaderType *trace)
mNumFrames = numFrames;
mFrames = new FRAME[mNumFrames];
mTop = 0;
-
- mSnapshotNumFrames = numFrames;
- mSnapshotFrames = new FRAME[mSnapshotNumFrames];
- mSnapshotTop = 0;
+ mAllowNativeFrames = true;
memset(&mDummyFunction, 0, sizeof(symbol_type));
memset(&mDummyRegion, 0, sizeof(region_type));
@@ -139,7 +136,6 @@ CallStack<FRAME, BASE>::CallStack(int id, int numFrames, TraceReaderType *trace)
memset(&mUserEvent, 0, sizeof(BBEvent));
mSkippedTime = 0;
mLastRunTime = 0;
- mJavaTop = 0;
// Read the first two methods from the trace if we haven't already read
// from the method trace yet.
@@ -169,11 +165,29 @@ CallStack<FRAME, BASE>::updateStack(BBEvent *event, symbol_type *function)
// instead.
if (function->vm_sym != NULL)
function = function->vm_sym;
+ } else {
+ doMethodAction(event, function);
}
Action action = getAction(event, function);
- Action methodAction = getMethodAction(event, function);
+ // Allow native frames if we are executing in the kernel.
+ if (!mAllowNativeFrames
+ && (function->region->flags & region_type::kIsKernelRegion) == 0) {
+ action = NONE;
+ }
+
+ if (function->vm_sym != NULL) {
+ function = function->vm_sym;
+ function->vm_sym = NULL;
+ }
+ if (action == PUSH) {
+ doPush(event, function);
+ } else if (action == POP) {
+ doPop(event, function, NONE);
+ }
+
+#if 0
// Pop off native functions before pushing or popping Java methods.
if (action == POP && mPrevFunction->vm_sym == NULL) {
// Pop off the previous function first.
@@ -198,11 +212,16 @@ CallStack<FRAME, BASE>::updateStack(BBEvent *event, symbol_type *function)
doPush(event, function);
}
}
+#endif
// If the stack is now empty, then push the current function.
if (mTop == 0) {
uint64_t time = event->time - mSkippedTime;
- doSimplePush(function, 0, time);
+ int flags = 0;
+ if (function->vm_sym != NULL) {
+ flags = FRAME::kInterpreted;
+ }
+ doSimplePush(function, 0, time, 0);
}
mPrevFunction = function;
@@ -465,12 +484,19 @@ void CallStack<FRAME, BASE>::doPush(BBEvent *event, symbol_type *function)
if ((function->flags & symbol_type::kIsVectorStart) && mTop > 0)
mFrames[mTop - 1].flags |= FRAME::kCausedException;
- doSimplePush(function, retAddr, time);
+ // If the function being pushed is a Java method, then mark it on
+ // the stack so that we don't pop it off until we get a matching
+ // trace record from the method trace file.
+ int flags = 0;
+ if (function->vm_sym != NULL) {
+ flags = FRAME::kInterpreted;
+ }
+ doSimplePush(function, retAddr, time, flags);
}
template<class FRAME, class BASE>
-void CallStack<FRAME, BASE>::doSimplePush(symbol_type *function,
- uint32_t addr, uint64_t time)
+void CallStack<FRAME, BASE>::doSimplePush(symbol_type *function, uint32_t addr,
+ uint64_t time, int flags)
{
// Check for stack overflow
if (mTop >= mNumFrames) {
@@ -479,30 +505,12 @@ void CallStack<FRAME, BASE>::doSimplePush(symbol_type *function,
exit(1);
}
- // Keep track of the number of Java methods we push on the stack.
- if (!mNativeOnly && function->vm_sym != NULL) {
- // If we are pushing the first Java method on the stack, then
- // save a snapshot of the stack so that we can clean things up
- // later when we pop off the last Java stack frame.
- if (mJavaTop == 0) {
- transitionToJava();
- }
- mJavaTop += 1;
- }
-
mFrames[mTop].addr = addr;
mFrames[mTop].function = function;
- mFrames[mTop].flags = 0;
+ mFrames[mTop].flags = flags;
mFrames[mTop].time = time;
mFrames[mTop].global_time = time + mSkippedTime;
- // If the function being pushed is a Java method, then mark it on
- // the stack so that we don't pop it off until we get a matching
- // trace record from the method trace file.
- if (function->vm_sym != NULL) {
- mFrames[mTop].flags = FRAME::kInterpreted;
- }
-
mFrames[mTop].push(mTop, time, this);
mTop += 1;
}
@@ -517,17 +525,25 @@ void CallStack<FRAME, BASE>::doSimplePop(uint64_t time)
mTop -= 1;
mFrames[mTop].pop(mTop, time, this);
- // Keep track of the number of Java methods we have on the stack.
- symbol_type *function = mFrames[mTop].function;
- if (!mNativeOnly && function->vm_sym != NULL) {
- mJavaTop -= 1;
-
- // When there are no more Java stack frames, then clean up
- // the client's stack. We need to do this because the client
- // doesn't see the changes to the native stack underlying the
- // fake Java stack until the last Java method is popped off.
- if (mJavaTop == 0) {
- transitionFromJava(time);
+ if (mNativeOnly)
+ return;
+
+ // If the stack is empty, then allow more native frames.
+ // Otherwise, if we are transitioning from Java to native, then allow
+ // more native frames.
+ // Otherwise, if we are transitioning from native to Java, then disallow
+ // more native frames.
+ if (mTop == 0) {
+ mAllowNativeFrames = true;
+ } else {
+ bool newerIsJava = (mFrames[mTop].flags & FRAME::kInterpreted) != 0;
+ bool olderIsJava = (mFrames[mTop - 1].flags & FRAME::kInterpreted) != 0;
+ if (newerIsJava && !olderIsJava) {
+ // We are transitioning from Java to native
+ mAllowNativeFrames = true;
+ } else if (!newerIsJava && olderIsJava) {
+ // We are transitioning from native to Java
+ mAllowNativeFrames = false;
}
}
}
@@ -671,20 +687,45 @@ void CallStack<FRAME, BASE>::popAll(uint64_t time)
}
template<class FRAME, class BASE>
-typename CallStack<FRAME, BASE>::Action
-CallStack<FRAME, BASE>::getMethodAction(BBEvent *event, symbol_type *function)
+void CallStack<FRAME, BASE>::doMethodPop(BBEvent *event, uint32_t addr,
+ const uint32_t flags)
{
- if (function->vm_sym == NULL && mPrevFunction->vm_sym == NULL) {
- return NONE;
+ uint64_t time = event->time - mSkippedTime;
+
+ // Search the stack from the top down for a frame that contains a
+ // matching method.
+ int stackLevel;
+ for (stackLevel = mTop - 1; stackLevel >= 0; --stackLevel) {
+ if (mFrames[stackLevel].flags & flags) {
+ // If we are searching for a native method, then don't bother trying
+ // to match the address.
+ if (flags == FRAME::kStartNative)
+ break;
+ symbol_type *func = mFrames[stackLevel].function;
+ uint32_t methodAddr = func->region->base_addr + func->addr;
+ if (methodAddr == addr) {
+ break;
+ }
+ }
}
- Action action = NONE;
- uint32_t prevAddr = mPrevFunction->addr + mPrevFunction->region->base_addr;
- uint32_t addr = function->addr + function->region->base_addr;
+ // If we found a matching frame then pop the stack up to and including
+ // that frame.
+ if (stackLevel >= 0) {
+ // Pop the stack frames
+ for (int ii = mTop - 1; ii >= stackLevel; --ii)
+ doSimplePop(time);
+ }
+}
+template<class FRAME, class BASE>
+void CallStack<FRAME, BASE>::doMethodAction(BBEvent *event, symbol_type *function)
+{
// If the events get ahead of the method trace, then read ahead until we
// sync up again. This can happen if there is a pop of a method in the
- // method trace for which we don't have a previous push.
+ // method trace for which we don't have a previous push. Such an unmatched
+ // pop can happen because the user can start tracing at any time and so
+ // there might already be a stack when we start tracing.
while (event->time >= sNextMethod.time) {
sCurrentMethod = sNextMethod;
if (mTrace->ReadMethod(&sNextMethod)) {
@@ -693,59 +734,26 @@ CallStack<FRAME, BASE>::getMethodAction(BBEvent *event, symbol_type *function)
}
if (event->time >= sCurrentMethod.time && event->pid == sCurrentMethod.pid) {
- if (addr == sCurrentMethod.addr || prevAddr == sCurrentMethod.addr) {
- action = (sCurrentMethod.flags == 0) ? PUSH : POP;
- // We found a match, so read the next record.
- sCurrentMethod = sNextMethod;
- if (sNextMethod.time != ~0ull && mTrace->ReadMethod(&sNextMethod)) {
- sNextMethod.time = ~0ull;
- }
- }
- }
- return action;
-}
-
-// When the first Java method is pushed on the stack, this method is
-// called to save a snapshot of the current native stack so that the
-// client's view of the native stack can be patched up later when the
-// Java stack is empty.
-template<class FRAME, class BASE>
-void CallStack<FRAME, BASE>::transitionToJava()
-{
- mSnapshotTop = mTop;
- for (int ii = 0; ii < mTop; ++ii) {
- mSnapshotFrames[ii] = mFrames[ii];
- }
-}
-
-// When the Java stack becomes empty, the native stack becomes
-// visible. This method is called when the Java stack becomes empty
-// to patch up the client's view of the native stack, which may have
-// changed underneath the Java stack. The stack snapshot is used to
-// create a sequence of pops and pushes to make the client's view of
-// the native stack match the current native stack.
-template<class FRAME, class BASE>
-void CallStack<FRAME, BASE>::transitionFromJava(uint64_t time)
-{
- int top = mTop;
- if (top > mSnapshotTop) {
- top = mSnapshotTop;
- }
- for (int ii = 0; ii < top; ++ii) {
- if (mSnapshotFrames[ii].function->addr == mFrames[ii].function->addr) {
- continue;
- }
-
- // Pop off all the rest of the frames from the snapshot
- for (int jj = top - 1; jj >= ii; --jj) {
- mSnapshotFrames[jj].pop(jj, time, this);
+ uint64_t time = event->time - mSkippedTime;
+ int flags = sCurrentMethod.flags;
+ if (flags == kMethodEnter) {
+ doSimplePush(function, 0, time, FRAME::kInterpreted);
+ mAllowNativeFrames = false;
+ } else if (flags == kNativeEnter) {
+ doSimplePush(function, 0, time, FRAME::kStartNative);
+ mAllowNativeFrames = true;
+ } else if (flags == kMethodExit || flags == kMethodException) {
+ doMethodPop(event, sCurrentMethod.addr, FRAME::kInterpreted);
+ } else if (flags == kNativeExit || flags == kNativeException) {
+ doMethodPop(event, sCurrentMethod.addr, FRAME::kStartNative);
}
- // Push the new frames from the native stack
- for (int jj = ii; jj < mTop; ++jj) {
- mFrames[jj].push(jj, time, this);
+ // We found a match, so read the next record. When we get to the end
+ // of the trace, we set the time to the maximum value (~0).
+ sCurrentMethod = sNextMethod;
+ if (sNextMethod.time != ~0ull && mTrace->ReadMethod(&sNextMethod)) {
+ sNextMethod.time = ~0ull;
}
- break;
}
}
@@ -764,16 +772,4 @@ void CallStack<FRAME, BASE>::showStack(FILE *stream)
}
}
-template<class FRAME, class BASE>
-void CallStack<FRAME, BASE>::showSnapshotStack(FILE *stream)
-{
- fprintf(stream, "mSnapshotTop: %d\n", mSnapshotTop);
- for (int ii = 0; ii < mSnapshotTop; ++ii) {
- fprintf(stream, " %d: t %d f %x 0x%08x 0x%08x %s\n",
- ii, mSnapshotFrames[ii].time, mSnapshotFrames[ii].flags,
- mSnapshotFrames[ii].addr, mSnapshotFrames[ii].function->addr,
- mSnapshotFrames[ii].function->name);
- }
-}
-
#endif /* CALL_STACK_H */