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