• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #ifndef V8_FRAMES_H_
29 #define V8_FRAMES_H_
30 
31 namespace v8 {
32 namespace internal {
33 
34 typedef uint32_t RegList;
35 
36 // Get the number of registers in a given register list.
37 int NumRegs(RegList list);
38 
39 // Return the code of the n-th saved register available to JavaScript.
40 int JSCallerSavedCode(int n);
41 
42 
43 // Forward declarations.
44 class StackFrameIterator;
45 class Top;
46 class ThreadLocalTop;
47 
48 
49 class StackHandler BASE_EMBEDDED {
50  public:
51   enum State {
52     ENTRY,
53     TRY_CATCH,
54     TRY_FINALLY
55   };
56 
57   // Get the address of this stack handler.
58   inline Address address() const;
59 
60   // Get the next stack handler in the chain.
61   inline StackHandler* next() const;
62 
63   // Tells whether the given address is inside this handler.
64   inline bool includes(Address address) const;
65 
66   // Garbage collection support.
67   inline void Iterate(ObjectVisitor* v) const;
68 
69   // Conversion support.
70   static inline StackHandler* FromAddress(Address address);
71 
72   // Testers
is_entry()73   bool is_entry() { return state() == ENTRY; }
is_try_catch()74   bool is_try_catch() { return state() == TRY_CATCH; }
is_try_finally()75   bool is_try_finally() { return state() == TRY_FINALLY; }
76 
77   // Garbage collection support.
78   void Cook(Code* code);
79   void Uncook(Code* code);
80 
81  private:
82   // Accessors.
83   inline State state() const;
84 
85   inline Address pc() const;
86   inline void set_pc(Address value);
87 
88   DISALLOW_IMPLICIT_CONSTRUCTORS(StackHandler);
89 };
90 
91 
92 #define STACK_FRAME_TYPE_LIST(V)              \
93   V(ENTRY,             EntryFrame)            \
94   V(ENTRY_CONSTRUCT,   EntryConstructFrame)   \
95   V(EXIT,              ExitFrame)             \
96   V(EXIT_DEBUG,        ExitDebugFrame)        \
97   V(JAVA_SCRIPT,       JavaScriptFrame)       \
98   V(INTERNAL,          InternalFrame)         \
99   V(CONSTRUCT,         ConstructFrame)        \
100   V(ARGUMENTS_ADAPTOR, ArgumentsAdaptorFrame)
101 
102 
103 // Abstract base class for all stack frames.
104 class StackFrame BASE_EMBEDDED {
105  public:
106 #define DECLARE_TYPE(type, ignore) type,
107   enum Type {
108     NONE = 0,
109     STACK_FRAME_TYPE_LIST(DECLARE_TYPE)
110     NUMBER_OF_TYPES
111   };
112 #undef DECLARE_TYPE
113 
114   // Opaque data type for identifying stack frames. Used extensively
115   // by the debugger.
116   enum Id { NO_ID = 0 };
117 
118   // Type testers.
is_entry()119   bool is_entry() const { return type() == ENTRY; }
is_entry_construct()120   bool is_entry_construct() const { return type() == ENTRY_CONSTRUCT; }
is_exit()121   bool is_exit() const { return type() == EXIT; }
is_exit_debug()122   bool is_exit_debug() const { return type() == EXIT_DEBUG; }
is_java_script()123   bool is_java_script() const { return type() == JAVA_SCRIPT; }
is_arguments_adaptor()124   bool is_arguments_adaptor() const { return type() == ARGUMENTS_ADAPTOR; }
is_internal()125   bool is_internal() const { return type() == INTERNAL; }
is_construct()126   bool is_construct() const { return type() == CONSTRUCT; }
is_standard()127   virtual bool is_standard() const { return false; }
128 
129   // Accessors.
sp()130   Address sp() const { return state_.sp; }
fp()131   Address fp() const { return state_.fp; }
caller_sp()132   Address caller_sp() const { return GetCallerStackPointer(); }
133 
pc()134   Address pc() const { return *pc_address(); }
set_pc(Address pc)135   void set_pc(Address pc) { *pc_address() = pc; }
136 
pc_address()137   Address* pc_address() const { return state_.pc_address; }
138 
139   // Get the id of this stack frame.
id()140   Id id() const { return static_cast<Id>(OffsetFrom(caller_sp())); }
141 
142   // Checks if this frame includes any stack handlers.
143   bool HasHandler() const;
144 
145   // Get the type of this frame.
146   virtual Type type() const = 0;
147 
148   // Get the code associated with this frame.
149   virtual Code* code() const = 0;
150 
151   // Garbage collection support.
152   static void CookFramesForThread(ThreadLocalTop* thread);
153   static void UncookFramesForThread(ThreadLocalTop* thread);
154 
Iterate(ObjectVisitor * v)155   virtual void Iterate(ObjectVisitor* v) const { }
156 
157   // Printing support.
158   enum PrintMode { OVERVIEW, DETAILS };
Print(StringStream * accumulator,PrintMode mode,int index)159   virtual void Print(StringStream* accumulator,
160                      PrintMode mode,
161                      int index) const { }
162 
163  protected:
164   struct State {
165     Address sp;
166     Address fp;
167     Address* pc_address;
168   };
169 
StackFrame(StackFrameIterator * iterator)170   explicit StackFrame(StackFrameIterator* iterator) : iterator_(iterator) { }
~StackFrame()171   virtual ~StackFrame() { }
172 
173   // Compute the stack pointer for the calling frame.
174   virtual Address GetCallerStackPointer() const = 0;
175 
176   // Printing support.
177   static void PrintIndex(StringStream* accumulator,
178                          PrintMode mode,
179                          int index);
180 
181   // Get the top handler from the current stack iterator.
182   inline StackHandler* top_handler() const;
183 
184   // Compute the stack frame type for the given state.
185   static Type ComputeType(State* state);
186 
187  private:
188   const StackFrameIterator* iterator_;
189   State state_;
190 
191   // Fill in the state of the calling frame.
192   virtual void ComputeCallerState(State* state) const = 0;
193 
194   // Get the type and the state of the calling frame.
195   virtual Type GetCallerState(State* state) const;
196 
197   // Cooking/uncooking support.
198   void Cook();
199   void Uncook();
200 
201   friend class StackFrameIterator;
202   friend class StackHandlerIterator;
203   friend class SafeStackFrameIterator;
204 
205   DISALLOW_IMPLICIT_CONSTRUCTORS(StackFrame);
206 };
207 
208 
209 // Entry frames are used to enter JavaScript execution from C.
210 class EntryFrame: public StackFrame {
211  public:
type()212   virtual Type type() const { return ENTRY; }
213 
214   virtual Code* code() const;
215 
216   // Garbage collection support.
217   virtual void Iterate(ObjectVisitor* v) const;
218 
cast(StackFrame * frame)219   static EntryFrame* cast(StackFrame* frame) {
220     ASSERT(frame->is_entry());
221     return static_cast<EntryFrame*>(frame);
222   }
223 
224  protected:
EntryFrame(StackFrameIterator * iterator)225   explicit EntryFrame(StackFrameIterator* iterator) : StackFrame(iterator) { }
226 
227   // The caller stack pointer for entry frames is always zero. The
228   // real information about the caller frame is available through the
229   // link to the top exit frame.
GetCallerStackPointer()230   virtual Address GetCallerStackPointer() const { return 0; }
231 
232  private:
233   virtual void ComputeCallerState(State* state) const;
234   virtual Type GetCallerState(State* state) const;
235 
236   friend class StackFrameIterator;
237 };
238 
239 
240 class EntryConstructFrame: public EntryFrame {
241  public:
type()242   virtual Type type() const { return ENTRY_CONSTRUCT; }
243 
244   virtual Code* code() const;
245 
cast(StackFrame * frame)246   static EntryConstructFrame* cast(StackFrame* frame) {
247     ASSERT(frame->is_entry_construct());
248     return static_cast<EntryConstructFrame*>(frame);
249   }
250 
251  protected:
EntryConstructFrame(StackFrameIterator * iterator)252   explicit EntryConstructFrame(StackFrameIterator* iterator)
253       : EntryFrame(iterator) { }
254 
255  private:
256   friend class StackFrameIterator;
257 };
258 
259 
260 // Exit frames are used to exit JavaScript execution and go to C.
261 class ExitFrame: public StackFrame {
262  public:
type()263   virtual Type type() const { return EXIT; }
264 
265   virtual Code* code() const;
266 
267   // Garbage collection support.
268   virtual void Iterate(ObjectVisitor* v) const;
269 
cast(StackFrame * frame)270   static ExitFrame* cast(StackFrame* frame) {
271     ASSERT(frame->is_exit());
272     return static_cast<ExitFrame*>(frame);
273   }
274 
275   // Compute the state and type of an exit frame given a frame
276   // pointer. Used when constructing the first stack frame seen by an
277   // iterator and the frames following entry frames.
278   static Type GetStateForFramePointer(Address fp, State* state);
279 
280  protected:
ExitFrame(StackFrameIterator * iterator)281   explicit ExitFrame(StackFrameIterator* iterator) : StackFrame(iterator) { }
282 
283   virtual Address GetCallerStackPointer() const;
284 
285  private:
286   virtual void ComputeCallerState(State* state) const;
287 
288   friend class StackFrameIterator;
289 };
290 
291 
292 class ExitDebugFrame: public ExitFrame {
293  public:
type()294   virtual Type type() const { return EXIT_DEBUG; }
295 
296   virtual Code* code() const;
297 
cast(StackFrame * frame)298   static ExitDebugFrame* cast(StackFrame* frame) {
299     ASSERT(frame->is_exit_debug());
300     return static_cast<ExitDebugFrame*>(frame);
301   }
302 
303  protected:
ExitDebugFrame(StackFrameIterator * iterator)304   explicit ExitDebugFrame(StackFrameIterator* iterator)
305       : ExitFrame(iterator) { }
306 
307  private:
308   friend class StackFrameIterator;
309 };
310 
311 
312 class StandardFrame: public StackFrame {
313  public:
314   // Testers.
is_standard()315   virtual bool is_standard() const { return true; }
316 
317   // Accessors.
318   inline Object* context() const;
319 
320   // Access the expressions in the stack frame including locals.
321   inline Object* GetExpression(int index) const;
322   inline void SetExpression(int index, Object* value);
323   int ComputeExpressionsCount() const;
324 
cast(StackFrame * frame)325   static StandardFrame* cast(StackFrame* frame) {
326     ASSERT(frame->is_standard());
327     return static_cast<StandardFrame*>(frame);
328   }
329 
330  protected:
StandardFrame(StackFrameIterator * iterator)331   explicit StandardFrame(StackFrameIterator* iterator)
332       : StackFrame(iterator) { }
333 
334   virtual void ComputeCallerState(State* state) const;
335 
336   // Accessors.
337   inline Address caller_fp() const;
338   inline Address caller_pc() const;
339 
340   // Computes the address of the PC field in the standard frame given
341   // by the provided frame pointer.
342   static inline Address ComputePCAddress(Address fp);
343 
344   // Iterate over expression stack including stack handlers, locals,
345   // and parts of the fixed part including context and code fields.
346   void IterateExpressions(ObjectVisitor* v) const;
347 
348   // Returns the address of the n'th expression stack element.
349   Address GetExpressionAddress(int n) const;
350 
351   // Determines if the n'th expression stack element is in a stack
352   // handler or not. Requires traversing all handlers in this frame.
353   bool IsExpressionInsideHandler(int n) const;
354 
355   // Determines if the standard frame for the given frame pointer is
356   // an arguments adaptor frame.
357   static inline bool IsArgumentsAdaptorFrame(Address fp);
358 
359   // Determines if the standard frame for the given frame pointer is a
360   // construct frame.
361   static inline bool IsConstructFrame(Address fp);
362 
363  private:
364   friend class StackFrame;
365 };
366 
367 
368 class JavaScriptFrame: public StandardFrame {
369  public:
type()370   virtual Type type() const { return JAVA_SCRIPT; }
371 
372   // Accessors.
373   inline Object* function() const;
374   inline Object* receiver() const;
375   inline void set_receiver(Object* value);
376 
377   // Access the parameters.
378   Object* GetParameter(int index) const;
379   int ComputeParametersCount() const;
380 
381   // Temporary way of getting access to the number of parameters
382   // passed on the stack by the caller. Once argument adaptor frames
383   // has been introduced on ARM, this number will always match the
384   // computed parameters count.
385   int GetProvidedParametersCount() const;
386 
387   // Check if this frame is a constructor frame invoked through 'new'.
388   bool IsConstructor() const;
389 
390   // Check if this frame has "adapted" arguments in the sense that the
391   // actual passed arguments are available in an arguments adaptor
392   // frame below it on the stack.
393   inline bool has_adapted_arguments() const;
394 
395   // Garbage collection support.
396   virtual void Iterate(ObjectVisitor* v) const;
397 
398   // Printing support.
399   virtual void Print(StringStream* accumulator,
400                      PrintMode mode,
401                      int index) const;
402 
403   // Determine the code for the frame.
404   virtual Code* code() const;
405 
cast(StackFrame * frame)406   static JavaScriptFrame* cast(StackFrame* frame) {
407     ASSERT(frame->is_java_script());
408     return static_cast<JavaScriptFrame*>(frame);
409   }
410 
411  protected:
JavaScriptFrame(StackFrameIterator * iterator)412   explicit JavaScriptFrame(StackFrameIterator* iterator)
413       : StandardFrame(iterator), disable_heap_access_(false) { }
414 
415   virtual Address GetCallerStackPointer() const;
416 
417   // When this mode is enabled it is not allowed to access heap objects.
418   // This is a special mode used when gathering stack samples in profiler.
419   // A shortcoming is that caller's SP value will be calculated incorrectly
420   // (see GetCallerStackPointer implementation), but it is not used for stack
421   // sampling.
DisableHeapAccess()422   void DisableHeapAccess() { disable_heap_access_ = true; }
423 
424  private:
425   bool disable_heap_access_;
426   inline Object* function_slot_object() const;
427 
428   friend class StackFrameIterator;
429 };
430 
431 
432 // Arguments adaptor frames are automatically inserted below
433 // JavaScript frames when the actual number of parameters does not
434 // match the formal number of parameters.
435 class ArgumentsAdaptorFrame: public JavaScriptFrame {
436  public:
type()437   virtual Type type() const { return ARGUMENTS_ADAPTOR; }
438 
439   // Determine the code for the frame.
440   virtual Code* code() const;
441 
cast(StackFrame * frame)442   static ArgumentsAdaptorFrame* cast(StackFrame* frame) {
443     ASSERT(frame->is_arguments_adaptor());
444     return static_cast<ArgumentsAdaptorFrame*>(frame);
445   }
446 
447   // Printing support.
448   virtual void Print(StringStream* accumulator,
449                      PrintMode mode,
450                      int index) const;
451  protected:
ArgumentsAdaptorFrame(StackFrameIterator * iterator)452   explicit ArgumentsAdaptorFrame(StackFrameIterator* iterator)
453       : JavaScriptFrame(iterator) { }
454 
455   virtual Address GetCallerStackPointer() const;
456 
457  private:
458   friend class StackFrameIterator;
459 };
460 
461 
462 class InternalFrame: public StandardFrame {
463  public:
type()464   virtual Type type() const { return INTERNAL; }
465 
466   // Garbage collection support.
467   virtual void Iterate(ObjectVisitor* v) const;
468 
469   // Determine the code for the frame.
470   virtual Code* code() const;
471 
cast(StackFrame * frame)472   static InternalFrame* cast(StackFrame* frame) {
473     ASSERT(frame->is_internal());
474     return static_cast<InternalFrame*>(frame);
475   }
476 
477  protected:
InternalFrame(StackFrameIterator * iterator)478   explicit InternalFrame(StackFrameIterator* iterator)
479       : StandardFrame(iterator) { }
480 
481   virtual Address GetCallerStackPointer() const;
482 
483  private:
484   friend class StackFrameIterator;
485 };
486 
487 
488 // Construct frames are special trampoline frames introduced to handle
489 // function invocations through 'new'.
490 class ConstructFrame: public InternalFrame {
491  public:
type()492   virtual Type type() const { return CONSTRUCT; }
493 
cast(StackFrame * frame)494   static ConstructFrame* cast(StackFrame* frame) {
495     ASSERT(frame->is_construct());
496     return static_cast<ConstructFrame*>(frame);
497   }
498 
499  protected:
ConstructFrame(StackFrameIterator * iterator)500   explicit ConstructFrame(StackFrameIterator* iterator)
501       : InternalFrame(iterator) { }
502 
503  private:
504   friend class StackFrameIterator;
505 };
506 
507 
508 class StackFrameIterator BASE_EMBEDDED {
509  public:
510   // An iterator that iterates over the current thread's stack.
511   StackFrameIterator();
512 
513   // An iterator that iterates over a given thread's stack.
514   explicit StackFrameIterator(ThreadLocalTop* thread);
515 
516   // An iterator that can start from a given FP address.
517   // If use_top, then work as usual, if fp isn't NULL, use it,
518   // otherwise, do nothing.
519   StackFrameIterator(bool use_top, Address fp, Address sp);
520 
frame()521   StackFrame* frame() const {
522     ASSERT(!done());
523     return frame_;
524   }
525 
done()526   bool done() const { return frame_ == NULL; }
Advance()527   void Advance() { (this->*advance_)(); }
528 
529   // Go back to the first frame.
530   void Reset();
531 
532  private:
533 #define DECLARE_SINGLETON(ignore, type) type type##_;
534   STACK_FRAME_TYPE_LIST(DECLARE_SINGLETON)
535 #undef DECLARE_SINGLETON
536   StackFrame* frame_;
537   StackHandler* handler_;
538   ThreadLocalTop* thread_;
539   Address fp_;
540   Address sp_;
541   void (StackFrameIterator::*advance_)();
542 
handler()543   StackHandler* handler() const {
544     ASSERT(!done());
545     return handler_;
546   }
547 
548   // Get the type-specific frame singleton in a given state.
549   StackFrame* SingletonFor(StackFrame::Type type, StackFrame::State* state);
550   // A helper function, can return a NULL pointer.
551   StackFrame* SingletonFor(StackFrame::Type type);
552 
553   void AdvanceWithHandler();
554   void AdvanceWithoutHandler();
555 
556   friend class StackFrame;
557   friend class SafeStackFrameIterator;
558   DISALLOW_COPY_AND_ASSIGN(StackFrameIterator);
559 };
560 
561 
562 // Iterator that supports iterating through all JavaScript frames.
563 template<typename Iterator>
564 class JavaScriptFrameIteratorTemp BASE_EMBEDDED {
565  public:
JavaScriptFrameIteratorTemp()566   JavaScriptFrameIteratorTemp() { if (!done()) Advance(); }
567 
JavaScriptFrameIteratorTemp(ThreadLocalTop * thread)568   explicit JavaScriptFrameIteratorTemp(ThreadLocalTop* thread) :
569       iterator_(thread) {
570     if (!done()) Advance();
571   }
572 
573   // Skip frames until the frame with the given id is reached.
574   explicit JavaScriptFrameIteratorTemp(StackFrame::Id id);
575 
JavaScriptFrameIteratorTemp(Address fp,Address sp,Address low_bound,Address high_bound)576   JavaScriptFrameIteratorTemp(Address fp, Address sp,
577                               Address low_bound, Address high_bound) :
578       iterator_(fp, sp, low_bound, high_bound) {
579     if (!done()) Advance();
580   }
581 
582   inline JavaScriptFrame* frame() const;
583 
done()584   bool done() const { return iterator_.done(); }
585   void Advance();
586 
587   // Advance to the frame holding the arguments for the current
588   // frame. This only affects the current frame if it has adapted
589   // arguments.
590   void AdvanceToArgumentsFrame();
591 
592   // Go back to the first frame.
593   void Reset();
594 
595  private:
596   Iterator iterator_;
597 };
598 
599 
600 typedef JavaScriptFrameIteratorTemp<StackFrameIterator> JavaScriptFrameIterator;
601 
602 
603 // NOTE: The stack trace frame iterator is an iterator that only
604 // traverse proper JavaScript frames; that is JavaScript frames that
605 // have proper JavaScript functions. This excludes the problematic
606 // functions in runtime.js.
607 class StackTraceFrameIterator: public JavaScriptFrameIterator {
608  public:
609   StackTraceFrameIterator();
610   void Advance();
611 };
612 
613 
614 class SafeStackFrameIterator BASE_EMBEDDED {
615  public:
616   SafeStackFrameIterator(Address fp, Address sp,
617                          Address low_bound, Address high_bound);
618 
frame()619   StackFrame* frame() const {
620     ASSERT(is_working_iterator_);
621     return iterator_.frame();
622   }
623 
done()624   bool done() const { return iteration_done_ ? true : iterator_.done(); }
625 
626   void Advance();
627   void Reset();
628 
629  private:
IsWithinBounds(Address low_bound,Address high_bound,Address addr)630   static bool IsWithinBounds(
631       Address low_bound, Address high_bound, Address addr) {
632     return low_bound <= addr && addr <= high_bound;
633   }
IsValidStackAddress(Address addr)634   bool IsValidStackAddress(Address addr) const {
635     return IsWithinBounds(low_bound_, high_bound_, addr);
636   }
637   bool CanIterateHandles(StackFrame* frame, StackHandler* handler);
638   bool IsValidFrame(StackFrame* frame) const;
639   bool IsValidCaller(StackFrame* frame);
640 
641   Address low_bound_;
642   Address high_bound_;
643   const bool is_valid_top_;
644   const bool is_valid_fp_;
645   const bool is_working_iterator_;
646   bool iteration_done_;
647   StackFrameIterator iterator_;
648 };
649 
650 
651 #ifdef ENABLE_LOGGING_AND_PROFILING
652 typedef JavaScriptFrameIteratorTemp<SafeStackFrameIterator>
653     SafeJavaScriptFrameIterator;
654 
655 
656 class SafeStackTraceFrameIterator: public SafeJavaScriptFrameIterator {
657  public:
658   explicit SafeStackTraceFrameIterator(Address fp, Address sp,
659                                        Address low_bound, Address high_bound);
660   void Advance();
661 };
662 #endif
663 
664 
665 class StackFrameLocator BASE_EMBEDDED {
666  public:
667   // Find the nth JavaScript frame on the stack. The caller must
668   // guarantee that such a frame exists.
669   JavaScriptFrame* FindJavaScriptFrame(int n);
670 
671  private:
672   StackFrameIterator iterator_;
673 };
674 
675 
676 } }  // namespace v8::internal
677 
678 #endif  // V8_FRAMES_H_
679