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 #include "v8.h" 29 30 #include "frames-inl.h" 31 #include "mark-compact.h" 32 #include "scopeinfo.h" 33 #include "string-stream.h" 34 #include "top.h" 35 #include "zone-inl.h" 36 37 namespace v8 { 38 namespace internal { 39 40 // Iterator that supports traversing the stack handlers of a 41 // particular frame. Needs to know the top of the handler chain. 42 class StackHandlerIterator BASE_EMBEDDED { 43 public: 44 StackHandlerIterator(const StackFrame* frame, StackHandler* handler) 45 : limit_(frame->fp()), handler_(handler) { 46 // Make sure the handler has already been unwound to this frame. 47 ASSERT(frame->sp() <= handler->address()); 48 } 49 50 StackHandler* handler() const { return handler_; } 51 52 bool done() { 53 return handler_ == NULL || handler_->address() > limit_; 54 } 55 void Advance() { 56 ASSERT(!done()); 57 handler_ = handler_->next(); 58 } 59 60 private: 61 const Address limit_; 62 StackHandler* handler_; 63 }; 64 65 66 // ------------------------------------------------------------------------- 67 68 69 #define INITIALIZE_SINGLETON(type, field) field##_(this), 70 StackFrameIterator::StackFrameIterator() 71 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON) 72 frame_(NULL), handler_(NULL), thread_(Top::GetCurrentThread()), 73 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) { 74 Reset(); 75 } 76 StackFrameIterator::StackFrameIterator(ThreadLocalTop* t) 77 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON) 78 frame_(NULL), handler_(NULL), thread_(t), 79 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) { 80 Reset(); 81 } 82 StackFrameIterator::StackFrameIterator(bool use_top, Address fp, Address sp) 83 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON) 84 frame_(NULL), handler_(NULL), 85 thread_(use_top ? Top::GetCurrentThread() : NULL), 86 fp_(use_top ? NULL : fp), sp_(sp), 87 advance_(use_top ? &StackFrameIterator::AdvanceWithHandler : 88 &StackFrameIterator::AdvanceWithoutHandler) { 89 if (use_top || fp != NULL) { 90 Reset(); 91 } 92 JavaScriptFrame_.DisableHeapAccess(); 93 } 94 95 #undef INITIALIZE_SINGLETON 96 97 98 void StackFrameIterator::AdvanceWithHandler() { 99 ASSERT(!done()); 100 // Compute the state of the calling frame before restoring 101 // callee-saved registers and unwinding handlers. This allows the 102 // frame code that computes the caller state to access the top 103 // handler and the value of any callee-saved register if needed. 104 StackFrame::State state; 105 StackFrame::Type type = frame_->GetCallerState(&state); 106 107 // Unwind handlers corresponding to the current frame. 108 StackHandlerIterator it(frame_, handler_); 109 while (!it.done()) it.Advance(); 110 handler_ = it.handler(); 111 112 // Advance to the calling frame. 113 frame_ = SingletonFor(type, &state); 114 115 // When we're done iterating over the stack frames, the handler 116 // chain must have been completely unwound. 117 ASSERT(!done() || handler_ == NULL); 118 } 119 120 121 void StackFrameIterator::AdvanceWithoutHandler() { 122 // A simpler version of Advance which doesn't care about handler. 123 ASSERT(!done()); 124 StackFrame::State state; 125 StackFrame::Type type = frame_->GetCallerState(&state); 126 frame_ = SingletonFor(type, &state); 127 } 128 129 130 void StackFrameIterator::Reset() { 131 StackFrame::State state; 132 StackFrame::Type type; 133 if (thread_ != NULL) { 134 type = ExitFrame::GetStateForFramePointer(Top::c_entry_fp(thread_), &state); 135 handler_ = StackHandler::FromAddress(Top::handler(thread_)); 136 } else { 137 ASSERT(fp_ != NULL); 138 state.fp = fp_; 139 state.sp = sp_; 140 state.pc_address = 141 reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp_)); 142 type = StackFrame::ComputeType(&state); 143 if (SingletonFor(type) == NULL) return; 144 } 145 frame_ = SingletonFor(type, &state); 146 } 147 148 149 StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type, 150 StackFrame::State* state) { 151 if (type == StackFrame::NONE) return NULL; 152 StackFrame* result = SingletonFor(type); 153 ASSERT(result != NULL); 154 result->state_ = *state; 155 return result; 156 } 157 158 159 StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type) { 160 #define FRAME_TYPE_CASE(type, field) \ 161 case StackFrame::type: result = &field##_; break; 162 163 StackFrame* result = NULL; 164 switch (type) { 165 case StackFrame::NONE: return NULL; 166 STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE) 167 default: break; 168 } 169 return result; 170 171 #undef FRAME_TYPE_CASE 172 } 173 174 175 // ------------------------------------------------------------------------- 176 177 178 StackTraceFrameIterator::StackTraceFrameIterator() { 179 if (!done() && !IsValidFrame()) Advance(); 180 } 181 182 183 void StackTraceFrameIterator::Advance() { 184 while (true) { 185 JavaScriptFrameIterator::Advance(); 186 if (done()) return; 187 if (IsValidFrame()) return; 188 } 189 } 190 191 bool StackTraceFrameIterator::IsValidFrame() { 192 if (!frame()->function()->IsJSFunction()) return false; 193 Object* script = JSFunction::cast(frame()->function())->shared()->script(); 194 // Don't show functions from native scripts to user. 195 return (script->IsScript() && 196 Script::TYPE_NATIVE != Script::cast(script)->type()->value()); 197 } 198 199 200 // ------------------------------------------------------------------------- 201 202 203 SafeStackFrameIterator::SafeStackFrameIterator( 204 Address fp, Address sp, Address low_bound, Address high_bound) : 205 low_bound_(low_bound), high_bound_(high_bound), 206 is_valid_top_( 207 IsWithinBounds(low_bound, high_bound, 208 Top::c_entry_fp(Top::GetCurrentThread())) && 209 Top::handler(Top::GetCurrentThread()) != NULL), 210 is_valid_fp_(IsWithinBounds(low_bound, high_bound, fp)), 211 is_working_iterator_(is_valid_top_ || is_valid_fp_), 212 iteration_done_(!is_working_iterator_), 213 iterator_(is_valid_top_, is_valid_fp_ ? fp : NULL, sp) { 214 } 215 216 217 void SafeStackFrameIterator::Advance() { 218 ASSERT(is_working_iterator_); 219 ASSERT(!done()); 220 StackFrame* last_frame = iterator_.frame(); 221 Address last_sp = last_frame->sp(), last_fp = last_frame->fp(); 222 // Before advancing to the next stack frame, perform pointer validity tests 223 iteration_done_ = !IsValidFrame(last_frame) || 224 !CanIterateHandles(last_frame, iterator_.handler()) || 225 !IsValidCaller(last_frame); 226 if (iteration_done_) return; 227 228 iterator_.Advance(); 229 if (iterator_.done()) return; 230 // Check that we have actually moved to the previous frame in the stack 231 StackFrame* prev_frame = iterator_.frame(); 232 iteration_done_ = prev_frame->sp() < last_sp || prev_frame->fp() < last_fp; 233 } 234 235 236 bool SafeStackFrameIterator::CanIterateHandles(StackFrame* frame, 237 StackHandler* handler) { 238 // If StackIterator iterates over StackHandles, verify that 239 // StackHandlerIterator can be instantiated (see StackHandlerIterator 240 // constructor.) 241 return !is_valid_top_ || (frame->sp() <= handler->address()); 242 } 243 244 245 bool SafeStackFrameIterator::IsValidFrame(StackFrame* frame) const { 246 return IsValidStackAddress(frame->sp()) && IsValidStackAddress(frame->fp()); 247 } 248 249 250 bool SafeStackFrameIterator::IsValidCaller(StackFrame* frame) { 251 StackFrame::State state; 252 if (frame->is_entry() || frame->is_entry_construct()) { 253 // See EntryFrame::GetCallerState. It computes the caller FP address 254 // and calls ExitFrame::GetStateForFramePointer on it. We need to be 255 // sure that caller FP address is valid. 256 Address caller_fp = Memory::Address_at( 257 frame->fp() + EntryFrameConstants::kCallerFPOffset); 258 if (!IsValidStackAddress(caller_fp)) { 259 return false; 260 } 261 } else if (frame->is_arguments_adaptor()) { 262 // See ArgumentsAdaptorFrame::GetCallerStackPointer. It assumes that 263 // the number of arguments is stored on stack as Smi. We need to check 264 // that it really an Smi. 265 Object* number_of_args = reinterpret_cast<ArgumentsAdaptorFrame*>(frame)-> 266 GetExpression(0); 267 if (!number_of_args->IsSmi()) { 268 return false; 269 } 270 } 271 frame->ComputeCallerState(&state); 272 return IsValidStackAddress(state.sp) && IsValidStackAddress(state.fp) && 273 iterator_.SingletonFor(frame->GetCallerState(&state)) != NULL; 274 } 275 276 277 void SafeStackFrameIterator::Reset() { 278 if (is_working_iterator_) { 279 iterator_.Reset(); 280 iteration_done_ = false; 281 } 282 } 283 284 285 // ------------------------------------------------------------------------- 286 287 288 #ifdef ENABLE_LOGGING_AND_PROFILING 289 SafeStackTraceFrameIterator::SafeStackTraceFrameIterator( 290 Address fp, Address sp, Address low_bound, Address high_bound) : 291 SafeJavaScriptFrameIterator(fp, sp, low_bound, high_bound) { 292 if (!done() && !frame()->is_java_script()) Advance(); 293 } 294 295 296 void SafeStackTraceFrameIterator::Advance() { 297 while (true) { 298 SafeJavaScriptFrameIterator::Advance(); 299 if (done()) return; 300 if (frame()->is_java_script()) return; 301 } 302 } 303 #endif 304 305 306 // ------------------------------------------------------------------------- 307 308 309 void StackHandler::Cook(Code* code) { 310 ASSERT(MarkCompactCollector::IsCompacting()); 311 ASSERT(code->contains(pc())); 312 set_pc(AddressFrom<Address>(pc() - code->instruction_start())); 313 } 314 315 316 void StackHandler::Uncook(Code* code) { 317 ASSERT(MarkCompactCollector::HasCompacted()); 318 set_pc(code->instruction_start() + OffsetFrom(pc())); 319 ASSERT(code->contains(pc())); 320 } 321 322 323 // ------------------------------------------------------------------------- 324 325 326 bool StackFrame::HasHandler() const { 327 StackHandlerIterator it(this, top_handler()); 328 return !it.done(); 329 } 330 331 332 void StackFrame::CookFramesForThread(ThreadLocalTop* thread) { 333 // Only cooking frames when the collector is compacting and thus moving code 334 // around. 335 ASSERT(MarkCompactCollector::IsCompacting()); 336 ASSERT(!thread->stack_is_cooked()); 337 for (StackFrameIterator it(thread); !it.done(); it.Advance()) { 338 it.frame()->Cook(); 339 } 340 thread->set_stack_is_cooked(true); 341 } 342 343 344 void StackFrame::UncookFramesForThread(ThreadLocalTop* thread) { 345 // Only uncooking frames when the collector is compacting and thus moving code 346 // around. 347 ASSERT(MarkCompactCollector::HasCompacted()); 348 ASSERT(thread->stack_is_cooked()); 349 for (StackFrameIterator it(thread); !it.done(); it.Advance()) { 350 it.frame()->Uncook(); 351 } 352 thread->set_stack_is_cooked(false); 353 } 354 355 356 void StackFrame::Cook() { 357 Code* code = this->code(); 358 ASSERT(code->IsCode()); 359 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) { 360 it.handler()->Cook(code); 361 } 362 ASSERT(code->contains(pc())); 363 set_pc(AddressFrom<Address>(pc() - code->instruction_start())); 364 } 365 366 367 void StackFrame::Uncook() { 368 Code* code = this->code(); 369 ASSERT(code->IsCode()); 370 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) { 371 it.handler()->Uncook(code); 372 } 373 set_pc(code->instruction_start() + OffsetFrom(pc())); 374 ASSERT(code->contains(pc())); 375 } 376 377 378 StackFrame::Type StackFrame::GetCallerState(State* state) const { 379 ComputeCallerState(state); 380 return ComputeType(state); 381 } 382 383 384 Code* EntryFrame::code() const { 385 return Heap::js_entry_code(); 386 } 387 388 389 void EntryFrame::ComputeCallerState(State* state) const { 390 GetCallerState(state); 391 } 392 393 394 StackFrame::Type EntryFrame::GetCallerState(State* state) const { 395 const int offset = EntryFrameConstants::kCallerFPOffset; 396 Address fp = Memory::Address_at(this->fp() + offset); 397 return ExitFrame::GetStateForFramePointer(fp, state); 398 } 399 400 401 Code* EntryConstructFrame::code() const { 402 return Heap::js_construct_entry_code(); 403 } 404 405 406 Object*& ExitFrame::code_slot() const { 407 const int offset = ExitFrameConstants::kCodeOffset; 408 return Memory::Object_at(fp() + offset); 409 } 410 411 412 Code* ExitFrame::code() const { 413 return Code::cast(code_slot()); 414 } 415 416 417 void ExitFrame::ComputeCallerState(State* state) const { 418 // Setup the caller state. 419 state->sp = caller_sp(); 420 state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset); 421 state->pc_address 422 = reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset); 423 } 424 425 426 Address ExitFrame::GetCallerStackPointer() const { 427 return fp() + ExitFrameConstants::kCallerSPDisplacement; 428 } 429 430 431 Address StandardFrame::GetExpressionAddress(int n) const { 432 const int offset = StandardFrameConstants::kExpressionsOffset; 433 return fp() + offset - n * kPointerSize; 434 } 435 436 437 int StandardFrame::ComputeExpressionsCount() const { 438 const int offset = 439 StandardFrameConstants::kExpressionsOffset + kPointerSize; 440 Address base = fp() + offset; 441 Address limit = sp(); 442 ASSERT(base >= limit); // stack grows downwards 443 // Include register-allocated locals in number of expressions. 444 return static_cast<int>((base - limit) / kPointerSize); 445 } 446 447 448 void StandardFrame::ComputeCallerState(State* state) const { 449 state->sp = caller_sp(); 450 state->fp = caller_fp(); 451 state->pc_address = reinterpret_cast<Address*>(ComputePCAddress(fp())); 452 } 453 454 455 bool StandardFrame::IsExpressionInsideHandler(int n) const { 456 Address address = GetExpressionAddress(n); 457 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) { 458 if (it.handler()->includes(address)) return true; 459 } 460 return false; 461 } 462 463 464 Object* JavaScriptFrame::GetParameter(int index) const { 465 ASSERT(index >= 0 && index < ComputeParametersCount()); 466 const int offset = JavaScriptFrameConstants::kParam0Offset; 467 return Memory::Object_at(caller_sp() + offset - (index * kPointerSize)); 468 } 469 470 471 int JavaScriptFrame::ComputeParametersCount() const { 472 Address base = caller_sp() + JavaScriptFrameConstants::kReceiverOffset; 473 Address limit = fp() + JavaScriptFrameConstants::kSavedRegistersOffset; 474 return static_cast<int>((base - limit) / kPointerSize); 475 } 476 477 478 bool JavaScriptFrame::IsConstructor() const { 479 Address fp = caller_fp(); 480 if (has_adapted_arguments()) { 481 // Skip the arguments adaptor frame and look at the real caller. 482 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset); 483 } 484 return IsConstructFrame(fp); 485 } 486 487 488 Code* JavaScriptFrame::code() const { 489 JSFunction* function = JSFunction::cast(this->function()); 490 return function->shared()->code(); 491 } 492 493 494 Code* ArgumentsAdaptorFrame::code() const { 495 return Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline); 496 } 497 498 499 Code* InternalFrame::code() const { 500 const int offset = InternalFrameConstants::kCodeOffset; 501 Object* code = Memory::Object_at(fp() + offset); 502 ASSERT(code != NULL); 503 return Code::cast(code); 504 } 505 506 507 void StackFrame::PrintIndex(StringStream* accumulator, 508 PrintMode mode, 509 int index) { 510 accumulator->Add((mode == OVERVIEW) ? "%5d: " : "[%d]: ", index); 511 } 512 513 514 void JavaScriptFrame::Print(StringStream* accumulator, 515 PrintMode mode, 516 int index) const { 517 HandleScope scope; 518 Object* receiver = this->receiver(); 519 Object* function = this->function(); 520 521 accumulator->PrintSecurityTokenIfChanged(function); 522 PrintIndex(accumulator, mode, index); 523 Code* code = NULL; 524 if (IsConstructor()) accumulator->Add("new "); 525 accumulator->PrintFunction(function, receiver, &code); 526 accumulator->Add("(this=%o", receiver); 527 528 // Get scope information for nicer output, if possible. If code is 529 // NULL, or doesn't contain scope info, info will return 0 for the 530 // number of parameters, stack slots, or context slots. 531 ScopeInfo<PreallocatedStorage> info(code); 532 533 // Print the parameters. 534 int parameters_count = ComputeParametersCount(); 535 for (int i = 0; i < parameters_count; i++) { 536 accumulator->Add(","); 537 // If we have a name for the parameter we print it. Nameless 538 // parameters are either because we have more actual parameters 539 // than formal parameters or because we have no scope information. 540 if (i < info.number_of_parameters()) { 541 accumulator->PrintName(*info.parameter_name(i)); 542 accumulator->Add("="); 543 } 544 accumulator->Add("%o", GetParameter(i)); 545 } 546 547 accumulator->Add(")"); 548 if (mode == OVERVIEW) { 549 accumulator->Add("\n"); 550 return; 551 } 552 accumulator->Add(" {\n"); 553 554 // Compute the number of locals and expression stack elements. 555 int stack_locals_count = info.number_of_stack_slots(); 556 int heap_locals_count = info.number_of_context_slots(); 557 int expressions_count = ComputeExpressionsCount(); 558 559 // Print stack-allocated local variables. 560 if (stack_locals_count > 0) { 561 accumulator->Add(" // stack-allocated locals\n"); 562 } 563 for (int i = 0; i < stack_locals_count; i++) { 564 accumulator->Add(" var "); 565 accumulator->PrintName(*info.stack_slot_name(i)); 566 accumulator->Add(" = "); 567 if (i < expressions_count) { 568 accumulator->Add("%o", GetExpression(i)); 569 } else { 570 accumulator->Add("// no expression found - inconsistent frame?"); 571 } 572 accumulator->Add("\n"); 573 } 574 575 // Try to get hold of the context of this frame. 576 Context* context = NULL; 577 if (this->context() != NULL && this->context()->IsContext()) { 578 context = Context::cast(this->context()); 579 } 580 581 // Print heap-allocated local variables. 582 if (heap_locals_count > Context::MIN_CONTEXT_SLOTS) { 583 accumulator->Add(" // heap-allocated locals\n"); 584 } 585 for (int i = Context::MIN_CONTEXT_SLOTS; i < heap_locals_count; i++) { 586 accumulator->Add(" var "); 587 accumulator->PrintName(*info.context_slot_name(i)); 588 accumulator->Add(" = "); 589 if (context != NULL) { 590 if (i < context->length()) { 591 accumulator->Add("%o", context->get(i)); 592 } else { 593 accumulator->Add( 594 "// warning: missing context slot - inconsistent frame?"); 595 } 596 } else { 597 accumulator->Add("// warning: no context found - inconsistent frame?"); 598 } 599 accumulator->Add("\n"); 600 } 601 602 // Print the expression stack. 603 int expressions_start = stack_locals_count; 604 if (expressions_start < expressions_count) { 605 accumulator->Add(" // expression stack (top to bottom)\n"); 606 } 607 for (int i = expressions_count - 1; i >= expressions_start; i--) { 608 if (IsExpressionInsideHandler(i)) continue; 609 accumulator->Add(" [%02d] : %o\n", i, GetExpression(i)); 610 } 611 612 // Print details about the function. 613 if (FLAG_max_stack_trace_source_length != 0 && code != NULL) { 614 SharedFunctionInfo* shared = JSFunction::cast(function)->shared(); 615 accumulator->Add("--------- s o u r c e c o d e ---------\n"); 616 shared->SourceCodePrint(accumulator, FLAG_max_stack_trace_source_length); 617 accumulator->Add("\n-----------------------------------------\n"); 618 } 619 620 accumulator->Add("}\n\n"); 621 } 622 623 624 void ArgumentsAdaptorFrame::Print(StringStream* accumulator, 625 PrintMode mode, 626 int index) const { 627 int actual = ComputeParametersCount(); 628 int expected = -1; 629 Object* function = this->function(); 630 if (function->IsJSFunction()) { 631 expected = JSFunction::cast(function)->shared()->formal_parameter_count(); 632 } 633 634 PrintIndex(accumulator, mode, index); 635 accumulator->Add("arguments adaptor frame: %d->%d", actual, expected); 636 if (mode == OVERVIEW) { 637 accumulator->Add("\n"); 638 return; 639 } 640 accumulator->Add(" {\n"); 641 642 // Print actual arguments. 643 if (actual > 0) accumulator->Add(" // actual arguments\n"); 644 for (int i = 0; i < actual; i++) { 645 accumulator->Add(" [%02d] : %o", i, GetParameter(i)); 646 if (expected != -1 && i >= expected) { 647 accumulator->Add(" // not passed to callee"); 648 } 649 accumulator->Add("\n"); 650 } 651 652 accumulator->Add("}\n\n"); 653 } 654 655 656 void EntryFrame::Iterate(ObjectVisitor* v) const { 657 StackHandlerIterator it(this, top_handler()); 658 ASSERT(!it.done()); 659 StackHandler* handler = it.handler(); 660 ASSERT(handler->is_entry()); 661 handler->Iterate(v); 662 // Make sure that there's the entry frame does not contain more than 663 // one stack handler. 664 #ifdef DEBUG 665 it.Advance(); 666 ASSERT(it.done()); 667 #endif 668 } 669 670 671 void StandardFrame::IterateExpressions(ObjectVisitor* v) const { 672 const int offset = StandardFrameConstants::kContextOffset; 673 Object** base = &Memory::Object_at(sp()); 674 Object** limit = &Memory::Object_at(fp() + offset) + 1; 675 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) { 676 StackHandler* handler = it.handler(); 677 // Traverse pointers down to - but not including - the next 678 // handler in the handler chain. Update the base to skip the 679 // handler and allow the handler to traverse its own pointers. 680 const Address address = handler->address(); 681 v->VisitPointers(base, reinterpret_cast<Object**>(address)); 682 base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize); 683 // Traverse the pointers in the handler itself. 684 handler->Iterate(v); 685 } 686 v->VisitPointers(base, limit); 687 } 688 689 690 void JavaScriptFrame::Iterate(ObjectVisitor* v) const { 691 IterateExpressions(v); 692 693 // Traverse callee-saved registers, receiver, and parameters. 694 const int kBaseOffset = JavaScriptFrameConstants::kSavedRegistersOffset; 695 const int kLimitOffset = JavaScriptFrameConstants::kReceiverOffset; 696 Object** base = &Memory::Object_at(fp() + kBaseOffset); 697 Object** limit = &Memory::Object_at(caller_sp() + kLimitOffset) + 1; 698 v->VisitPointers(base, limit); 699 } 700 701 702 void InternalFrame::Iterate(ObjectVisitor* v) const { 703 // Internal frames only have object pointers on the expression stack 704 // as they never have any arguments. 705 IterateExpressions(v); 706 } 707 708 709 // ------------------------------------------------------------------------- 710 711 712 JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) { 713 ASSERT(n >= 0); 714 for (int i = 0; i <= n; i++) { 715 while (!iterator_.frame()->is_java_script()) iterator_.Advance(); 716 if (i == n) return JavaScriptFrame::cast(iterator_.frame()); 717 iterator_.Advance(); 718 } 719 UNREACHABLE(); 720 return NULL; 721 } 722 723 724 // ------------------------------------------------------------------------- 725 726 727 int NumRegs(RegList reglist) { 728 int n = 0; 729 while (reglist != 0) { 730 n++; 731 reglist &= reglist - 1; // clear one bit 732 } 733 return n; 734 } 735 736 737 int JSCallerSavedCode(int n) { 738 static int reg_code[kNumJSCallerSaved]; 739 static bool initialized = false; 740 if (!initialized) { 741 initialized = true; 742 int i = 0; 743 for (int r = 0; r < kNumRegs; r++) 744 if ((kJSCallerSaved & (1 << r)) != 0) 745 reg_code[i++] = r; 746 747 ASSERT(i == kNumJSCallerSaved); 748 } 749 ASSERT(0 <= n && n < kNumJSCallerSaved); 750 return reg_code[n]; 751 } 752 753 754 } } // namespace v8::internal 755