Extract StackFrameIteratorBase

This change introduces StackFrameIteratorBase which owns singleton frame instances and encapsulates some basic iterator functionality. It has two actual implementations: StackFrameIterator and SafeStackFrameIterator.

All logic specific to frame iteration at a random point (basically checks that fp and sp extracted from stack frames are within current stack boundaries) used only by CPU profiler is now concentrated in SafeStackFrameIterator.

Generic stack iteration used in all other places is put into StackFrameIterator. Also this iterator unlike SafeStackFrameIterator iterates through stack handlers.

StackAddressValidator and ExitFrameValidator classes were removed in favor of inline checks and simple methods.

BUG=None
R=loislo@chromium.org, svenpanne@chromium.org

Review URL: https://codereview.chromium.org/17819003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15349 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
yurys@chromium.org 2013-06-27 09:34:31 +00:00
parent 4aeccdb23e
commit 52d848bce7
3 changed files with 153 additions and 207 deletions

View File

@ -116,7 +116,7 @@ inline Object** StackHandler::code_address() const {
} }
inline StackFrame::StackFrame(StackFrameIterator* iterator) inline StackFrame::StackFrame(StackFrameIteratorBase* iterator)
: iterator_(iterator), isolate_(iterator_->isolate()) { : iterator_(iterator), isolate_(iterator_->isolate()) {
} }
@ -136,22 +136,23 @@ inline Code* StackFrame::GetContainingCode(Isolate* isolate, Address pc) {
} }
inline EntryFrame::EntryFrame(StackFrameIterator* iterator) inline EntryFrame::EntryFrame(StackFrameIteratorBase* iterator)
: StackFrame(iterator) { : StackFrame(iterator) {
} }
inline EntryConstructFrame::EntryConstructFrame(StackFrameIterator* iterator) inline EntryConstructFrame::EntryConstructFrame(
StackFrameIteratorBase* iterator)
: EntryFrame(iterator) { : EntryFrame(iterator) {
} }
inline ExitFrame::ExitFrame(StackFrameIterator* iterator) inline ExitFrame::ExitFrame(StackFrameIteratorBase* iterator)
: StackFrame(iterator) { : StackFrame(iterator) {
} }
inline StandardFrame::StandardFrame(StackFrameIterator* iterator) inline StandardFrame::StandardFrame(StackFrameIteratorBase* iterator)
: StackFrame(iterator) { : StackFrame(iterator) {
} }
@ -201,7 +202,7 @@ inline bool StandardFrame::IsConstructFrame(Address fp) {
} }
inline JavaScriptFrame::JavaScriptFrame(StackFrameIterator* iterator) inline JavaScriptFrame::JavaScriptFrame(StackFrameIteratorBase* iterator)
: StandardFrame(iterator) { : StandardFrame(iterator) {
} }
@ -269,32 +270,32 @@ inline Object* JavaScriptFrame::function() const {
} }
inline StubFrame::StubFrame(StackFrameIterator* iterator) inline StubFrame::StubFrame(StackFrameIteratorBase* iterator)
: StandardFrame(iterator) { : StandardFrame(iterator) {
} }
inline OptimizedFrame::OptimizedFrame(StackFrameIterator* iterator) inline OptimizedFrame::OptimizedFrame(StackFrameIteratorBase* iterator)
: JavaScriptFrame(iterator) { : JavaScriptFrame(iterator) {
} }
inline ArgumentsAdaptorFrame::ArgumentsAdaptorFrame( inline ArgumentsAdaptorFrame::ArgumentsAdaptorFrame(
StackFrameIterator* iterator) : JavaScriptFrame(iterator) { StackFrameIteratorBase* iterator) : JavaScriptFrame(iterator) {
} }
inline InternalFrame::InternalFrame(StackFrameIterator* iterator) inline InternalFrame::InternalFrame(StackFrameIteratorBase* iterator)
: StandardFrame(iterator) { : StandardFrame(iterator) {
} }
inline StubFailureTrampolineFrame::StubFailureTrampolineFrame( inline StubFailureTrampolineFrame::StubFailureTrampolineFrame(
StackFrameIterator* iterator) : StandardFrame(iterator) { StackFrameIteratorBase* iterator) : StandardFrame(iterator) {
} }
inline ConstructFrame::ConstructFrame(StackFrameIterator* iterator) inline ConstructFrame::ConstructFrame(StackFrameIteratorBase* iterator)
: InternalFrame(iterator) { : InternalFrame(iterator) {
} }
@ -325,14 +326,9 @@ inline JavaScriptFrame* JavaScriptFrameIterator::frame() const {
inline JavaScriptFrame* SafeStackFrameIterator::frame() const { inline JavaScriptFrame* SafeStackFrameIterator::frame() const {
ASSERT(!iteration_done_); ASSERT(!done());
// TODO(1233797): The frame hierarchy needs to change. It's ASSERT(frame_->is_java_script());
// problematic that we can't use the safe-cast operator to cast to return static_cast<JavaScriptFrame*>(frame_);
// the JavaScript frame type, because we may encounter arguments
// adaptor frames.
StackFrame* frame = iterator_.frame();
ASSERT(frame->is_java_script());
return static_cast<JavaScriptFrame*>(frame);
} }

View File

@ -88,41 +88,29 @@ class StackHandlerIterator BASE_EMBEDDED {
#define INITIALIZE_SINGLETON(type, field) field##_(this), #define INITIALIZE_SINGLETON(type, field) field##_(this),
StackFrameIterator::StackFrameIterator(Isolate* isolate) StackFrameIteratorBase::StackFrameIteratorBase(Isolate* isolate,
bool can_access_heap_objects)
: isolate_(isolate), : isolate_(isolate),
STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON) STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
frame_(NULL), handler_(NULL), frame_(NULL), handler_(NULL),
thread_(isolate_->thread_local_top()), can_access_heap_objects_(can_access_heap_objects) {
fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler),
can_access_heap_objects_(true) {
Reset();
} }
StackFrameIterator::StackFrameIterator(Isolate* isolate, ThreadLocalTop* t)
: isolate_(isolate),
STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
frame_(NULL), handler_(NULL), thread_(t),
fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler),
can_access_heap_objects_(true) {
Reset();
}
StackFrameIterator::StackFrameIterator(Isolate* isolate,
bool use_top, Address fp, Address sp)
: isolate_(isolate),
STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
frame_(NULL), handler_(NULL),
thread_(use_top ? isolate_->thread_local_top() : NULL),
fp_(use_top ? NULL : fp), sp_(sp),
advance_(&StackFrameIterator::AdvanceWithoutHandler),
can_access_heap_objects_(false) {
if (use_top || fp != NULL) {
Reset();
}
}
#undef INITIALIZE_SINGLETON #undef INITIALIZE_SINGLETON
void StackFrameIterator::AdvanceWithHandler() { StackFrameIterator::StackFrameIterator(Isolate* isolate)
: StackFrameIteratorBase(isolate, true) {
Reset(isolate->thread_local_top());
}
StackFrameIterator::StackFrameIterator(Isolate* isolate, ThreadLocalTop* t)
: StackFrameIteratorBase(isolate, true) {
Reset(t);
}
void StackFrameIterator::Advance() {
ASSERT(!done()); ASSERT(!done());
// Compute the state of the calling frame before restoring // Compute the state of the calling frame before restoring
// callee-saved registers and unwinding handlers. This allows the // callee-saved registers and unwinding handlers. This allows the
@ -145,37 +133,17 @@ void StackFrameIterator::AdvanceWithHandler() {
} }
void StackFrameIterator::AdvanceWithoutHandler() { void StackFrameIterator::Reset(ThreadLocalTop* top) {
// A simpler version of Advance which doesn't care about handler.
ASSERT(!done());
StackFrame::State state; StackFrame::State state;
StackFrame::Type type = frame_->GetCallerState(&state); StackFrame::Type type = ExitFrame::GetStateForFramePointer(
frame_ = SingletonFor(type, &state); Isolate::c_entry_fp(top), &state);
} handler_ = StackHandler::FromAddress(Isolate::handler(top));
void StackFrameIterator::Reset() {
StackFrame::State state;
StackFrame::Type type;
if (thread_ != NULL) {
type = ExitFrame::GetStateForFramePointer(
Isolate::c_entry_fp(thread_), &state);
handler_ = StackHandler::FromAddress(
Isolate::handler(thread_));
} else {
ASSERT(fp_ != NULL);
state.fp = fp_;
state.sp = sp_;
state.pc_address = ResolveReturnAddressLocation(
reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp_)));
type = StackFrame::ComputeType(this, &state);
}
if (SingletonFor(type) == NULL) return; if (SingletonFor(type) == NULL) return;
frame_ = SingletonFor(type, &state); frame_ = SingletonFor(type, &state);
} }
StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type, StackFrame* StackFrameIteratorBase::SingletonFor(StackFrame::Type type,
StackFrame::State* state) { StackFrame::State* state) {
if (type == StackFrame::NONE) return NULL; if (type == StackFrame::NONE) return NULL;
StackFrame* result = SingletonFor(type); StackFrame* result = SingletonFor(type);
@ -185,7 +153,7 @@ StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type,
} }
StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type) { StackFrame* StackFrameIteratorBase::SingletonFor(StackFrame::Type type) {
#define FRAME_TYPE_CASE(type, field) \ #define FRAME_TYPE_CASE(type, field) \
case StackFrame::type: result = &field##_; break; case StackFrame::type: result = &field##_; break;
@ -257,55 +225,61 @@ bool StackTraceFrameIterator::IsValidFrame() {
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
bool SafeStackFrameIterator::ExitFrameValidator::IsValidFP(Address fp) {
if (!validator_.IsValid(fp)) return false;
Address sp = ExitFrame::ComputeStackPointer(fp);
if (!validator_.IsValid(sp)) return false;
StackFrame::State state;
ExitFrame::FillState(fp, sp, &state);
if (!validator_.IsValid(reinterpret_cast<Address>(state.pc_address))) {
return false;
}
return *state.pc_address != NULL;
}
SafeStackFrameIterator::SafeStackFrameIterator( SafeStackFrameIterator::SafeStackFrameIterator(
Isolate* isolate, Isolate* isolate,
Address fp, Address sp, Address low_bound, Address high_bound) : Address fp, Address sp, Address low_bound, Address high_bound) :
stack_validator_(low_bound, high_bound), StackFrameIteratorBase(isolate, false),
is_valid_top_(IsValidTop(isolate, low_bound, high_bound)), low_bound_(low_bound), high_bound_(high_bound) {
is_valid_fp_(IsWithinBounds(low_bound, high_bound, fp)), StackFrame::State state;
iteration_done_(!is_valid_top_ && !is_valid_fp_), StackFrame::Type type;
iterator_(isolate, is_valid_top_, is_valid_fp_ ? fp : NULL, sp) { ThreadLocalTop* top = isolate->thread_local_top();
if (IsValidTop(top)) {
type = ExitFrame::GetStateForFramePointer(Isolate::c_entry_fp(top), &state);
} else if (IsValidStackAddress(fp)) {
ASSERT(fp != NULL);
state.fp = fp;
state.sp = sp;
state.pc_address = ResolveReturnAddressLocation(
reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp)));
type = StackFrame::ComputeType(this, &state);
} else {
return;
}
if (SingletonFor(type) == NULL) return;
frame_ = SingletonFor(type, &state);
if (!done()) Advance(); if (!done()) Advance();
} }
bool SafeStackFrameIterator::IsValidTop(Isolate* isolate, bool SafeStackFrameIterator::IsValidTop(ThreadLocalTop* top) const {
Address low_bound, Address high_bound) {
ThreadLocalTop* top = isolate->thread_local_top();
Address fp = Isolate::c_entry_fp(top); Address fp = Isolate::c_entry_fp(top);
ExitFrameValidator validator(low_bound, high_bound); if (!IsValidExitFrame(fp)) return false;
if (!validator.IsValidFP(fp)) return false; // There should be at least one JS_ENTRY stack handler.
return Isolate::handler(top) != NULL; return Isolate::handler(top) != NULL;
} }
void SafeStackFrameIterator::AdvanceOneFrame() { void SafeStackFrameIterator::AdvanceOneFrame() {
ASSERT(!done()); ASSERT(!done());
StackFrame* last_frame = iterator_.frame(); StackFrame* last_frame = frame_;
Address last_sp = last_frame->sp(), last_fp = last_frame->fp(); Address last_sp = last_frame->sp(), last_fp = last_frame->fp();
// Before advancing to the next stack frame, perform pointer validity tests // Before advancing to the next stack frame, perform pointer validity tests.
iteration_done_ = !IsValidFrame(last_frame) || if (!IsValidFrame(last_frame) || !IsValidCaller(last_frame)) {
!IsValidCaller(last_frame); frame_ = NULL;
if (iteration_done_) return; return;
}
iterator_.Advance(); // Advance to the previous frame.
if (iterator_.done()) return; StackFrame::State state;
// Check that we have actually moved to the previous frame in the stack StackFrame::Type type = frame_->GetCallerState(&state);
StackFrame* prev_frame = iterator_.frame(); frame_ = SingletonFor(type, &state);
iteration_done_ = prev_frame->sp() < last_sp || prev_frame->fp() < last_fp; if (frame_ == NULL) return;
// Check that we have actually moved to the previous frame in the stack.
if (frame_->sp() < last_sp || frame_->fp() < last_fp) {
frame_ = NULL;
}
} }
@ -322,8 +296,7 @@ bool SafeStackFrameIterator::IsValidCaller(StackFrame* frame) {
// sure that caller FP address is valid. // sure that caller FP address is valid.
Address caller_fp = Memory::Address_at( Address caller_fp = Memory::Address_at(
frame->fp() + EntryFrameConstants::kCallerFPOffset); frame->fp() + EntryFrameConstants::kCallerFPOffset);
ExitFrameValidator validator(stack_validator_); if (!IsValidExitFrame(caller_fp)) return false;
if (!validator.IsValidFP(caller_fp)) return false;
} else if (frame->is_arguments_adaptor()) { } else if (frame->is_arguments_adaptor()) {
// See ArgumentsAdaptorFrame::GetCallerStackPointer. It assumes that // See ArgumentsAdaptorFrame::GetCallerStackPointer. It assumes that
// the number of arguments is stored on stack as Smi. We need to check // the number of arguments is stored on stack as Smi. We need to check
@ -336,7 +309,20 @@ bool SafeStackFrameIterator::IsValidCaller(StackFrame* frame) {
} }
frame->ComputeCallerState(&state); frame->ComputeCallerState(&state);
return IsValidStackAddress(state.sp) && IsValidStackAddress(state.fp) && return IsValidStackAddress(state.sp) && IsValidStackAddress(state.fp) &&
iterator_.SingletonFor(frame->GetCallerState(&state)) != NULL; SingletonFor(frame->GetCallerState(&state)) != NULL;
}
bool SafeStackFrameIterator::IsValidExitFrame(Address fp) const {
if (!IsValidStackAddress(fp)) return false;
Address sp = ExitFrame::ComputeStackPointer(fp);
if (!IsValidStackAddress(sp)) return false;
StackFrame::State state;
ExitFrame::FillState(fp, sp, &state);
if (!IsValidStackAddress(reinterpret_cast<Address>(state.pc_address))) {
return false;
}
return *state.pc_address != NULL;
} }
@ -344,7 +330,7 @@ void SafeStackFrameIterator::Advance() {
while (true) { while (true) {
AdvanceOneFrame(); AdvanceOneFrame();
if (done()) return; if (done()) return;
if (iterator_.frame()->is_java_script()) return; if (frame_->is_java_script()) return;
} }
} }
@ -408,7 +394,7 @@ void StackFrame::SetReturnAddressLocationResolver(
} }
StackFrame::Type StackFrame::ComputeType(const StackFrameIterator* iterator, StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator,
State* state) { State* state) {
ASSERT(state->fp != NULL); ASSERT(state->fp != NULL);
if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) { if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {

View File

@ -47,7 +47,7 @@ int JSCallerSavedCode(int n);
// Forward declarations. // Forward declarations.
class StackFrameIterator; class StackFrameIteratorBase;
class ThreadLocalTop; class ThreadLocalTop;
class Isolate; class Isolate;
@ -306,7 +306,7 @@ class StackFrame BASE_EMBEDDED {
Isolate* isolate() const { return isolate_; } Isolate* isolate() const { return isolate_; }
protected: protected:
inline explicit StackFrame(StackFrameIterator* iterator); inline explicit StackFrame(StackFrameIteratorBase* iterator);
virtual ~StackFrame() { } virtual ~StackFrame() { }
// Compute the stack pointer for the calling frame. // Compute the stack pointer for the calling frame.
@ -321,14 +321,14 @@ class StackFrame BASE_EMBEDDED {
inline StackHandler* top_handler() const; inline StackHandler* top_handler() const;
// Compute the stack frame type for the given state. // Compute the stack frame type for the given state.
static Type ComputeType(const StackFrameIterator* iterator, State* state); static Type ComputeType(const StackFrameIteratorBase* iterator, State* state);
#ifdef DEBUG #ifdef DEBUG
bool can_access_heap_objects() const; bool can_access_heap_objects() const;
#endif #endif
private: private:
const StackFrameIterator* iterator_; const StackFrameIteratorBase* iterator_;
Isolate* isolate_; Isolate* isolate_;
State state_; State state_;
@ -341,6 +341,7 @@ class StackFrame BASE_EMBEDDED {
static const intptr_t kIsolateTag = 1; static const intptr_t kIsolateTag = 1;
friend class StackFrameIterator; friend class StackFrameIterator;
friend class StackFrameIteratorBase;
friend class StackHandlerIterator; friend class StackHandlerIterator;
friend class SafeStackFrameIterator; friend class SafeStackFrameIterator;
@ -366,7 +367,7 @@ class EntryFrame: public StackFrame {
virtual void SetCallerFp(Address caller_fp); virtual void SetCallerFp(Address caller_fp);
protected: protected:
inline explicit EntryFrame(StackFrameIterator* iterator); inline explicit EntryFrame(StackFrameIteratorBase* iterator);
// The caller stack pointer for entry frames is always zero. The // The caller stack pointer for entry frames is always zero. The
// real information about the caller frame is available through the // real information about the caller frame is available through the
@ -377,7 +378,7 @@ class EntryFrame: public StackFrame {
virtual void ComputeCallerState(State* state) const; virtual void ComputeCallerState(State* state) const;
virtual Type GetCallerState(State* state) const; virtual Type GetCallerState(State* state) const;
friend class StackFrameIterator; friend class StackFrameIteratorBase;
}; };
@ -393,10 +394,10 @@ class EntryConstructFrame: public EntryFrame {
} }
protected: protected:
inline explicit EntryConstructFrame(StackFrameIterator* iterator); inline explicit EntryConstructFrame(StackFrameIteratorBase* iterator);
private: private:
friend class StackFrameIterator; friend class StackFrameIteratorBase;
}; };
@ -427,14 +428,14 @@ class ExitFrame: public StackFrame {
static void FillState(Address fp, Address sp, State* state); static void FillState(Address fp, Address sp, State* state);
protected: protected:
inline explicit ExitFrame(StackFrameIterator* iterator); inline explicit ExitFrame(StackFrameIteratorBase* iterator);
virtual Address GetCallerStackPointer() const; virtual Address GetCallerStackPointer() const;
private: private:
virtual void ComputeCallerState(State* state) const; virtual void ComputeCallerState(State* state) const;
friend class StackFrameIterator; friend class StackFrameIteratorBase;
}; };
@ -460,7 +461,7 @@ class StandardFrame: public StackFrame {
} }
protected: protected:
inline explicit StandardFrame(StackFrameIterator* iterator); inline explicit StandardFrame(StackFrameIteratorBase* iterator);
virtual void ComputeCallerState(State* state) const; virtual void ComputeCallerState(State* state) const;
@ -497,7 +498,7 @@ class StandardFrame: public StackFrame {
private: private:
friend class StackFrame; friend class StackFrame;
friend class StackFrameIterator; friend class SafeStackFrameIterator;
}; };
@ -603,7 +604,7 @@ class JavaScriptFrame: public StandardFrame {
bool print_line_number); bool print_line_number);
protected: protected:
inline explicit JavaScriptFrame(StackFrameIterator* iterator); inline explicit JavaScriptFrame(StackFrameIteratorBase* iterator);
virtual Address GetCallerStackPointer() const; virtual Address GetCallerStackPointer() const;
@ -616,7 +617,7 @@ class JavaScriptFrame: public StandardFrame {
private: private:
inline Object* function_slot_object() const; inline Object* function_slot_object() const;
friend class StackFrameIterator; friend class StackFrameIteratorBase;
}; };
@ -631,13 +632,13 @@ class StubFrame : public StandardFrame {
virtual Code* unchecked_code() const; virtual Code* unchecked_code() const;
protected: protected:
inline explicit StubFrame(StackFrameIterator* iterator); inline explicit StubFrame(StackFrameIteratorBase* iterator);
virtual Address GetCallerStackPointer() const; virtual Address GetCallerStackPointer() const;
virtual int GetNumberOfIncomingArguments() const; virtual int GetNumberOfIncomingArguments() const;
friend class StackFrameIterator; friend class StackFrameIteratorBase;
}; };
@ -660,12 +661,12 @@ class OptimizedFrame : public JavaScriptFrame {
DeoptimizationInputData* GetDeoptimizationData(int* deopt_index); DeoptimizationInputData* GetDeoptimizationData(int* deopt_index);
protected: protected:
inline explicit OptimizedFrame(StackFrameIterator* iterator); inline explicit OptimizedFrame(StackFrameIteratorBase* iterator);
private: private:
JSFunction* LiteralAt(FixedArray* literal_array, int literal_id); JSFunction* LiteralAt(FixedArray* literal_array, int literal_id);
friend class StackFrameIterator; friend class StackFrameIteratorBase;
}; };
@ -690,14 +691,14 @@ class ArgumentsAdaptorFrame: public JavaScriptFrame {
int index) const; int index) const;
protected: protected:
inline explicit ArgumentsAdaptorFrame(StackFrameIterator* iterator); inline explicit ArgumentsAdaptorFrame(StackFrameIteratorBase* iterator);
virtual int GetNumberOfIncomingArguments() const; virtual int GetNumberOfIncomingArguments() const;
virtual Address GetCallerStackPointer() const; virtual Address GetCallerStackPointer() const;
private: private:
friend class StackFrameIterator; friend class StackFrameIteratorBase;
}; };
@ -717,12 +718,12 @@ class InternalFrame: public StandardFrame {
} }
protected: protected:
inline explicit InternalFrame(StackFrameIterator* iterator); inline explicit InternalFrame(StackFrameIteratorBase* iterator);
virtual Address GetCallerStackPointer() const; virtual Address GetCallerStackPointer() const;
private: private:
friend class StackFrameIterator; friend class StackFrameIteratorBase;
}; };
@ -750,12 +751,12 @@ class StubFailureTrampolineFrame: public StandardFrame {
protected: protected:
inline explicit StubFailureTrampolineFrame( inline explicit StubFailureTrampolineFrame(
StackFrameIterator* iterator); StackFrameIteratorBase* iterator);
virtual Address GetCallerStackPointer() const; virtual Address GetCallerStackPointer() const;
private: private:
friend class StackFrameIterator; friend class StackFrameIteratorBase;
}; };
@ -771,40 +772,22 @@ class ConstructFrame: public InternalFrame {
} }
protected: protected:
inline explicit ConstructFrame(StackFrameIterator* iterator); inline explicit ConstructFrame(StackFrameIteratorBase* iterator);
private: private:
friend class StackFrameIterator; friend class StackFrameIteratorBase;
}; };
class StackFrameIterator BASE_EMBEDDED { class StackFrameIteratorBase BASE_EMBEDDED {
public: public:
// An iterator that iterates over the isolate's current thread's stack,
explicit StackFrameIterator(Isolate* isolate);
// An iterator that iterates over a given thread's stack.
StackFrameIterator(Isolate* isolate, ThreadLocalTop* t);
StackFrame* frame() const {
ASSERT(!done());
return frame_;
}
Isolate* isolate() const { return isolate_; } Isolate* isolate() const { return isolate_; }
bool done() const { return frame_ == NULL; } bool done() const { return frame_ == NULL; }
void Advance() { (this->*advance_)(); }
private: protected:
// An iterator that can start from a given FP address. // An iterator that iterates over a given thread's stack.
// If use_top, then work as usual, if fp isn't NULL, use it, StackFrameIteratorBase(Isolate* isolate, bool can_access_heap_objects);
// otherwise, do nothing. This constructor is used to create
// StackFrameIterator for "safe" stack iteration.
StackFrameIterator(Isolate* isolate, bool use_top, Address fp, Address sp);
// Go back to the first frame.
void Reset();
Isolate* isolate_; Isolate* isolate_;
#define DECLARE_SINGLETON(ignore, type) type type##_; #define DECLARE_SINGLETON(ignore, type) type type##_;
@ -812,10 +795,6 @@ class StackFrameIterator BASE_EMBEDDED {
#undef DECLARE_SINGLETON #undef DECLARE_SINGLETON
StackFrame* frame_; StackFrame* frame_;
StackHandler* handler_; StackHandler* handler_;
ThreadLocalTop* thread_;
Address fp_;
Address sp_;
void (StackFrameIterator::*advance_)();
const bool can_access_heap_objects_; const bool can_access_heap_objects_;
StackHandler* handler() const { StackHandler* handler() const {
@ -828,11 +807,29 @@ class StackFrameIterator BASE_EMBEDDED {
// A helper function, can return a NULL pointer. // A helper function, can return a NULL pointer.
StackFrame* SingletonFor(StackFrame::Type type); StackFrame* SingletonFor(StackFrame::Type type);
void AdvanceWithHandler(); private:
void AdvanceWithoutHandler();
friend class StackFrame; friend class StackFrame;
friend class SafeStackFrameIterator; DISALLOW_COPY_AND_ASSIGN(StackFrameIteratorBase);
};
class StackFrameIterator: public StackFrameIteratorBase {
public:
// An iterator that iterates over the isolate's current thread's stack,
explicit StackFrameIterator(Isolate* isolate);
// An iterator that iterates over a given thread's stack.
StackFrameIterator(Isolate* isolate, ThreadLocalTop* t);
StackFrame* frame() const {
ASSERT(!done());
return frame_;
}
void Advance();
private:
// Go back to the first frame.
void Reset(ThreadLocalTop* top);
DISALLOW_COPY_AND_ASSIGN(StackFrameIterator); DISALLOW_COPY_AND_ASSIGN(StackFrameIterator);
}; };
@ -874,61 +871,28 @@ class StackTraceFrameIterator: public JavaScriptFrameIterator {
}; };
class SafeStackFrameIterator BASE_EMBEDDED { class SafeStackFrameIterator: public StackFrameIteratorBase {
public: public:
SafeStackFrameIterator(Isolate* isolate, SafeStackFrameIterator(Isolate* isolate,
Address fp, Address sp, Address fp, Address sp,
Address low_bound, Address high_bound); Address low_bound, Address high_bound);
inline JavaScriptFrame* frame() const; inline JavaScriptFrame* frame() const;
bool done() const { return iteration_done_ || iterator_.done(); }
void Advance(); void Advance();
private: private:
void AdvanceOneFrame(); void AdvanceOneFrame();
static bool IsWithinBounds(
Address low_bound, Address high_bound, Address addr) {
return low_bound <= addr && addr <= high_bound;
}
class StackAddressValidator {
public:
StackAddressValidator(Address low_bound, Address high_bound)
: low_bound_(low_bound), high_bound_(high_bound) { }
bool IsValid(Address addr) const {
return IsWithinBounds(low_bound_, high_bound_, addr);
}
private:
Address low_bound_;
Address high_bound_;
};
class ExitFrameValidator {
public:
explicit ExitFrameValidator(const StackAddressValidator& validator)
: validator_(validator) { }
ExitFrameValidator(Address low_bound, Address high_bound)
: validator_(low_bound, high_bound) { }
bool IsValidFP(Address fp);
private:
StackAddressValidator validator_;
};
bool IsValidStackAddress(Address addr) const { bool IsValidStackAddress(Address addr) const {
return stack_validator_.IsValid(addr); return low_bound_ <= addr && addr <= high_bound_;
} }
bool IsValidFrame(StackFrame* frame) const; bool IsValidFrame(StackFrame* frame) const;
bool IsValidCaller(StackFrame* frame); bool IsValidCaller(StackFrame* frame);
static bool IsValidTop(Isolate* isolate, bool IsValidExitFrame(Address fp) const;
Address low_bound, Address high_bound); bool IsValidTop(ThreadLocalTop* top) const;
StackAddressValidator stack_validator_; const Address low_bound_;
const bool is_valid_top_; const Address high_bound_;
const bool is_valid_fp_;
bool iteration_done_;
StackFrameIterator iterator_;
}; };