Home | History | Annotate | Download | only in src
      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