blob: 8cbbc6267978b5929277e97787a684ee3167dcb0 [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
117 // Type testers.
118 bool is_entry() const { return type() == ENTRY; }
119 bool is_entry_construct() const { return type() == ENTRY_CONSTRUCT; }
120 bool is_exit() const { return type() == EXIT; }
Steve Blocka7e24c12009-10-30 11:49:00 +0000121 bool is_java_script() const { return type() == JAVA_SCRIPT; }
122 bool is_arguments_adaptor() const { return type() == ARGUMENTS_ADAPTOR; }
123 bool is_internal() const { return type() == INTERNAL; }
124 bool is_construct() const { return type() == CONSTRUCT; }
125 virtual bool is_standard() const { return false; }
126
127 // Accessors.
128 Address sp() const { return state_.sp; }
129 Address fp() const { return state_.fp; }
130 Address caller_sp() const { return GetCallerStackPointer(); }
131
132 Address pc() const { return *pc_address(); }
133 void set_pc(Address pc) { *pc_address() = pc; }
134
135 Address* pc_address() const { return state_.pc_address; }
136
137 // Get the id of this stack frame.
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
153 virtual void Iterate(ObjectVisitor* v) const { }
154
155 // Printing support.
156 enum PrintMode { OVERVIEW, DETAILS };
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
168 explicit StackFrame(StackFrameIterator* iterator) : iterator_(iterator) { }
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.
208class EntryFrame: public StackFrame {
209 public:
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
217 static EntryFrame* cast(StackFrame* frame) {
218 ASSERT(frame->is_entry());
219 return static_cast<EntryFrame*>(frame);
220 }
221
222 protected:
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.
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
238class EntryConstructFrame: public EntryFrame {
239 public:
240 virtual Type type() const { return ENTRY_CONSTRUCT; }
241
242 virtual Code* code() const;
243
244 static EntryConstructFrame* cast(StackFrame* frame) {
245 ASSERT(frame->is_entry_construct());
246 return static_cast<EntryConstructFrame*>(frame);
247 }
248
249 protected:
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.
259class ExitFrame: public StackFrame {
260 public:
Steve Blockd0582a62009-12-15 09:54:21 +0000261 enum Mode { MODE_NORMAL, MODE_DEBUG };
Steve Blocka7e24c12009-10-30 11:49:00 +0000262 virtual Type type() const { return EXIT; }
263
264 virtual Code* code() const;
265
Steve Blockd0582a62009-12-15 09:54:21 +0000266 Object*& code_slot() const;
267
Steve Blocka7e24c12009-10-30 11:49:00 +0000268 // Garbage collection support.
269 virtual void Iterate(ObjectVisitor* v) const;
270
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:
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
Steve Blocka7e24c12009-10-30 11:49:00 +0000293class StandardFrame: public StackFrame {
294 public:
295 // Testers.
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
306 static StandardFrame* cast(StackFrame* frame) {
307 ASSERT(frame->is_standard());
308 return static_cast<StandardFrame*>(frame);
309 }
310
311 protected:
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
349class JavaScriptFrame: public StandardFrame {
350 public:
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
387 static JavaScriptFrame* cast(StackFrame* frame) {
388 ASSERT(frame->is_java_script());
389 return static_cast<JavaScriptFrame*>(frame);
390 }
391
392 protected:
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.
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.
416class ArgumentsAdaptorFrame: public JavaScriptFrame {
417 public:
418 virtual Type type() const { return ARGUMENTS_ADAPTOR; }
419
420 // Determine the code for the frame.
421 virtual Code* code() const;
422
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:
433 explicit ArgumentsAdaptorFrame(StackFrameIterator* iterator)
434 : JavaScriptFrame(iterator) { }
435
436 virtual Address GetCallerStackPointer() const;
437
438 private:
439 friend class StackFrameIterator;
440};
441
442
443class InternalFrame: public StandardFrame {
444 public:
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
453 static InternalFrame* cast(StackFrame* frame) {
454 ASSERT(frame->is_internal());
455 return static_cast<InternalFrame*>(frame);
456 }
457
458 protected:
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'.
471class ConstructFrame: public InternalFrame {
472 public:
473 virtual Type type() const { return CONSTRUCT; }
474
475 static ConstructFrame* cast(StackFrame* frame) {
476 ASSERT(frame->is_construct());
477 return static_cast<ConstructFrame*>(frame);
478 }
479
480 protected:
481 explicit ConstructFrame(StackFrameIterator* iterator)
482 : InternalFrame(iterator) { }
483
484 private:
485 friend class StackFrameIterator;
486};
487
488
489class 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
502 StackFrame* frame() const {
503 ASSERT(!done());
504 return frame_;
505 }
506
507 bool done() const { return frame_ == NULL; }
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
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.
544template<typename Iterator>
545class JavaScriptFrameIteratorTemp BASE_EMBEDDED {
546 public:
547 JavaScriptFrameIteratorTemp() { if (!done()) Advance(); }
548
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
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
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
581typedef 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.
588class StackTraceFrameIterator: public JavaScriptFrameIterator {
589 public:
590 StackTraceFrameIterator();
591 void Advance();
Leon Clarke4515c472010-02-03 11:58:03 +0000592
593 private:
594 bool IsValidFrame();
Steve Blocka7e24c12009-10-30 11:49:00 +0000595};
596
597
598class SafeStackFrameIterator BASE_EMBEDDED {
599 public:
600 SafeStackFrameIterator(Address fp, Address sp,
601 Address low_bound, Address high_bound);
602
603 StackFrame* frame() const {
604 ASSERT(is_working_iterator_);
605 return iterator_.frame();
606 }
607
608 bool done() const { return iteration_done_ ? true : iterator_.done(); }
609
610 void Advance();
611 void Reset();
612
Steve Blocka7e24c12009-10-30 11:49:00 +0000613 static bool IsWithinBounds(
614 Address low_bound, Address high_bound, Address addr) {
615 return low_bound <= addr && addr <= high_bound;
616 }
Leon Clarked91b9f72010-01-27 17:25:45 +0000617
618 private:
Steve Blocka7e24c12009-10-30 11:49:00 +0000619 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
637typedef JavaScriptFrameIteratorTemp<SafeStackFrameIterator>
638 SafeJavaScriptFrameIterator;
639
640
641class 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
650class 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_