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