Index: src/frames.cc |
diff --git a/src/frames.cc b/src/frames.cc |
index 890e77ad63608f7bb178bfd4693146858a9533b2..85293f5b7f974098d1b3b403b8db4ea0e6667098 100644 |
--- a/src/frames.cc |
+++ b/src/frames.cc |
@@ -36,6 +36,7 @@ |
#include "safepoint-table.h" |
#include "scopeinfo.h" |
#include "string-stream.h" |
+#include "vm-state-inl.h" |
#include "allocation-inl.h" |
@@ -221,7 +222,8 @@ SafeStackFrameIterator::SafeStackFrameIterator( |
: StackFrameIteratorBase(isolate, false), |
low_bound_(sp), |
high_bound_(js_entry_sp), |
- top_frame_type_(StackFrame::NONE) { |
+ top_frame_type_(StackFrame::NONE), |
+ external_callback_scope_(isolate->external_callback_scope()) { |
StackFrame::State state; |
StackFrame::Type type; |
ThreadLocalTop* top = isolate->thread_local_top(); |
@@ -256,16 +258,28 @@ SafeStackFrameIterator::SafeStackFrameIterator( |
} |
if (SingletonFor(type) == NULL) return; |
frame_ = SingletonFor(type, &state); |
+ if (frame_ == NULL) return; |
+ |
+ Advance(); |
- if (!done()) Advance(); |
+ if (frame_ != NULL && !frame_->is_exit() && |
+ external_callback_scope_ != NULL && |
+ external_callback_scope_->scope_address() < frame_->fp()) { |
+ // Skip top ExternalCallbackScope if we already advanced to a JS frame |
+ // under it. Sampler will anyways take this top external callback. |
+ external_callback_scope_ = external_callback_scope_->previous(); |
+ } |
} |
bool SafeStackFrameIterator::IsValidTop(ThreadLocalTop* top) const { |
- Address fp = Isolate::c_entry_fp(top); |
- if (!IsValidExitFrame(fp)) return false; |
+ Address c_entry_fp = Isolate::c_entry_fp(top); |
+ if (!IsValidExitFrame(c_entry_fp)) return false; |
// There should be at least one JS_ENTRY stack handler. |
- return Isolate::handler(top) != NULL; |
+ Address handler = Isolate::handler(top); |
+ if (handler == NULL) return false; |
+ // Check that there are no js frames on top of the native frames. |
+ return c_entry_fp < handler; |
} |
@@ -340,6 +354,24 @@ void SafeStackFrameIterator::Advance() { |
AdvanceOneFrame(); |
if (done()) return; |
if (frame_->is_java_script()) return; |
+ if (frame_->is_exit() && external_callback_scope_) { |
+ // Some of the EXIT frames may have ExternalCallbackScope allocated on |
+ // top of them. In that case the scope corresponds to the first EXIT |
+ // frame beneath it. There may be other EXIT frames on top of the |
+ // ExternalCallbackScope, just skip them as we cannot collect any useful |
+ // information about them. |
+ if (external_callback_scope_->scope_address() < frame_->fp()) { |
+ Address* callback_address = |
+ external_callback_scope_->callback_address(); |
+ if (*callback_address != NULL) { |
+ frame_->state_.pc_address = callback_address; |
+ } |
+ external_callback_scope_ = external_callback_scope_->previous(); |
+ ASSERT(external_callback_scope_ == NULL || |
+ external_callback_scope_->scope_address() > frame_->fp()); |
+ return; |
+ } |
+ } |
} |
} |