• 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(JAVA_SCRIPT,       JavaScriptFrame)       \
97   V(INTERNAL,          InternalFrame)         \
98   V(CONSTRUCT,         ConstructFrame)        \
99   V(ARGUMENTS_ADAPTOR, ArgumentsAdaptorFrame)
100 
101 
102 // Abstract base class for all stack frames.
103 class StackFrame BASE_EMBEDDED {
104  public:
105 #define DECLARE_TYPE(type, ignore) type,
106   enum Type {
107     NONE = 0,
108     STACK_FRAME_TYPE_LIST(DECLARE_TYPE)
109     NUMBER_OF_TYPES
110   };
111 #undef DECLARE_TYPE
112 
113   // Opaque data type for identifying stack frames. Used extensively
114   // by the debugger.
115   enum Id { NO_ID = 0 };
116 
117   // Type testers.
is_entry()118   bool is_entry() const { return type() == ENTRY; }
is_entry_construct()119   bool is_entry_construct() const { return type() == ENTRY_CONSTRUCT; }
is_exit()120   bool is_exit() const { return type() == EXIT; }
is_java_script()121   bool is_java_script() const { return type() == JAVA_SCRIPT; }
is_arguments_adaptor()122   bool is_arguments_adaptor() const { return type() == ARGUMENTS_ADAPTOR; }
is_internal()123   bool is_internal() const { return type() == INTERNAL; }
is_construct()124   bool is_construct() const { return type() == CONSTRUCT; }
is_standard()125   virtual bool is_standard() const { return false; }
126 
127   // Accessors.
sp()128   Address sp() const { return state_.sp; }
fp()129   Address fp() const { return state_.fp; }
caller_sp()130   Address caller_sp() const { return GetCallerStackPointer(); }
131 
pc()132   Address pc() const { return *pc_address(); }
set_pc(Address pc)133   void set_pc(Address pc) { *pc_address() = pc; }
134 
pc_address()135   Address* pc_address() const { return state_.pc_address; }
136 
137   // Get the id of this stack frame.
id()138   Id id() const { return static_cast<Id>(OffsetFrom(caller_sp())); }
139 
140   // Checks if this frame includes any stack handlers.
141   bool HasHandler() const;
142 
143   // Get the type of this frame.
144   virtual Type type() const = 0;
145 
146   // Get the code associated with this frame.
147   virtual Code* code() const = 0;
148 
149   // Garbage collection support.
150   static void CookFramesForThread(ThreadLocalTop* thread);
151   static void UncookFramesForThread(ThreadLocalTop* thread);
152 
Iterate(ObjectVisitor * v)153   virtual void Iterate(ObjectVisitor* v) const { }
154 
155   // Printing support.
156   enum PrintMode { OVERVIEW, DETAILS };
Print(StringStream * accumulator,PrintMode mode,int index)157   virtual void Print(StringStream* accumulator,
158                      PrintMode mode,
159                      int index) const { }
160 
161  protected:
162   struct State {
163     Address sp;
164     Address fp;
165     Address* pc_address;
166   };
167 
StackFrame(StackFrameIterator * iterator)168   explicit StackFrame(StackFrameIterator* iterator) : iterator_(iterator) { }
~StackFrame()169   virtual ~StackFrame() { }
170 
171   // Compute the stack pointer for the calling frame.
172   virtual Address GetCallerStackPointer() const = 0;
173 
174   // Printing support.
175   static void PrintIndex(StringStream* accumulator,
176                          PrintMode mode,
177                          int index);
178 
179   // Get the top handler from the current stack iterator.
180   inline StackHandler* top_handler() const;
181 
182   // Compute the stack frame type for the given state.
183   static Type ComputeType(State* state);
184 
185  private:
186   const StackFrameIterator* iterator_;
187   State state_;
188 
189   // Fill in the state of the calling frame.
190   virtual void ComputeCallerState(State* state) const = 0;
191 
192   // Get the type and the state of the calling frame.
193   virtual Type GetCallerState(State* state) const;
194 
195   // Cooking/uncooking support.
196   void Cook();
197   void Uncook();
198 
199   friend class StackFrameIterator;
200   friend class StackHandlerIterator;
201   friend class SafeStackFrameIterator;
202 
203   DISALLOW_IMPLICIT_CONSTRUCTORS(StackFrame);
204 };
205 
206 
207 // Entry frames are used to enter JavaScript execution from C.
208 class EntryFrame: public StackFrame {
209  public:
type()210   virtual Type type() const { return ENTRY; }
211 
212   virtual Code* code() const;
213 
214   // Garbage collection support.
215   virtual void Iterate(ObjectVisitor* v) const;
216 
cast(StackFrame * frame)217   static EntryFrame* cast(StackFrame* frame) {
218     ASSERT(frame->is_entry());
219     return static_cast<EntryFrame*>(frame);
220   }
221 
222  protected:
EntryFrame(StackFrameIterator * iterator)223   explicit EntryFrame(StackFrameIterator* iterator) : StackFrame(iterator) { }
224 
225   // The caller stack pointer for entry frames is always zero. The
226   // real information about the caller frame is available through the
227   // link to the top exit frame.
GetCallerStackPointer()228   virtual Address GetCallerStackPointer() const { return 0; }
229 
230  private:
231   virtual void ComputeCallerState(State* state) const;
232   virtual Type GetCallerState(State* state) const;
233 
234   friend class StackFrameIterator;
235 };
236 
237 
238 class EntryConstructFrame: public EntryFrame {
239  public:
type()240   virtual Type type() const { return ENTRY_CONSTRUCT; }
241 
242   virtual Code* code() const;
243 
cast(StackFrame * frame)244   static EntryConstructFrame* cast(StackFrame* frame) {
245     ASSERT(frame->is_entry_construct());
246     return static_cast<EntryConstructFrame*>(frame);
247   }
248 
249  protected:
EntryConstructFrame(StackFrameIterator * iterator)250   explicit EntryConstructFrame(StackFrameIterator* iterator)
251       : EntryFrame(iterator) { }
252 
253  private:
254   friend class StackFrameIterator;
255 };
256 
257 
258 // Exit frames are used to exit JavaScript execution and go to C.
259 class ExitFrame: public StackFrame {
260  public:
261   enum Mode { MODE_NORMAL, MODE_DEBUG };
type()262   virtual Type type() const { return EXIT; }
263 
264   virtual Code* code() const;
265 
266   Object*& code_slot() const;
267 
268   // Garbage collection support.
269   virtual void Iterate(ObjectVisitor* v) const;
270 
cast(StackFrame * frame)271   static ExitFrame* cast(StackFrame* frame) {
272     ASSERT(frame->is_exit());
273     return static_cast<ExitFrame*>(frame);
274   }
275 
276   // Compute the state and type of an exit frame given a frame
277   // pointer. Used when constructing the first stack frame seen by an
278   // iterator and the frames following entry frames.
279   static Type GetStateForFramePointer(Address fp, State* state);
280 
281  protected:
ExitFrame(StackFrameIterator * iterator)282   explicit ExitFrame(StackFrameIterator* iterator) : StackFrame(iterator) { }
283 
284   virtual Address GetCallerStackPointer() const;
285 
286  private:
287   virtual void ComputeCallerState(State* state) const;
288 
289   friend class StackFrameIterator;
290 };
291 
292 
293 class StandardFrame: public StackFrame {
294  public:
295   // Testers.
is_standard()296   virtual bool is_standard() const { return true; }
297 
298   // Accessors.
299   inline Object* context() const;
300 
301   // Access the expressions in the stack frame including locals.
302   inline Object* GetExpression(int index) const;
303   inline void SetExpression(int index, Object* value);
304   int ComputeExpressionsCount() const;
305 
cast(StackFrame * frame)306   static StandardFrame* cast(StackFrame* frame) {
307     ASSERT(frame->is_standard());
308     return static_cast<StandardFrame*>(frame);
309   }
310 
311  protected:
StandardFrame(StackFrameIterator * iterator)312   explicit StandardFrame(StackFrameIterator* iterator)
313       : StackFrame(iterator) { }
314 
315   virtual void ComputeCallerState(State* state) const;
316 
317   // Accessors.
318   inline Address caller_fp() const;
319   inline Address caller_pc() const;
320 
321   // Computes the address of the PC field in the standard frame given
322   // by the provided frame pointer.
323   static inline Address ComputePCAddress(Address fp);
324 
325   // Iterate over expression stack including stack handlers, locals,
326   // and parts of the fixed part including context and code fields.
327   void IterateExpressions(ObjectVisitor* v) const;
328 
329   // Returns the address of the n'th expression stack element.
330   Address GetExpressionAddress(int n) const;
331 
332   // Determines if the n'th expression stack element is in a stack
333   // handler or not. Requires traversing all handlers in this frame.
334   bool IsExpressionInsideHandler(int n) const;
335 
336   // Determines if the standard frame for the given frame pointer is
337   // an arguments adaptor frame.
338   static inline bool IsArgumentsAdaptorFrame(Address fp);
339 
340   // Determines if the standard frame for the given frame pointer is a
341   // construct frame.
342   static inline bool IsConstructFrame(Address fp);
343 
344  private:
345   friend class StackFrame;
346 };
347 
348 
349 class JavaScriptFrame: public StandardFrame {
350  public:
type()351   virtual Type type() const { return JAVA_SCRIPT; }
352 
353   // Accessors.
354   inline Object* function() const;
355   inline Object* receiver() const;
356   inline void set_receiver(Object* value);
357 
358   // Access the parameters.
359   Object* GetParameter(int index) const;
360   int ComputeParametersCount() const;
361 
362   // Temporary way of getting access to the number of parameters
363   // passed on the stack by the caller. Once argument adaptor frames
364   // has been introduced on ARM, this number will always match the
365   // computed parameters count.
366   int GetProvidedParametersCount() const;
367 
368   // Check if this frame is a constructor frame invoked through 'new'.
369   bool IsConstructor() const;
370 
371   // Check if this frame has "adapted" arguments in the sense that the
372   // actual passed arguments are available in an arguments adaptor
373   // frame below it on the stack.
374   inline bool has_adapted_arguments() const;
375 
376   // Garbage collection support.
377   virtual void Iterate(ObjectVisitor* v) const;
378 
379   // Printing support.
380   virtual void Print(StringStream* accumulator,
381                      PrintMode mode,
382                      int index) const;
383 
384   // Determine the code for the frame.
385   virtual Code* code() const;
386 
cast(StackFrame * frame)387   static JavaScriptFrame* cast(StackFrame* frame) {
388     ASSERT(frame->is_java_script());
389     return static_cast<JavaScriptFrame*>(frame);
390   }
391 
392  protected:
JavaScriptFrame(StackFrameIterator * iterator)393   explicit JavaScriptFrame(StackFrameIterator* iterator)
394       : StandardFrame(iterator), disable_heap_access_(false) { }
395 
396   virtual Address GetCallerStackPointer() const;
397 
398   // When this mode is enabled it is not allowed to access heap objects.
399   // This is a special mode used when gathering stack samples in profiler.
400   // A shortcoming is that caller's SP value will be calculated incorrectly
401   // (see GetCallerStackPointer implementation), but it is not used for stack
402   // sampling.
DisableHeapAccess()403   void DisableHeapAccess() { disable_heap_access_ = true; }
404 
405  private:
406   bool disable_heap_access_;
407   inline Object* function_slot_object() const;
408 
409   friend class StackFrameIterator;
410 };
411 
412 
413 // Arguments adaptor frames are automatically inserted below
414 // JavaScript frames when the actual number of parameters does not
415 // match the formal number of parameters.
416 class ArgumentsAdaptorFrame: public JavaScriptFrame {
417  public:
type()418   virtual Type type() const { return ARGUMENTS_ADAPTOR; }
419 
420   // Determine the code for the frame.
421   virtual Code* code() const;
422 
cast(StackFrame * frame)423   static ArgumentsAdaptorFrame* cast(StackFrame* frame) {
424     ASSERT(frame->is_arguments_adaptor());
425     return static_cast<ArgumentsAdaptorFrame*>(frame);
426   }
427 
428   // Printing support.
429   virtual void Print(StringStream* accumulator,
430                      PrintMode mode,
431                      int index) const;
432  protected:
ArgumentsAdaptorFrame(StackFrameIterator * iterator)433   explicit ArgumentsAdaptorFrame(StackFrameIterator* iterator)
434       : JavaScriptFrame(iterator) { }
435 
436   virtual Address GetCallerStackPointer() const;
437 
438  private:
439   friend class StackFrameIterator;
440 };
441 
442 
443 class InternalFrame: public StandardFrame {
444  public:
type()445   virtual Type type() const { return INTERNAL; }
446 
447   // Garbage collection support.
448   virtual void Iterate(ObjectVisitor* v) const;
449 
450   // Determine the code for the frame.
451   virtual Code* code() const;
452 
cast(StackFrame * frame)453   static InternalFrame* cast(StackFrame* frame) {
454     ASSERT(frame->is_internal());
455     return static_cast<InternalFrame*>(frame);
456   }
457 
458  protected:
InternalFrame(StackFrameIterator * iterator)459   explicit InternalFrame(StackFrameIterator* iterator)
460       : StandardFrame(iterator) { }
461 
462   virtual Address GetCallerStackPointer() const;
463 
464  private:
465   friend class StackFrameIterator;
466 };
467 
468 
469 // Construct frames are special trampoline frames introduced to handle
470 // function invocations through 'new'.
471 class ConstructFrame: public InternalFrame {
472  public:
type()473   virtual Type type() const { return CONSTRUCT; }
474 
cast(StackFrame * frame)475   static ConstructFrame* cast(StackFrame* frame) {
476     ASSERT(frame->is_construct());
477     return static_cast<ConstructFrame*>(frame);
478   }
479 
480  protected:
ConstructFrame(StackFrameIterator * iterator)481   explicit ConstructFrame(StackFrameIterator* iterator)
482       : InternalFrame(iterator) { }
483 
484  private:
485   friend class StackFrameIterator;
486 };
487 
488 
489 class StackFrameIterator BASE_EMBEDDED {
490  public:
491   // An iterator that iterates over the current thread's stack.
492   StackFrameIterator();
493 
494   // An iterator that iterates over a given thread's stack.
495   explicit StackFrameIterator(ThreadLocalTop* thread);
496 
497   // An iterator that can start from a given FP address.
498   // If use_top, then work as usual, if fp isn't NULL, use it,
499   // otherwise, do nothing.
500   StackFrameIterator(bool use_top, Address fp, Address sp);
501 
frame()502   StackFrame* frame() const {
503     ASSERT(!done());
504     return frame_;
505   }
506 
done()507   bool done() const { return frame_ == NULL; }
Advance()508   void Advance() { (this->*advance_)(); }
509 
510   // Go back to the first frame.
511   void Reset();
512 
513  private:
514 #define DECLARE_SINGLETON(ignore, type) type type##_;
515   STACK_FRAME_TYPE_LIST(DECLARE_SINGLETON)
516 #undef DECLARE_SINGLETON
517   StackFrame* frame_;
518   StackHandler* handler_;
519   ThreadLocalTop* thread_;
520   Address fp_;
521   Address sp_;
522   void (StackFrameIterator::*advance_)();
523 
handler()524   StackHandler* handler() const {
525     ASSERT(!done());
526     return handler_;
527   }
528 
529   // Get the type-specific frame singleton in a given state.
530   StackFrame* SingletonFor(StackFrame::Type type, StackFrame::State* state);
531   // A helper function, can return a NULL pointer.
532   StackFrame* SingletonFor(StackFrame::Type type);
533 
534   void AdvanceWithHandler();
535   void AdvanceWithoutHandler();
536 
537   friend class StackFrame;
538   friend class SafeStackFrameIterator;
539   DISALLOW_COPY_AND_ASSIGN(StackFrameIterator);
540 };
541 
542 
543 // Iterator that supports iterating through all JavaScript frames.
544 template<typename Iterator>
545 class JavaScriptFrameIteratorTemp BASE_EMBEDDED {
546  public:
JavaScriptFrameIteratorTemp()547   JavaScriptFrameIteratorTemp() { if (!done()) Advance(); }
548 
JavaScriptFrameIteratorTemp(ThreadLocalTop * thread)549   explicit JavaScriptFrameIteratorTemp(ThreadLocalTop* thread) :
550       iterator_(thread) {
551     if (!done()) Advance();
552   }
553 
554   // Skip frames until the frame with the given id is reached.
555   explicit JavaScriptFrameIteratorTemp(StackFrame::Id id);
556 
JavaScriptFrameIteratorTemp(Address fp,Address sp,Address low_bound,Address high_bound)557   JavaScriptFrameIteratorTemp(Address fp, Address sp,
558                               Address low_bound, Address high_bound) :
559       iterator_(fp, sp, low_bound, high_bound) {
560     if (!done()) Advance();
561   }
562 
563   inline JavaScriptFrame* frame() const;
564 
done()565   bool done() const { return iterator_.done(); }
566   void Advance();
567 
568   // Advance to the frame holding the arguments for the current
569   // frame. This only affects the current frame if it has adapted
570   // arguments.
571   void AdvanceToArgumentsFrame();
572 
573   // Go back to the first frame.
574   void Reset();
575 
576  private:
577   Iterator iterator_;
578 };
579 
580 
581 typedef JavaScriptFrameIteratorTemp<StackFrameIterator> JavaScriptFrameIterator;
582 
583 
584 // NOTE: The stack trace frame iterator is an iterator that only
585 // traverse proper JavaScript frames; that is JavaScript frames that
586 // have proper JavaScript functions. This excludes the problematic
587 // functions in runtime.js.
588 class StackTraceFrameIterator: public JavaScriptFrameIterator {
589  public:
590   StackTraceFrameIterator();
591   void Advance();
592 
593  private:
594   bool IsValidFrame();
595 };
596 
597 
598 class SafeStackFrameIterator BASE_EMBEDDED {
599  public:
600   SafeStackFrameIterator(Address fp, Address sp,
601                          Address low_bound, Address high_bound);
602 
frame()603   StackFrame* frame() const {
604     ASSERT(is_working_iterator_);
605     return iterator_.frame();
606   }
607 
done()608   bool done() const { return iteration_done_ ? true : iterator_.done(); }
609 
610   void Advance();
611   void Reset();
612 
IsWithinBounds(Address low_bound,Address high_bound,Address addr)613   static bool IsWithinBounds(
614       Address low_bound, Address high_bound, Address addr) {
615     return low_bound <= addr && addr <= high_bound;
616   }
617 
618  private:
IsValidStackAddress(Address addr)619   bool IsValidStackAddress(Address addr) const {
620     return IsWithinBounds(low_bound_, high_bound_, addr);
621   }
622   bool CanIterateHandles(StackFrame* frame, StackHandler* handler);
623   bool IsValidFrame(StackFrame* frame) const;
624   bool IsValidCaller(StackFrame* frame);
625 
626   Address low_bound_;
627   Address high_bound_;
628   const bool is_valid_top_;
629   const bool is_valid_fp_;
630   const bool is_working_iterator_;
631   bool iteration_done_;
632   StackFrameIterator iterator_;
633 };
634 
635 
636 #ifdef ENABLE_LOGGING_AND_PROFILING
637 typedef JavaScriptFrameIteratorTemp<SafeStackFrameIterator>
638     SafeJavaScriptFrameIterator;
639 
640 
641 class SafeStackTraceFrameIterator: public SafeJavaScriptFrameIterator {
642  public:
643   explicit SafeStackTraceFrameIterator(Address fp, Address sp,
644                                        Address low_bound, Address high_bound);
645   void Advance();
646 };
647 #endif
648 
649 
650 class StackFrameLocator BASE_EMBEDDED {
651  public:
652   // Find the nth JavaScript frame on the stack. The caller must
653   // guarantee that such a frame exists.
654   JavaScriptFrame* FindJavaScriptFrame(int n);
655 
656  private:
657   StackFrameIterator iterator_;
658 };
659 
660 
661 } }  // namespace v8::internal
662 
663 #endif  // V8_FRAMES_H_
664