blob: 662d2373f51e87dadb9943277727b8bd0fb40a36 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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 { namespace internal {
32
33typedef uint32_t RegList;
34
35// Get the number of registers in a given register list.
36int NumRegs(RegList list);
37
38// Return the code of the n-th saved register available to JavaScript.
39int JSCallerSavedCode(int n);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040
41
42// Forward declarations.
43class StackFrameIterator;
44class Top;
45class ThreadLocalTop;
46
47
48class StackHandler BASE_EMBEDDED {
49 public:
50 enum State {
51 ENTRY,
52 TRY_CATCH,
53 TRY_FINALLY
54 };
55
56 // Get the address of this stack handler.
57 inline Address address() const;
58
59 // Get the next stack handler in the chain.
60 inline StackHandler* next() const;
61
62 // Tells whether the given address is inside this handler.
63 inline bool includes(Address address) const;
64
65 // Garbage collection support.
66 inline void Iterate(ObjectVisitor* v) const;
67
68 // Conversion support.
69 static inline StackHandler* FromAddress(Address address);
70
71 // Testers
72 bool is_entry() { return state() == ENTRY; }
73 bool is_try_catch() { return state() == TRY_CATCH; }
74 bool is_try_finally() { return state() == TRY_FINALLY; }
75
76 // Garbage collection support.
77 void Cook(Code* code);
78 void Uncook(Code* code);
79
80 // TODO(1233780): Get rid of the code slot in stack handlers.
81 static const int kCodeNotPresent = 0;
82
83 private:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000084 // Accessors.
85 inline State state() const;
86
87 inline Address pc() const;
88 inline void set_pc(Address value);
mads.s.ager31e71382008-08-13 09:32:07 +000089
90 DISALLOW_IMPLICIT_CONSTRUCTORS(StackHandler);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091};
92
93
94#define STACK_FRAME_TYPE_LIST(V) \
95 V(ENTRY, EntryFrame) \
96 V(ENTRY_CONSTRUCT, EntryConstructFrame) \
97 V(EXIT, ExitFrame) \
98 V(EXIT_DEBUG, ExitDebugFrame) \
99 V(JAVA_SCRIPT, JavaScriptFrame) \
100 V(INTERNAL, InternalFrame) \
ager@chromium.org7c537e22008-10-16 08:43:32 +0000101 V(CONSTRUCT, ConstructFrame) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000102 V(ARGUMENTS_ADAPTOR, ArgumentsAdaptorFrame)
103
104
105// Abstract base class for all stack frames.
106class StackFrame BASE_EMBEDDED {
107 public:
108#define DECLARE_TYPE(type, ignore) type,
109 enum Type {
110 NONE = 0,
111 STACK_FRAME_TYPE_LIST(DECLARE_TYPE)
112 NUMBER_OF_TYPES
113 };
114#undef DECLARE_TYPE
115
116 // Opaque data type for identifying stack frames. Used extensively
117 // by the debugger.
118 enum Id { NO_ID = 0 };
119
120 // Type testers.
121 bool is_entry() const { return type() == ENTRY; }
122 bool is_entry_construct() const { return type() == ENTRY_CONSTRUCT; }
123 bool is_exit() const { return type() == EXIT; }
124 bool is_exit_debug() const { return type() == EXIT_DEBUG; }
125 bool is_java_script() const { return type() == JAVA_SCRIPT; }
126 bool is_arguments_adaptor() const { return type() == ARGUMENTS_ADAPTOR; }
127 bool is_internal() const { return type() == INTERNAL; }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000128 bool is_construct() const { return type() == CONSTRUCT; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000129 virtual bool is_standard() const { return false; }
130
131 // Accessors.
132 Address sp() const { return state_.sp; }
133 Address fp() const { return state_.fp; }
134 Address pp() const { return GetCallerStackPointer(); }
135
136 Address pc() const { return *pc_address(); }
137 void set_pc(Address pc) { *pc_address() = pc; }
138
139 Address* pc_address() const { return state_.pc_address; }
140
141 // Get the id of this stack frame.
142 Id id() const { return static_cast<Id>(OffsetFrom(pp())); }
143
144 // Checks if this frame includes any stack handlers.
145 bool HasHandler() const;
146
147 // Get the type of this frame.
148 virtual Type type() const = 0;
149
150 // Get the code associated with this frame.
151 virtual Code* FindCode() const = 0;
152
153 // Garbage collection support.
154 static void CookFramesForThread(ThreadLocalTop* thread);
155 static void UncookFramesForThread(ThreadLocalTop* thread);
156
157 virtual void Iterate(ObjectVisitor* v) const { }
158
159 // Printing support.
160 enum PrintMode { OVERVIEW, DETAILS };
161 virtual void Print(StringStream* accumulator,
162 PrintMode mode,
163 int index) const { }
164
165 protected:
166 struct State {
167 Address sp;
168 Address fp;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000169 Address* pc_address;
170 };
171
172 explicit StackFrame(StackFrameIterator* iterator) : iterator_(iterator) { }
173 virtual ~StackFrame() { }
174
175 // Compute the stack pointer for the calling frame.
176 virtual Address GetCallerStackPointer() const = 0;
177
178 // Printing support.
179 static void PrintIndex(StringStream* accumulator,
180 PrintMode mode,
181 int index);
182
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000183 // Get the top handler from the current stack iterator.
184 inline StackHandler* top_handler() const;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000185
186 // Compute the stack frame type for the given state.
187 static Type ComputeType(State* state);
188
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000189 private:
190 const StackFrameIterator* iterator_;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000191 State state_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000192
193 // Get the type and the state of the calling frame.
194 virtual Type GetCallerState(State* state) const = 0;
195
196 // Cooking/uncooking support.
197 void Cook();
198 void Uncook();
199
200 friend class StackFrameIterator;
201 friend class StackHandlerIterator;
mads.s.ager31e71382008-08-13 09:32:07 +0000202
203 DISALLOW_IMPLICIT_CONSTRUCTORS(StackFrame);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000204};
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* FindCode() 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 Type GetCallerState(State* state) const;
232
233 friend class StackFrameIterator;
234};
235
236
237class EntryConstructFrame: public EntryFrame {
238 public:
239 virtual Type type() const { return ENTRY_CONSTRUCT; }
240
241 virtual Code* FindCode() const;
242
243 static EntryConstructFrame* cast(StackFrame* frame) {
244 ASSERT(frame->is_entry_construct());
245 return static_cast<EntryConstructFrame*>(frame);
246 }
247
248 protected:
249 explicit EntryConstructFrame(StackFrameIterator* iterator)
250 : EntryFrame(iterator) { }
251
252 private:
253 friend class StackFrameIterator;
254};
255
256
257// Exit frames are used to exit JavaScript execution and go to C.
258class ExitFrame: public StackFrame {
259 public:
260 virtual Type type() const { return EXIT; }
261
262 virtual Code* FindCode() const;
263
264 // Garbage colletion support.
265 virtual void Iterate(ObjectVisitor* v) const;
266
267 static ExitFrame* cast(StackFrame* frame) {
268 ASSERT(frame->is_exit());
269 return static_cast<ExitFrame*>(frame);
270 }
271
272 // Compute the state and type of an exit frame given a frame
273 // pointer. Used when constructing the first stack frame seen by an
274 // iterator and the frames following entry frames.
275 static Type GetStateForFramePointer(Address fp, State* state);
276
277 protected:
278 explicit ExitFrame(StackFrameIterator* iterator) : StackFrame(iterator) { }
279
280 virtual Address GetCallerStackPointer() const;
281
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000282 private:
283 virtual Type GetCallerState(State* state) const;
284
285 friend class StackFrameIterator;
286};
287
288
289class ExitDebugFrame: public ExitFrame {
290 public:
291 virtual Type type() const { return EXIT_DEBUG; }
292
293 virtual Code* FindCode() const;
294
295 static ExitDebugFrame* cast(StackFrame* frame) {
296 ASSERT(frame->is_exit_debug());
297 return static_cast<ExitDebugFrame*>(frame);
298 }
299
300 protected:
301 explicit ExitDebugFrame(StackFrameIterator* iterator)
302 : ExitFrame(iterator) { }
303
304 private:
305 friend class StackFrameIterator;
306};
307
308
309class StandardFrame: public StackFrame {
310 public:
311 // Testers.
312 virtual bool is_standard() const { return true; }
313
314 // Accessors.
315 inline Object* context() const;
316
317 // Access the expressions in the stack frame including locals.
318 inline Object* GetExpression(int index) const;
319 inline void SetExpression(int index, Object* value);
320 int ComputeExpressionsCount() const;
321
322 static StandardFrame* cast(StackFrame* frame) {
323 ASSERT(frame->is_standard());
324 return static_cast<StandardFrame*>(frame);
325 }
326
327 protected:
328 explicit StandardFrame(StackFrameIterator* iterator)
329 : StackFrame(iterator) { }
330
331 virtual Type GetCallerState(State* state) const;
332
333 // Accessors.
334 inline Address caller_sp() const;
335 inline Address caller_fp() const;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000336 inline Address caller_pc() const;
337
338 // Computes the address of the PC field in the standard frame given
339 // by the provided frame pointer.
340 static inline Address ComputePCAddress(Address fp);
341
342 // Iterate over expression stack including stack handlers, locals,
343 // and parts of the fixed part including context and code fields.
344 void IterateExpressions(ObjectVisitor* v) const;
345
346 // Returns the address of the n'th expression stack element.
347 Address GetExpressionAddress(int n) const;
348
349 // Determines if the n'th expression stack element is in a stack
350 // handler or not. Requires traversing all handlers in this frame.
351 bool IsExpressionInsideHandler(int n) const;
352
353 // Determines if the standard frame for the given frame pointer is
354 // an arguments adaptor frame.
355 static inline bool IsArgumentsAdaptorFrame(Address fp);
356
ager@chromium.org7c537e22008-10-16 08:43:32 +0000357 // Determines if the standard frame for the given frame pointer is a
358 // construct frame.
359 static inline bool IsConstructFrame(Address fp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360
361 private:
362 friend class StackFrame;
363};
364
365
366class JavaScriptFrame: public StandardFrame {
367 public:
368 virtual Type type() const { return JAVA_SCRIPT; }
369
370 // Accessors.
371 inline Object* function() const;
372 inline Object* receiver() const;
373 inline void set_receiver(Object* value);
374
375 // Access the parameters.
376 Object* GetParameter(int index) const;
377 int ComputeParametersCount() const;
378
379 // Temporary way of getting access to the number of parameters
380 // passed on the stack by the caller. Once argument adaptor frames
381 // has been introduced on ARM, this number will always match the
382 // computed parameters count.
383 int GetProvidedParametersCount() const;
384
ager@chromium.org7c537e22008-10-16 08:43:32 +0000385 // Check if this frame is a constructor frame invoked through 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000386 bool IsConstructor() const;
387
388 // Check if this frame has "adapted" arguments in the sense that the
389 // actual passed arguments are available in an arguments adaptor
390 // frame below it on the stack.
391 inline bool has_adapted_arguments() const;
392
393 // Garbage colletion support.
394 virtual void Iterate(ObjectVisitor* v) const;
395
396 // Printing support.
397 virtual void Print(StringStream* accumulator,
398 PrintMode mode,
399 int index) const;
400
401 // Determine the code for the frame.
402 virtual Code* FindCode() const;
403
404 static JavaScriptFrame* cast(StackFrame* frame) {
405 ASSERT(frame->is_java_script());
406 return static_cast<JavaScriptFrame*>(frame);
407 }
408
409 protected:
410 explicit JavaScriptFrame(StackFrameIterator* iterator)
411 : StandardFrame(iterator) { }
412
413 virtual Address GetCallerStackPointer() const;
414
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000415 private:
416 friend class StackFrameIterator;
417};
418
419
420// Arguments adaptor frames are automatically inserted below
421// JavaScript frames when the actual number of parameters does not
422// match the formal number of parameters.
423class ArgumentsAdaptorFrame: public JavaScriptFrame {
424 public:
425 // This sentinel value is temporarily used to distinguish arguments
426 // adaptor frames from ordinary JavaScript frames. If a frame has
427 // the sentinel as its context, it is an arguments adaptor frame. It
428 // must be tagged as a small integer to avoid GC issues. Crud.
429 enum {
430 SENTINEL = (1 << kSmiTagSize) | kSmiTag
431 };
432
433 virtual Type type() const { return ARGUMENTS_ADAPTOR; }
434
435 // Determine the code for the frame.
436 virtual Code* FindCode() 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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000462 // Garbage colletion support.
463 virtual void Iterate(ObjectVisitor* v) const;
464
465 // Determine the code for the frame.
466 virtual Code* FindCode() 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
ager@chromium.org7c537e22008-10-16 08:43:32 +0000484// 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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000504class 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 StackFrame* frame() const {
513 ASSERT(!done());
514 return frame_;
515 }
516
517 bool done() const { return frame_ == NULL; }
518 void Advance();
519
520 // Go back to the first frame.
521 void Reset();
522
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000523 private:
524#define DECLARE_SINGLETON(ignore, type) type type##_;
525 STACK_FRAME_TYPE_LIST(DECLARE_SINGLETON)
526#undef DECLARE_SINGLETON
527 StackFrame* frame_;
528 StackHandler* handler_;
kasper.lund7276f142008-07-30 08:49:36 +0000529 ThreadLocalTop* thread_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000530
531 StackHandler* handler() const {
532 ASSERT(!done());
533 return handler_;
534 }
535
536 // Get the type-specific frame singleton in a given state.
537 StackFrame* SingletonFor(StackFrame::Type type, StackFrame::State* state);
538
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000539 friend class StackFrame;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000540 DISALLOW_COPY_AND_ASSIGN(StackFrameIterator);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000541};
542
543
544// Iterator that supports iterating through all JavaScript frames.
545class JavaScriptFrameIterator BASE_EMBEDDED {
546 public:
547 JavaScriptFrameIterator() { if (!done()) Advance(); }
548
549 explicit JavaScriptFrameIterator(ThreadLocalTop* thread) : iterator_(thread) {
550 if (!done()) Advance();
551 }
552
553 // Skip frames until the frame with the given id is reached.
554 explicit JavaScriptFrameIterator(StackFrame::Id id);
555
556 inline JavaScriptFrame* frame() const;
557
558 bool done() const { return iterator_.done(); }
559 void Advance();
560
561 // Advance to the frame holding the arguments for the current
562 // frame. This only affects the current frame if it has adapted
563 // arguments.
564 void AdvanceToArgumentsFrame();
565
566 // Go back to the first frame.
567 void Reset();
568
569 private:
570 StackFrameIterator iterator_;
571};
572
573
574class StackFrameLocator BASE_EMBEDDED {
575 public:
576 // Find the nth JavaScript frame on the stack. The caller must
577 // guarantee that such a frame exists.
578 JavaScriptFrame* FindJavaScriptFrame(int n);
579
580 private:
581 StackFrameIterator iterator_;
582};
583
584
585} } // namespace v8::internal
586
587#endif // V8_FRAMES_H_