blob: 768196d3c6869cd49a7aba7d391c36f3b9608089 [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) \
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.
104class 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.
119 bool is_entry() const { return type() == ENTRY; }
120 bool is_entry_construct() const { return type() == ENTRY_CONSTRUCT; }
121 bool is_exit() const { return type() == EXIT; }
122 bool is_exit_debug() const { return type() == EXIT_DEBUG; }
123 bool is_java_script() const { return type() == JAVA_SCRIPT; }
124 bool is_arguments_adaptor() const { return type() == ARGUMENTS_ADAPTOR; }
125 bool is_internal() const { return type() == INTERNAL; }
126 bool is_construct() const { return type() == CONSTRUCT; }
127 virtual bool is_standard() const { return false; }
128
129 // Accessors.
130 Address sp() const { return state_.sp; }
131 Address fp() const { return state_.fp; }
132 Address caller_sp() const { return GetCallerStackPointer(); }
133
134 Address pc() const { return *pc_address(); }
135 void set_pc(Address pc) { *pc_address() = pc; }
136
137 Address* pc_address() const { return state_.pc_address; }
138
139 // Get the id of this stack frame.
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
155 virtual void Iterate(ObjectVisitor* v) const { }
156
157 // Printing support.
158 enum PrintMode { OVERVIEW, DETAILS };
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
170 explicit StackFrame(StackFrameIterator* iterator) : iterator_(iterator) { }
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.
210class EntryFrame: public StackFrame {
211 public:
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
219 static EntryFrame* cast(StackFrame* frame) {
220 ASSERT(frame->is_entry());
221 return static_cast<EntryFrame*>(frame);
222 }
223
224 protected:
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.
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
240class EntryConstructFrame: public EntryFrame {
241 public:
242 virtual Type type() const { return ENTRY_CONSTRUCT; }
243
244 virtual Code* code() const;
245
246 static EntryConstructFrame* cast(StackFrame* frame) {
247 ASSERT(frame->is_entry_construct());
248 return static_cast<EntryConstructFrame*>(frame);
249 }
250
251 protected:
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.
261class ExitFrame: public StackFrame {
262 public:
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
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:
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
292class ExitDebugFrame: public ExitFrame {
293 public:
294 virtual Type type() const { return EXIT_DEBUG; }
295
296 virtual Code* code() const;
297
298 static ExitDebugFrame* cast(StackFrame* frame) {
299 ASSERT(frame->is_exit_debug());
300 return static_cast<ExitDebugFrame*>(frame);
301 }
302
303 protected:
304 explicit ExitDebugFrame(StackFrameIterator* iterator)
305 : ExitFrame(iterator) { }
306
307 private:
308 friend class StackFrameIterator;
309};
310
311
312class StandardFrame: public StackFrame {
313 public:
314 // Testers.
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
325 static StandardFrame* cast(StackFrame* frame) {
326 ASSERT(frame->is_standard());
327 return static_cast<StandardFrame*>(frame);
328 }
329
330 protected:
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
368class JavaScriptFrame: public StandardFrame {
369 public:
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
406 static JavaScriptFrame* cast(StackFrame* frame) {
407 ASSERT(frame->is_java_script());
408 return static_cast<JavaScriptFrame*>(frame);
409 }
410
411 protected:
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.
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.
435class ArgumentsAdaptorFrame: public JavaScriptFrame {
436 public:
437 virtual Type type() const { return ARGUMENTS_ADAPTOR; }
438
439 // Determine the code for the frame.
440 virtual Code* code() const;
441
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:
452 explicit ArgumentsAdaptorFrame(StackFrameIterator* iterator)
453 : JavaScriptFrame(iterator) { }
454
455 virtual Address GetCallerStackPointer() const;
456
457 private:
458 friend class StackFrameIterator;
459};
460
461
462class InternalFrame: public StandardFrame {
463 public:
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
472 static InternalFrame* cast(StackFrame* frame) {
473 ASSERT(frame->is_internal());
474 return static_cast<InternalFrame*>(frame);
475 }
476
477 protected:
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'.
490class ConstructFrame: public InternalFrame {
491 public:
492 virtual Type type() const { return CONSTRUCT; }
493
494 static ConstructFrame* cast(StackFrame* frame) {
495 ASSERT(frame->is_construct());
496 return static_cast<ConstructFrame*>(frame);
497 }
498
499 protected:
500 explicit ConstructFrame(StackFrameIterator* iterator)
501 : InternalFrame(iterator) { }
502
503 private:
504 friend class StackFrameIterator;
505};
506
507
508class 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
521 StackFrame* frame() const {
522 ASSERT(!done());
523 return frame_;
524 }
525
526 bool done() const { return frame_ == NULL; }
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
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.
563template<typename Iterator>
564class JavaScriptFrameIteratorTemp BASE_EMBEDDED {
565 public:
566 JavaScriptFrameIteratorTemp() { if (!done()) Advance(); }
567
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
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
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
600typedef 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.
607class StackTraceFrameIterator: public JavaScriptFrameIterator {
608 public:
609 StackTraceFrameIterator();
610 void Advance();
611};
612
613
614class SafeStackFrameIterator BASE_EMBEDDED {
615 public:
616 SafeStackFrameIterator(Address fp, Address sp,
617 Address low_bound, Address high_bound);
618
619 StackFrame* frame() const {
620 ASSERT(is_working_iterator_);
621 return iterator_.frame();
622 }
623
624 bool done() const { return iteration_done_ ? true : iterator_.done(); }
625
626 void Advance();
627 void Reset();
628
629 private:
630 static bool IsWithinBounds(
631 Address low_bound, Address high_bound, Address addr) {
632 return low_bound <= addr && addr <= high_bound;
633 }
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
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
676} } // namespace v8::internal
677
678#endif // V8_FRAMES_H_