blob: 102244c9ba2f81879b823b69ebfe4fd6c46fa324 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// 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
31namespace v8 {
32namespace internal {
33
34typedef uint32_t RegList;
35
36// Get the number of registers in a given register list.
37int NumRegs(RegList list);
38
39// Return the code of the n-th saved register available to JavaScript.
40int JSCallerSavedCode(int n);
41
42
43// Forward declarations.
44class StackFrameIterator;
45class Top;
46class ThreadLocalTop;
47
48
49class 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
73 bool is_entry() { return state() == ENTRY; }
74 bool is_try_catch() { return state() == TRY_CATCH; }
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) \
Steve Blocka7e24c12009-10-30 11:49:00 +000096 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.
103class 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
Steve Block6ded16b2010-05-10 14:33:55 +0100117 // Copy constructor; it breaks the connection to host iterator.
118 StackFrame(const StackFrame& original) {
119 this->state_ = original.state_;
120 this->iterator_ = NULL;
121 }
122
Steve Blocka7e24c12009-10-30 11:49:00 +0000123 // Type testers.
124 bool is_entry() const { return type() == ENTRY; }
125 bool is_entry_construct() const { return type() == ENTRY_CONSTRUCT; }
126 bool is_exit() const { return type() == EXIT; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000127 bool is_java_script() const { return type() == JAVA_SCRIPT; }
128 bool is_arguments_adaptor() const { return type() == ARGUMENTS_ADAPTOR; }
129 bool is_internal() const { return type() == INTERNAL; }
130 bool is_construct() const { return type() == CONSTRUCT; }
131 virtual bool is_standard() const { return false; }
132
133 // Accessors.
134 Address sp() const { return state_.sp; }
135 Address fp() const { return state_.fp; }
136 Address caller_sp() const { return GetCallerStackPointer(); }
137
138 Address pc() const { return *pc_address(); }
139 void set_pc(Address pc) { *pc_address() = pc; }
140
Steve Block6ded16b2010-05-10 14:33:55 +0100141 virtual void SetCallerFp(Address caller_fp) = 0;
142
Steve Blocka7e24c12009-10-30 11:49:00 +0000143 Address* pc_address() const { return state_.pc_address; }
144
145 // Get the id of this stack frame.
146 Id id() const { return static_cast<Id>(OffsetFrom(caller_sp())); }
147
148 // Checks if this frame includes any stack handlers.
149 bool HasHandler() const;
150
151 // Get the type of this frame.
152 virtual Type type() const = 0;
153
154 // Get the code associated with this frame.
155 virtual Code* code() const = 0;
156
157 // Garbage collection support.
158 static void CookFramesForThread(ThreadLocalTop* thread);
159 static void UncookFramesForThread(ThreadLocalTop* thread);
160
161 virtual void Iterate(ObjectVisitor* v) const { }
162
163 // Printing support.
164 enum PrintMode { OVERVIEW, DETAILS };
165 virtual void Print(StringStream* accumulator,
166 PrintMode mode,
167 int index) const { }
168
169 protected:
170 struct State {
171 Address sp;
172 Address fp;
173 Address* pc_address;
174 };
175
176 explicit StackFrame(StackFrameIterator* iterator) : iterator_(iterator) { }
177 virtual ~StackFrame() { }
178
179 // Compute the stack pointer for the calling frame.
180 virtual Address GetCallerStackPointer() const = 0;
181
182 // Printing support.
183 static void PrintIndex(StringStream* accumulator,
184 PrintMode mode,
185 int index);
186
187 // Get the top handler from the current stack iterator.
188 inline StackHandler* top_handler() const;
189
190 // Compute the stack frame type for the given state.
191 static Type ComputeType(State* state);
192
193 private:
194 const StackFrameIterator* iterator_;
195 State state_;
196
197 // Fill in the state of the calling frame.
198 virtual void ComputeCallerState(State* state) const = 0;
199
200 // Get the type and the state of the calling frame.
201 virtual Type GetCallerState(State* state) const;
202
203 // Cooking/uncooking support.
204 void Cook();
205 void Uncook();
206
207 friend class StackFrameIterator;
208 friend class StackHandlerIterator;
209 friend class SafeStackFrameIterator;
210
Steve Block6ded16b2010-05-10 14:33:55 +0100211 private:
212 void operator=(const StackFrame& original);
Steve Blocka7e24c12009-10-30 11:49:00 +0000213};
214
215
216// Entry frames are used to enter JavaScript execution from C.
217class EntryFrame: public StackFrame {
218 public:
219 virtual Type type() const { return ENTRY; }
220
221 virtual Code* code() const;
222
223 // Garbage collection support.
224 virtual void Iterate(ObjectVisitor* v) const;
225
226 static EntryFrame* cast(StackFrame* frame) {
227 ASSERT(frame->is_entry());
228 return static_cast<EntryFrame*>(frame);
229 }
Steve Block6ded16b2010-05-10 14:33:55 +0100230 virtual void SetCallerFp(Address caller_fp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000231
232 protected:
233 explicit EntryFrame(StackFrameIterator* iterator) : StackFrame(iterator) { }
234
235 // The caller stack pointer for entry frames is always zero. The
236 // real information about the caller frame is available through the
237 // link to the top exit frame.
238 virtual Address GetCallerStackPointer() const { return 0; }
239
240 private:
241 virtual void ComputeCallerState(State* state) const;
242 virtual Type GetCallerState(State* state) const;
243
244 friend class StackFrameIterator;
245};
246
247
248class EntryConstructFrame: public EntryFrame {
249 public:
250 virtual Type type() const { return ENTRY_CONSTRUCT; }
251
252 virtual Code* code() const;
253
254 static EntryConstructFrame* cast(StackFrame* frame) {
255 ASSERT(frame->is_entry_construct());
256 return static_cast<EntryConstructFrame*>(frame);
257 }
258
259 protected:
260 explicit EntryConstructFrame(StackFrameIterator* iterator)
261 : EntryFrame(iterator) { }
262
263 private:
264 friend class StackFrameIterator;
265};
266
267
268// Exit frames are used to exit JavaScript execution and go to C.
269class ExitFrame: public StackFrame {
270 public:
Steve Blockd0582a62009-12-15 09:54:21 +0000271 enum Mode { MODE_NORMAL, MODE_DEBUG };
Steve Blocka7e24c12009-10-30 11:49:00 +0000272 virtual Type type() const { return EXIT; }
273
274 virtual Code* code() const;
275
Steve Blockd0582a62009-12-15 09:54:21 +0000276 Object*& code_slot() const;
277
Steve Blocka7e24c12009-10-30 11:49:00 +0000278 // Garbage collection support.
279 virtual void Iterate(ObjectVisitor* v) const;
280
Steve Block6ded16b2010-05-10 14:33:55 +0100281 virtual void SetCallerFp(Address caller_fp);
282
Steve Blocka7e24c12009-10-30 11:49:00 +0000283 static ExitFrame* cast(StackFrame* frame) {
284 ASSERT(frame->is_exit());
285 return static_cast<ExitFrame*>(frame);
286 }
287
288 // Compute the state and type of an exit frame given a frame
289 // pointer. Used when constructing the first stack frame seen by an
290 // iterator and the frames following entry frames.
291 static Type GetStateForFramePointer(Address fp, State* state);
292
293 protected:
294 explicit ExitFrame(StackFrameIterator* iterator) : StackFrame(iterator) { }
295
296 virtual Address GetCallerStackPointer() const;
297
298 private:
299 virtual void ComputeCallerState(State* state) const;
300
301 friend class StackFrameIterator;
302};
303
304
Steve Blocka7e24c12009-10-30 11:49:00 +0000305class StandardFrame: public StackFrame {
306 public:
307 // Testers.
308 virtual bool is_standard() const { return true; }
309
310 // Accessors.
311 inline Object* context() const;
312
313 // Access the expressions in the stack frame including locals.
314 inline Object* GetExpression(int index) const;
315 inline void SetExpression(int index, Object* value);
316 int ComputeExpressionsCount() const;
317
Steve Block6ded16b2010-05-10 14:33:55 +0100318 virtual void SetCallerFp(Address caller_fp);
319
Steve Blocka7e24c12009-10-30 11:49:00 +0000320 static StandardFrame* cast(StackFrame* frame) {
321 ASSERT(frame->is_standard());
322 return static_cast<StandardFrame*>(frame);
323 }
324
325 protected:
326 explicit StandardFrame(StackFrameIterator* iterator)
327 : StackFrame(iterator) { }
328
329 virtual void ComputeCallerState(State* state) const;
330
331 // Accessors.
332 inline Address caller_fp() const;
333 inline Address caller_pc() const;
334
335 // Computes the address of the PC field in the standard frame given
336 // by the provided frame pointer.
337 static inline Address ComputePCAddress(Address fp);
338
339 // Iterate over expression stack including stack handlers, locals,
340 // and parts of the fixed part including context and code fields.
341 void IterateExpressions(ObjectVisitor* v) const;
342
343 // Returns the address of the n'th expression stack element.
344 Address GetExpressionAddress(int n) const;
345
346 // Determines if the n'th expression stack element is in a stack
347 // handler or not. Requires traversing all handlers in this frame.
348 bool IsExpressionInsideHandler(int n) const;
349
350 // Determines if the standard frame for the given frame pointer is
351 // an arguments adaptor frame.
352 static inline bool IsArgumentsAdaptorFrame(Address fp);
353
354 // Determines if the standard frame for the given frame pointer is a
355 // construct frame.
356 static inline bool IsConstructFrame(Address fp);
357
358 private:
359 friend class StackFrame;
Kristian Monsen25f61362010-05-21 11:50:48 +0100360 friend class StackFrameIterator;
Steve Blocka7e24c12009-10-30 11:49:00 +0000361};
362
363
364class JavaScriptFrame: public StandardFrame {
365 public:
366 virtual Type type() const { return JAVA_SCRIPT; }
367
368 // Accessors.
369 inline Object* function() const;
370 inline Object* receiver() const;
371 inline void set_receiver(Object* value);
372
373 // Access the parameters.
374 Object* GetParameter(int index) const;
375 int ComputeParametersCount() const;
376
377 // Temporary way of getting access to the number of parameters
378 // passed on the stack by the caller. Once argument adaptor frames
379 // has been introduced on ARM, this number will always match the
380 // computed parameters count.
381 int GetProvidedParametersCount() const;
382
383 // Check if this frame is a constructor frame invoked through 'new'.
384 bool IsConstructor() const;
385
386 // Check if this frame has "adapted" arguments in the sense that the
387 // actual passed arguments are available in an arguments adaptor
388 // frame below it on the stack.
389 inline bool has_adapted_arguments() const;
390
391 // Garbage collection support.
392 virtual void Iterate(ObjectVisitor* v) const;
393
394 // Printing support.
395 virtual void Print(StringStream* accumulator,
396 PrintMode mode,
397 int index) const;
398
399 // Determine the code for the frame.
400 virtual Code* code() const;
401
402 static JavaScriptFrame* cast(StackFrame* frame) {
403 ASSERT(frame->is_java_script());
404 return static_cast<JavaScriptFrame*>(frame);
405 }
406
407 protected:
408 explicit JavaScriptFrame(StackFrameIterator* iterator)
409 : StandardFrame(iterator), disable_heap_access_(false) { }
410
411 virtual Address GetCallerStackPointer() const;
412
413 // When this mode is enabled it is not allowed to access heap objects.
414 // This is a special mode used when gathering stack samples in profiler.
415 // A shortcoming is that caller's SP value will be calculated incorrectly
416 // (see GetCallerStackPointer implementation), but it is not used for stack
417 // sampling.
418 void DisableHeapAccess() { disable_heap_access_ = true; }
419
420 private:
421 bool disable_heap_access_;
422 inline Object* function_slot_object() const;
423
424 friend class StackFrameIterator;
425};
426
427
428// Arguments adaptor frames are automatically inserted below
429// JavaScript frames when the actual number of parameters does not
430// match the formal number of parameters.
431class ArgumentsAdaptorFrame: public JavaScriptFrame {
432 public:
433 virtual Type type() const { return ARGUMENTS_ADAPTOR; }
434
435 // Determine the code for the frame.
436 virtual Code* code() const;
437
438 static ArgumentsAdaptorFrame* cast(StackFrame* frame) {
439 ASSERT(frame->is_arguments_adaptor());
440 return static_cast<ArgumentsAdaptorFrame*>(frame);
441 }
442
443 // Printing support.
444 virtual void Print(StringStream* accumulator,
445 PrintMode mode,
446 int index) const;
447 protected:
448 explicit ArgumentsAdaptorFrame(StackFrameIterator* iterator)
449 : JavaScriptFrame(iterator) { }
450
451 virtual Address GetCallerStackPointer() const;
452
453 private:
454 friend class StackFrameIterator;
455};
456
457
458class InternalFrame: public StandardFrame {
459 public:
460 virtual Type type() const { return INTERNAL; }
461
462 // Garbage collection support.
463 virtual void Iterate(ObjectVisitor* v) const;
464
465 // Determine the code for the frame.
466 virtual Code* code() const;
467
468 static InternalFrame* cast(StackFrame* frame) {
469 ASSERT(frame->is_internal());
470 return static_cast<InternalFrame*>(frame);
471 }
472
473 protected:
474 explicit InternalFrame(StackFrameIterator* iterator)
475 : StandardFrame(iterator) { }
476
477 virtual Address GetCallerStackPointer() const;
478
479 private:
480 friend class StackFrameIterator;
481};
482
483
484// Construct frames are special trampoline frames introduced to handle
485// function invocations through 'new'.
486class ConstructFrame: public InternalFrame {
487 public:
488 virtual Type type() const { return CONSTRUCT; }
489
490 static ConstructFrame* cast(StackFrame* frame) {
491 ASSERT(frame->is_construct());
492 return static_cast<ConstructFrame*>(frame);
493 }
494
495 protected:
496 explicit ConstructFrame(StackFrameIterator* iterator)
497 : InternalFrame(iterator) { }
498
499 private:
500 friend class StackFrameIterator;
501};
502
503
504class StackFrameIterator BASE_EMBEDDED {
505 public:
506 // An iterator that iterates over the current thread's stack.
507 StackFrameIterator();
508
509 // An iterator that iterates over a given thread's stack.
510 explicit StackFrameIterator(ThreadLocalTop* thread);
511
512 // An iterator that can start from a given FP address.
513 // If use_top, then work as usual, if fp isn't NULL, use it,
514 // otherwise, do nothing.
515 StackFrameIterator(bool use_top, Address fp, Address sp);
516
517 StackFrame* frame() const {
518 ASSERT(!done());
519 return frame_;
520 }
521
522 bool done() const { return frame_ == NULL; }
523 void Advance() { (this->*advance_)(); }
524
525 // Go back to the first frame.
526 void Reset();
527
528 private:
529#define DECLARE_SINGLETON(ignore, type) type type##_;
530 STACK_FRAME_TYPE_LIST(DECLARE_SINGLETON)
531#undef DECLARE_SINGLETON
532 StackFrame* frame_;
533 StackHandler* handler_;
534 ThreadLocalTop* thread_;
535 Address fp_;
536 Address sp_;
537 void (StackFrameIterator::*advance_)();
538
539 StackHandler* handler() const {
540 ASSERT(!done());
541 return handler_;
542 }
543
544 // Get the type-specific frame singleton in a given state.
545 StackFrame* SingletonFor(StackFrame::Type type, StackFrame::State* state);
546 // A helper function, can return a NULL pointer.
547 StackFrame* SingletonFor(StackFrame::Type type);
548
549 void AdvanceWithHandler();
550 void AdvanceWithoutHandler();
551
552 friend class StackFrame;
553 friend class SafeStackFrameIterator;
554 DISALLOW_COPY_AND_ASSIGN(StackFrameIterator);
555};
556
557
558// Iterator that supports iterating through all JavaScript frames.
559template<typename Iterator>
560class JavaScriptFrameIteratorTemp BASE_EMBEDDED {
561 public:
562 JavaScriptFrameIteratorTemp() { if (!done()) Advance(); }
563
564 explicit JavaScriptFrameIteratorTemp(ThreadLocalTop* thread) :
565 iterator_(thread) {
566 if (!done()) Advance();
567 }
568
569 // Skip frames until the frame with the given id is reached.
570 explicit JavaScriptFrameIteratorTemp(StackFrame::Id id);
571
572 JavaScriptFrameIteratorTemp(Address fp, Address sp,
573 Address low_bound, Address high_bound) :
574 iterator_(fp, sp, low_bound, high_bound) {
575 if (!done()) Advance();
576 }
577
578 inline JavaScriptFrame* frame() const;
579
580 bool done() const { return iterator_.done(); }
581 void Advance();
582
583 // Advance to the frame holding the arguments for the current
584 // frame. This only affects the current frame if it has adapted
585 // arguments.
586 void AdvanceToArgumentsFrame();
587
588 // Go back to the first frame.
589 void Reset();
590
591 private:
592 Iterator iterator_;
593};
594
595
596typedef JavaScriptFrameIteratorTemp<StackFrameIterator> JavaScriptFrameIterator;
597
598
599// NOTE: The stack trace frame iterator is an iterator that only
600// traverse proper JavaScript frames; that is JavaScript frames that
601// have proper JavaScript functions. This excludes the problematic
602// functions in runtime.js.
603class StackTraceFrameIterator: public JavaScriptFrameIterator {
604 public:
605 StackTraceFrameIterator();
606 void Advance();
Leon Clarke4515c472010-02-03 11:58:03 +0000607
608 private:
609 bool IsValidFrame();
Steve Blocka7e24c12009-10-30 11:49:00 +0000610};
611
612
613class SafeStackFrameIterator BASE_EMBEDDED {
614 public:
615 SafeStackFrameIterator(Address fp, Address sp,
616 Address low_bound, Address high_bound);
617
618 StackFrame* frame() const {
619 ASSERT(is_working_iterator_);
620 return iterator_.frame();
621 }
622
623 bool done() const { return iteration_done_ ? true : iterator_.done(); }
624
625 void Advance();
626 void Reset();
627
Steve Blocka7e24c12009-10-30 11:49:00 +0000628 static bool IsWithinBounds(
629 Address low_bound, Address high_bound, Address addr) {
630 return low_bound <= addr && addr <= high_bound;
631 }
Leon Clarked91b9f72010-01-27 17:25:45 +0000632
633 private:
Steve Blocka7e24c12009-10-30 11:49:00 +0000634 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
652typedef JavaScriptFrameIteratorTemp<SafeStackFrameIterator>
653 SafeJavaScriptFrameIterator;
654
655
656class 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
665class 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
Steve Block6ded16b2010-05-10 14:33:55 +0100676// Reads all frames on the current stack and copies them into the current
677// zone memory.
678Vector<StackFrame*> CreateStackMap();
679
Steve Blocka7e24c12009-10-30 11:49:00 +0000680} } // namespace v8::internal
681
682#endif // V8_FRAMES_H_