Index: src/frames.cc |
diff --git a/src/frames.cc b/src/frames.cc |
index 327079705b007414cd665ed86f996635f442abf4..763ff486eff0d804e4d98bde5d6de5832c4bfe92 100644 |
--- a/src/frames.cc |
+++ b/src/frames.cc |
@@ -66,23 +66,32 @@ class StackHandlerIterator BASE_EMBEDDED { |
#define INITIALIZE_SINGLETON(type, field) field##_(this), |
StackFrameIterator::StackFrameIterator() |
: STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON) |
- frame_(NULL), handler_(NULL), thread_(Top::GetCurrentThread()) { |
+ frame_(NULL), handler_(NULL), thread_(Top::GetCurrentThread()), |
+ fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) { |
Reset(); |
} |
StackFrameIterator::StackFrameIterator(ThreadLocalTop* t) |
: STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON) |
- frame_(NULL), handler_(NULL), thread_(t) { |
+ frame_(NULL), handler_(NULL), thread_(t), |
+ fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) { |
Reset(); |
} |
-StackFrameIterator::StackFrameIterator(bool reset) |
+StackFrameIterator::StackFrameIterator(bool use_top, Address fp, Address sp) |
: STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON) |
- frame_(NULL), handler_(NULL), thread_(Top::GetCurrentThread()) { |
- if (reset) Reset(); |
+ frame_(NULL), handler_(NULL), |
+ thread_(use_top ? Top::GetCurrentThread() : NULL), |
+ fp_(use_top ? NULL : fp), sp_(sp), |
+ advance_(use_top ? &StackFrameIterator::AdvanceWithHandler : |
+ &StackFrameIterator::AdvanceWithoutHandler) { |
+ if (use_top || fp != NULL) { |
+ Reset(); |
+ } |
} |
+ |
#undef INITIALIZE_SINGLETON |
-void StackFrameIterator::Advance() { |
+void StackFrameIterator::AdvanceWithHandler() { |
ASSERT(!done()); |
// Compute the state of the calling frame before restoring |
// callee-saved registers and unwinding handlers. This allows the |
@@ -105,17 +114,45 @@ void StackFrameIterator::Advance() { |
} |
+void StackFrameIterator::AdvanceWithoutHandler() { |
+ // A simpler version of Advance which doesn't care about handler. |
+ ASSERT(!done()); |
+ StackFrame::State state; |
+ StackFrame::Type type = frame_->GetCallerState(&state); |
+ frame_ = SingletonFor(type, &state); |
+} |
+ |
+ |
void StackFrameIterator::Reset() { |
- Address fp = Top::c_entry_fp(thread_); |
StackFrame::State state; |
- StackFrame::Type type = ExitFrame::GetStateForFramePointer(fp, &state); |
+ StackFrame::Type type; |
+ if (thread_ != NULL) { |
+ type = ExitFrame::GetStateForFramePointer(Top::c_entry_fp(thread_), &state); |
+ handler_ = StackHandler::FromAddress(Top::handler(thread_)); |
+ } else { |
+ ASSERT(fp_ != NULL); |
+ state.fp = fp_; |
+ state.sp = sp_; |
+ state.pc_address = |
+ reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp_)); |
+ type = StackFrame::ComputeType(&state); |
+ if (SingletonFor(type) == NULL) return; |
+ } |
frame_ = SingletonFor(type, &state); |
- handler_ = StackHandler::FromAddress(Top::handler(thread_)); |
} |
StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type, |
StackFrame::State* state) { |
+ if (type == StackFrame::NONE) return NULL; |
+ StackFrame* result = SingletonFor(type); |
+ ASSERT(result != NULL); |
+ result->state_ = *state; |
+ return result; |
+} |
+ |
+ |
+StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type) { |
#define FRAME_TYPE_CASE(type, field) \ |
case StackFrame::type: result = &field##_; break; |
@@ -125,8 +162,6 @@ StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type, |
STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE) |
default: break; |
} |
- ASSERT(result != NULL); |
- result->state_ = *state; |
return result; |
#undef FRAME_TYPE_CASE |
@@ -154,29 +189,50 @@ void StackTraceFrameIterator::Advance() { |
SafeStackFrameIterator::SafeStackFrameIterator( |
- Address low_bound, Address high_bound) : |
+ Address fp, Address sp, Address low_bound, Address high_bound) : |
low_bound_(low_bound), high_bound_(high_bound), |
- is_working_iterator_(IsInBounds(low_bound, high_bound, |
- Top::c_entry_fp(Top::GetCurrentThread()))), |
- iteration_done_(!is_working_iterator_), iterator_(is_working_iterator_) { |
+ is_valid_top_( |
+ IsWithinBounds(low_bound, high_bound, |
+ Top::c_entry_fp(Top::GetCurrentThread())) && |
+ Top::handler(Top::GetCurrentThread()) != NULL), |
+ is_valid_fp_(IsWithinBounds(low_bound, high_bound, fp)), |
+ is_working_iterator_(is_valid_top_ || is_valid_fp_), |
+ iteration_done_(!is_working_iterator_), |
+ iterator_(is_valid_top_, is_valid_fp_ ? fp : NULL, sp) { |
} |
void SafeStackFrameIterator::Advance() { |
ASSERT(is_working_iterator_); |
ASSERT(!done()); |
- StackFrame* frame = iterator_.frame(); |
- iteration_done_ = |
- !IsGoodStackAddress(frame->sp()) || !IsGoodStackAddress(frame->fp()); |
- if (!iteration_done_) { |
- iterator_.Advance(); |
- if (!iterator_.done()) { |
- // Check that we have actually moved to the previous frame in the stack |
- StackFrame* prev_frame = iterator_.frame(); |
- iteration_done_ = |
- prev_frame->sp() < frame->sp() || prev_frame->fp() < frame->fp(); |
- } |
- } |
+ StackFrame* last_frame = iterator_.frame(); |
+ Address last_sp = last_frame->sp(), last_fp = last_frame->fp(); |
+ // Before advancing to the next stack frame, perform pointer validity tests |
+ iteration_done_ = !IsValidFrame(last_frame) || !IsValidCaller(last_frame); |
+ if (iteration_done_) return; |
+ |
+ iterator_.Advance(); |
+ if (iterator_.done()) return; |
+ // Check that we have actually moved to the previous frame in the stack |
+ StackFrame* prev_frame = iterator_.frame(); |
+ iteration_done_ = prev_frame->sp() < last_sp || prev_frame->fp() < last_fp; |
+} |
+ |
+ |
+bool SafeStackFrameIterator::IsValidFrame(StackFrame* frame) const { |
+ return IsValidStackAddress(frame->sp()) && IsValidStackAddress(frame->fp()) && |
+ // JavaScriptFrame uses function shared info to advance, hence it must |
+ // point to a valid function object. |
+ (!frame->is_java_script() || |
+ reinterpret_cast<JavaScriptFrame*>(frame)->is_at_function()); |
+} |
+ |
+ |
+bool SafeStackFrameIterator::IsValidCaller(StackFrame* frame) { |
+ StackFrame::State state; |
+ frame->ComputeCallerState(&state); |
+ return IsValidStackAddress(state.sp) && IsValidStackAddress(state.fp) && |
+ iterator_.SingletonFor(frame->GetCallerState(&state)) != NULL; |
} |
@@ -193,9 +249,9 @@ void SafeStackFrameIterator::Reset() { |
#ifdef ENABLE_LOGGING_AND_PROFILING |
SafeStackTraceFrameIterator::SafeStackTraceFrameIterator( |
- Address low_bound, Address high_bound) : |
- SafeJavaScriptFrameIterator(low_bound, high_bound) { |
- if (!done() && !frame()->function()->IsJSFunction()) Advance(); |
+ Address fp, Address sp, Address low_bound, Address high_bound) : |
+ SafeJavaScriptFrameIterator(fp, sp, low_bound, high_bound) { |
+ if (!done() && !frame()->is_at_function()) Advance(); |
} |
@@ -203,7 +259,7 @@ void SafeStackTraceFrameIterator::Advance() { |
while (true) { |
SafeJavaScriptFrameIterator::Advance(); |
if (done()) return; |
- if (frame()->function()->IsJSFunction()) return; |
+ if (frame()->is_at_function()) return; |
} |
} |
#endif |
@@ -279,11 +335,22 @@ void StackFrame::Uncook() { |
} |
+StackFrame::Type StackFrame::GetCallerState(State* state) const { |
+ ComputeCallerState(state); |
+ return ComputeType(state); |
+} |
+ |
+ |
Code* EntryFrame::code() const { |
return Heap::js_entry_code(); |
} |
+void EntryFrame::ComputeCallerState(State* state) const { |
+ GetCallerState(state); |
+} |
+ |
+ |
StackFrame::Type EntryFrame::GetCallerState(State* state) const { |
const int offset = EntryFrameConstants::kCallerFPOffset; |
Address fp = Memory::Address_at(this->fp() + offset); |
@@ -301,13 +368,12 @@ Code* ExitFrame::code() const { |
} |
-StackFrame::Type ExitFrame::GetCallerState(State* state) const { |
+void ExitFrame::ComputeCallerState(State* state) const { |
// Setup the caller state. |
state->sp = pp(); |
state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset); |
state->pc_address |
= reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset); |
- return ComputeType(state); |
} |
@@ -338,11 +404,10 @@ int StandardFrame::ComputeExpressionsCount() const { |
} |
-StackFrame::Type StandardFrame::GetCallerState(State* state) const { |
+void StandardFrame::ComputeCallerState(State* state) const { |
state->sp = caller_sp(); |
state->fp = caller_fp(); |
state->pc_address = reinterpret_cast<Address*>(ComputePCAddress(fp())); |
- return ComputeType(state); |
} |