The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / frames.cc @ 40c0f755

History | View | Annotate | Download (22.7 KB)

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 { namespace internal {
38

    
39
// Iterator that supports traversing the stack handlers of a
40
// particular frame. Needs to know the top of the handler chain.
41
class StackHandlerIterator BASE_EMBEDDED {
42
 public:
43
  StackHandlerIterator(const StackFrame* frame, StackHandler* handler)
44
      : limit_(frame->fp()), handler_(handler) {
45
    // Make sure the handler has already been unwound to this frame.
46
    ASSERT(frame->sp() <= handler->address());
47
  }
48

    
49
  StackHandler* handler() const { return handler_; }
50

    
51
  bool done() { return handler_->address() > limit_; }
52
  void Advance() {
53
    ASSERT(!done());
54
    handler_ = handler_->next();
55
  }
56

    
57
 private:
58
  const Address limit_;
59
  StackHandler* handler_;
60
};
61

    
62

    
63
// -------------------------------------------------------------------------
64

    
65

    
66
#define INITIALIZE_SINGLETON(type, field) field##_(this),
67
StackFrameIterator::StackFrameIterator()
68
    : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
69
      frame_(NULL), handler_(NULL), thread_(Top::GetCurrentThread()),
70
      fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
71
  Reset();
72
}
73
StackFrameIterator::StackFrameIterator(ThreadLocalTop* t)
74
    : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
75
      frame_(NULL), handler_(NULL), thread_(t),
76
      fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
77
  Reset();
78
}
79
StackFrameIterator::StackFrameIterator(bool use_top, Address fp, Address sp)
80
    : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
81
      frame_(NULL), handler_(NULL),
82
      thread_(use_top ? Top::GetCurrentThread() : NULL),
83
      fp_(use_top ? NULL : fp), sp_(sp),
84
      advance_(use_top ? &StackFrameIterator::AdvanceWithHandler :
85
               &StackFrameIterator::AdvanceWithoutHandler) {
86
  if (use_top || fp != NULL) {
87
    Reset();
88
  }
89
  JavaScriptFrame_.DisableHeapAccess();
90
}
91

    
92
#undef INITIALIZE_SINGLETON
93

    
94

    
95
void StackFrameIterator::AdvanceWithHandler() {
96
  ASSERT(!done());
97
  // Compute the state of the calling frame before restoring
98
  // callee-saved registers and unwinding handlers. This allows the
99
  // frame code that computes the caller state to access the top
100
  // handler and the value of any callee-saved register if needed.
101
  StackFrame::State state;
102
  StackFrame::Type type = frame_->GetCallerState(&state);
103

    
104
  // Unwind handlers corresponding to the current frame.
105
  StackHandlerIterator it(frame_, handler_);
106
  while (!it.done()) it.Advance();
107
  handler_ = it.handler();
108

    
109
  // Advance to the calling frame.
110
  frame_ = SingletonFor(type, &state);
111

    
112
  // When we're done iterating over the stack frames, the handler
113
  // chain must have been completely unwound.
114
  ASSERT(!done() || handler_ == NULL);
115
}
116

    
117

    
118
void StackFrameIterator::AdvanceWithoutHandler() {
119
  // A simpler version of Advance which doesn't care about handler.
120
  ASSERT(!done());
121
  StackFrame::State state;
122
  StackFrame::Type type = frame_->GetCallerState(&state);
123
  frame_ = SingletonFor(type, &state);
124
}
125

    
126

    
127
void StackFrameIterator::Reset() {
128
  StackFrame::State state;
129
  StackFrame::Type type;
130
  if (thread_ != NULL) {
131
    type = ExitFrame::GetStateForFramePointer(Top::c_entry_fp(thread_), &state);
132
    handler_ = StackHandler::FromAddress(Top::handler(thread_));
133
  } else {
134
    ASSERT(fp_ != NULL);
135
    state.fp = fp_;
136
    state.sp = sp_;
137
    state.pc_address =
138
        reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp_));
139
    type = StackFrame::ComputeType(&state);
140
    if (SingletonFor(type) == NULL) return;
141
  }
142
  frame_ = SingletonFor(type, &state);
143
}
144

    
145

    
146
StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type,
147
                                             StackFrame::State* state) {
148
  if (type == StackFrame::NONE) return NULL;
149
  StackFrame* result = SingletonFor(type);
150
  ASSERT(result != NULL);
151
  result->state_ = *state;
152
  return result;
153
}
154

    
155

    
156
StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type) {
157
#define FRAME_TYPE_CASE(type, field) \
158
  case StackFrame::type: result = &field##_; break;
159

    
160
  StackFrame* result = NULL;
161
  switch (type) {
162
    case StackFrame::NONE: return NULL;
163
    STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
164
    default: break;
165
  }
166
  return result;
167

    
168
#undef FRAME_TYPE_CASE
169
}
170

    
171

    
172
// -------------------------------------------------------------------------
173

    
174

    
175
StackTraceFrameIterator::StackTraceFrameIterator() {
176
  if (!done() && !frame()->function()->IsJSFunction()) Advance();
177
}
178

    
179

    
180
void StackTraceFrameIterator::Advance() {
181
  while (true) {
182
    JavaScriptFrameIterator::Advance();
183
    if (done()) return;
184
    if (frame()->function()->IsJSFunction()) return;
185
  }
186
}
187

    
188

    
189
// -------------------------------------------------------------------------
190

    
191

    
192
SafeStackFrameIterator::SafeStackFrameIterator(
193
    Address fp, Address sp, Address low_bound, Address high_bound) :
194
    low_bound_(low_bound), high_bound_(high_bound),
195
    is_valid_top_(
196
        IsWithinBounds(low_bound, high_bound,
197
                       Top::c_entry_fp(Top::GetCurrentThread())) &&
198
        Top::handler(Top::GetCurrentThread()) != NULL),
199
    is_valid_fp_(IsWithinBounds(low_bound, high_bound, fp)),
200
    is_working_iterator_(is_valid_top_ || is_valid_fp_),
201
    iteration_done_(!is_working_iterator_),
202
    iterator_(is_valid_top_, is_valid_fp_ ? fp : NULL, sp) {
203
}
204

    
205

    
206
void SafeStackFrameIterator::Advance() {
207
  ASSERT(is_working_iterator_);
208
  ASSERT(!done());
209
  StackFrame* last_frame = iterator_.frame();
210
  Address last_sp = last_frame->sp(), last_fp = last_frame->fp();
211
  // Before advancing to the next stack frame, perform pointer validity tests
212
  iteration_done_ = !IsValidFrame(last_frame) ||
213
      !CanIterateHandles(last_frame, iterator_.handler()) ||
214
      !IsValidCaller(last_frame);
215
  if (iteration_done_) return;
216

    
217
  iterator_.Advance();
218
  if (iterator_.done()) return;
219
  // Check that we have actually moved to the previous frame in the stack
220
  StackFrame* prev_frame = iterator_.frame();
221
  iteration_done_ = prev_frame->sp() < last_sp || prev_frame->fp() < last_fp;
222
}
223

    
224

    
225
bool SafeStackFrameIterator::CanIterateHandles(StackFrame* frame,
226
                                               StackHandler* handler) {
227
  // If StackIterator iterates over StackHandles, verify that
228
  // StackHandlerIterator can be instantiated (see StackHandlerIterator
229
  // constructor.)
230
  return !is_valid_top_ || (frame->sp() <= handler->address());
231
}
232

    
233

    
234
bool SafeStackFrameIterator::IsValidFrame(StackFrame* frame) const {
235
  return IsValidStackAddress(frame->sp()) && IsValidStackAddress(frame->fp());
236
}
237

    
238

    
239
bool SafeStackFrameIterator::IsValidCaller(StackFrame* frame) {
240
  StackFrame::State state;
241
  if (frame->is_entry() || frame->is_entry_construct()) {
242
    // See EntryFrame::GetCallerState. It computes the caller FP address
243
    // and calls ExitFrame::GetStateForFramePointer on it. We need to be
244
    // sure that caller FP address is valid.
245
    Address caller_fp = Memory::Address_at(
246
        frame->fp() + EntryFrameConstants::kCallerFPOffset);
247
    if (!IsValidStackAddress(caller_fp)) {
248
      return false;
249
    }
250
  } else if (frame->is_arguments_adaptor()) {
251
    // See ArgumentsAdaptorFrame::GetCallerStackPointer. It assumes that
252
    // the number of arguments is stored on stack as Smi. We need to check
253
    // that it really an Smi.
254
    Object* number_of_args = reinterpret_cast<ArgumentsAdaptorFrame*>(frame)->
255
        GetExpression(0);
256
    if (!number_of_args->IsSmi()) {
257
      return false;
258
    }
259
  }
260
  frame->ComputeCallerState(&state);
261
  return IsValidStackAddress(state.sp) && IsValidStackAddress(state.fp) &&
262
      iterator_.SingletonFor(frame->GetCallerState(&state)) != NULL;
263
}
264

    
265

    
266
void SafeStackFrameIterator::Reset() {
267
  if (is_working_iterator_) {
268
    iterator_.Reset();
269
    iteration_done_ = false;
270
  }
271
}
272

    
273

    
274
// -------------------------------------------------------------------------
275

    
276

    
277
#ifdef ENABLE_LOGGING_AND_PROFILING
278
SafeStackTraceFrameIterator::SafeStackTraceFrameIterator(
279
    Address fp, Address sp, Address low_bound, Address high_bound) :
280
    SafeJavaScriptFrameIterator(fp, sp, low_bound, high_bound) {
281
  if (!done() && !frame()->is_java_script()) Advance();
282
}
283

    
284

    
285
void SafeStackTraceFrameIterator::Advance() {
286
  while (true) {
287
    SafeJavaScriptFrameIterator::Advance();
288
    if (done()) return;
289
    if (frame()->is_java_script()) return;
290
  }
291
}
292
#endif
293

    
294

    
295
// -------------------------------------------------------------------------
296

    
297

    
298
void StackHandler::Cook(Code* code) {
299
  ASSERT(MarkCompactCollector::IsCompacting());
300
  ASSERT(code->contains(pc()));
301
  set_pc(AddressFrom<Address>(pc() - code->instruction_start()));
302
}
303

    
304

    
305
void StackHandler::Uncook(Code* code) {
306
  ASSERT(MarkCompactCollector::IsCompacting());
307
  set_pc(code->instruction_start() + OffsetFrom(pc()));
308
  ASSERT(code->contains(pc()));
309
}
310

    
311

    
312
// -------------------------------------------------------------------------
313

    
314

    
315
bool StackFrame::HasHandler() const {
316
  StackHandlerIterator it(this, top_handler());
317
  return !it.done();
318
}
319

    
320

    
321
void StackFrame::CookFramesForThread(ThreadLocalTop* thread) {
322
  // Only cooking frames when the collector is compacting and thus moving code
323
  // around.
324
  ASSERT(MarkCompactCollector::IsCompacting());
325
  ASSERT(!thread->stack_is_cooked());
326
  for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
327
    it.frame()->Cook();
328
  }
329
  thread->set_stack_is_cooked(true);
330
}
331

    
332

    
333
void StackFrame::UncookFramesForThread(ThreadLocalTop* thread) {
334
  // Only uncooking frames when the collector is compacting and thus moving code
335
  // around.
336
  ASSERT(MarkCompactCollector::IsCompacting());
337
  ASSERT(thread->stack_is_cooked());
338
  for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
339
    it.frame()->Uncook();
340
  }
341
  thread->set_stack_is_cooked(false);
342
}
343

    
344

    
345
void StackFrame::Cook() {
346
  Code* code = this->code();
347
  for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
348
    it.handler()->Cook(code);
349
  }
350
  ASSERT(code->contains(pc()));
351
  set_pc(AddressFrom<Address>(pc() - code->instruction_start()));
352
}
353

    
354

    
355
void StackFrame::Uncook() {
356
  Code* code = this->code();
357
  for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
358
    it.handler()->Uncook(code);
359
  }
360
  set_pc(code->instruction_start() + OffsetFrom(pc()));
361
  ASSERT(code->contains(pc()));
362
}
363

    
364

    
365
StackFrame::Type StackFrame::GetCallerState(State* state) const {
366
  ComputeCallerState(state);
367
  return ComputeType(state);
368
}
369

    
370

    
371
Code* EntryFrame::code() const {
372
  return Heap::js_entry_code();
373
}
374

    
375

    
376
void EntryFrame::ComputeCallerState(State* state) const {
377
  GetCallerState(state);
378
}
379

    
380

    
381
StackFrame::Type EntryFrame::GetCallerState(State* state) const {
382
  const int offset = EntryFrameConstants::kCallerFPOffset;
383
  Address fp = Memory::Address_at(this->fp() + offset);
384
  return ExitFrame::GetStateForFramePointer(fp, state);
385
}
386

    
387

    
388
Code* EntryConstructFrame::code() const {
389
  return Heap::js_construct_entry_code();
390
}
391

    
392

    
393
Code* ExitFrame::code() const {
394
  return Heap::c_entry_code();
395
}
396

    
397

    
398
void ExitFrame::ComputeCallerState(State* state) const {
399
  // Setup the caller state.
400
  state->sp = pp();
401
  state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset);
402
  state->pc_address
403
      = reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset);
404
}
405

    
406

    
407
Address ExitFrame::GetCallerStackPointer() const {
408
  return fp() + ExitFrameConstants::kPPDisplacement;
409
}
410

    
411

    
412
Code* ExitDebugFrame::code() const {
413
  return Heap::c_entry_debug_break_code();
414
}
415

    
416

    
417
Address StandardFrame::GetExpressionAddress(int n) const {
418
  const int offset = StandardFrameConstants::kExpressionsOffset;
419
  return fp() + offset - n * kPointerSize;
420
}
421

    
422

    
423
int StandardFrame::ComputeExpressionsCount() const {
424
  const int offset =
425
      StandardFrameConstants::kExpressionsOffset + kPointerSize;
426
  Address base = fp() + offset;
427
  Address limit = sp();
428
  ASSERT(base >= limit);  // stack grows downwards
429
  // Include register-allocated locals in number of expressions.
430
  return (base - limit) / kPointerSize;
431
}
432

    
433

    
434
void StandardFrame::ComputeCallerState(State* state) const {
435
  state->sp = caller_sp();
436
  state->fp = caller_fp();
437
  state->pc_address = reinterpret_cast<Address*>(ComputePCAddress(fp()));
438
}
439

    
440

    
441
bool StandardFrame::IsExpressionInsideHandler(int n) const {
442
  Address address = GetExpressionAddress(n);
443
  for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
444
    if (it.handler()->includes(address)) return true;
445
  }
446
  return false;
447
}
448

    
449

    
450
Object* JavaScriptFrame::GetParameter(int index) const {
451
  ASSERT(index >= 0 && index < ComputeParametersCount());
452
  const int offset = JavaScriptFrameConstants::kParam0Offset;
453
  return Memory::Object_at(pp() + offset - (index * kPointerSize));
454
}
455

    
456

    
457
int JavaScriptFrame::ComputeParametersCount() const {
458
  Address base  = pp() + JavaScriptFrameConstants::kReceiverOffset;
459
  Address limit = fp() + JavaScriptFrameConstants::kSavedRegistersOffset;
460
  return (base - limit) / kPointerSize;
461
}
462

    
463

    
464
bool JavaScriptFrame::IsConstructor() const {
465
  Address fp = caller_fp();
466
  if (has_adapted_arguments()) {
467
    // Skip the arguments adaptor frame and look at the real caller.
468
    fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
469
  }
470
  return IsConstructFrame(fp);
471
}
472

    
473

    
474
Code* JavaScriptFrame::code() const {
475
  JSFunction* function = JSFunction::cast(this->function());
476
  return function->shared()->code();
477
}
478

    
479

    
480
Code* ArgumentsAdaptorFrame::code() const {
481
  return Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline);
482
}
483

    
484

    
485
Code* InternalFrame::code() const {
486
  const int offset = InternalFrameConstants::kCodeOffset;
487
  Object* code = Memory::Object_at(fp() + offset);
488
  ASSERT(code != NULL);
489
  return Code::cast(code);
490
}
491

    
492

    
493
void StackFrame::PrintIndex(StringStream* accumulator,
494
                            PrintMode mode,
495
                            int index) {
496
  accumulator->Add((mode == OVERVIEW) ? "%5d: " : "[%d]: ", index);
497
}
498

    
499

    
500
void JavaScriptFrame::Print(StringStream* accumulator,
501
                            PrintMode mode,
502
                            int index) const {
503
  HandleScope scope;
504
  Object* receiver = this->receiver();
505
  Object* function = this->function();
506

    
507
  accumulator->PrintSecurityTokenIfChanged(function);
508
  PrintIndex(accumulator, mode, index);
509
  Code* code = NULL;
510
  if (IsConstructor()) accumulator->Add("new ");
511
  accumulator->PrintFunction(function, receiver, &code);
512
  accumulator->Add("(this=%o", receiver);
513

    
514
  // Get scope information for nicer output, if possible. If code is
515
  // NULL, or doesn't contain scope info, info will return 0 for the
516
  // number of parameters, stack slots, or context slots.
517
  ScopeInfo<PreallocatedStorage> info(code);
518

    
519
  // Print the parameters.
520
  int parameters_count = ComputeParametersCount();
521
  for (int i = 0; i < parameters_count; i++) {
522
    accumulator->Add(",");
523
    // If we have a name for the parameter we print it. Nameless
524
    // parameters are either because we have more actual parameters
525
    // than formal parameters or because we have no scope information.
526
    if (i < info.number_of_parameters()) {
527
      accumulator->PrintName(*info.parameter_name(i));
528
      accumulator->Add("=");
529
    }
530
    accumulator->Add("%o", GetParameter(i));
531
  }
532

    
533
  accumulator->Add(")");
534
  if (mode == OVERVIEW) {
535
    accumulator->Add("\n");
536
    return;
537
  }
538
  accumulator->Add(" {\n");
539

    
540
  // Compute the number of locals and expression stack elements.
541
  int stack_locals_count = info.number_of_stack_slots();
542
  int heap_locals_count = info.number_of_context_slots();
543
  int expressions_count = ComputeExpressionsCount();
544

    
545
  // Print stack-allocated local variables.
546
  if (stack_locals_count > 0) {
547
    accumulator->Add("  // stack-allocated locals\n");
548
  }
549
  for (int i = 0; i < stack_locals_count; i++) {
550
    accumulator->Add("  var ");
551
    accumulator->PrintName(*info.stack_slot_name(i));
552
    accumulator->Add(" = ");
553
    if (i < expressions_count) {
554
      accumulator->Add("%o", GetExpression(i));
555
    } else {
556
      accumulator->Add("// no expression found - inconsistent frame?");
557
    }
558
    accumulator->Add("\n");
559
  }
560

    
561
  // Try to get hold of the context of this frame.
562
  Context* context = NULL;
563
  if (this->context() != NULL && this->context()->IsContext()) {
564
    context = Context::cast(this->context());
565
  }
566

    
567
  // Print heap-allocated local variables.
568
  if (heap_locals_count > Context::MIN_CONTEXT_SLOTS) {
569
    accumulator->Add("  // heap-allocated locals\n");
570
  }
571
  for (int i = Context::MIN_CONTEXT_SLOTS; i < heap_locals_count; i++) {
572
    accumulator->Add("  var ");
573
    accumulator->PrintName(*info.context_slot_name(i));
574
    accumulator->Add(" = ");
575
    if (context != NULL) {
576
      if (i < context->length()) {
577
        accumulator->Add("%o", context->get(i));
578
      } else {
579
        accumulator->Add(
580
            "// warning: missing context slot - inconsistent frame?");
581
      }
582
    } else {
583
      accumulator->Add("// warning: no context found - inconsistent frame?");
584
    }
585
    accumulator->Add("\n");
586
  }
587

    
588
  // Print the expression stack.
589
  int expressions_start = stack_locals_count;
590
  if (expressions_start < expressions_count) {
591
    accumulator->Add("  // expression stack (top to bottom)\n");
592
  }
593
  for (int i = expressions_count - 1; i >= expressions_start; i--) {
594
    if (IsExpressionInsideHandler(i)) continue;
595
    accumulator->Add("  [%02d] : %o\n", i, GetExpression(i));
596
  }
597

    
598
  // Print details about the function.
599
  if (FLAG_max_stack_trace_source_length != 0 && code != NULL) {
600
    SharedFunctionInfo* shared = JSFunction::cast(function)->shared();
601
    accumulator->Add("--------- s o u r c e   c o d e ---------\n");
602
    shared->SourceCodePrint(accumulator, FLAG_max_stack_trace_source_length);
603
    accumulator->Add("\n-----------------------------------------\n");
604
  }
605

    
606
  accumulator->Add("}\n\n");
607
}
608

    
609

    
610
void ArgumentsAdaptorFrame::Print(StringStream* accumulator,
611
                                  PrintMode mode,
612
                                  int index) const {
613
  int actual = ComputeParametersCount();
614
  int expected = -1;
615
  Object* function = this->function();
616
  if (function->IsJSFunction()) {
617
    expected = JSFunction::cast(function)->shared()->formal_parameter_count();
618
  }
619

    
620
  PrintIndex(accumulator, mode, index);
621
  accumulator->Add("arguments adaptor frame: %d->%d", actual, expected);
622
  if (mode == OVERVIEW) {
623
    accumulator->Add("\n");
624
    return;
625
  }
626
  accumulator->Add(" {\n");
627

    
628
  // Print actual arguments.
629
  if (actual > 0) accumulator->Add("  // actual arguments\n");
630
  for (int i = 0; i < actual; i++) {
631
    accumulator->Add("  [%02d] : %o", i, GetParameter(i));
632
    if (expected != -1 && i >= expected) {
633
      accumulator->Add("  // not passed to callee");
634
    }
635
    accumulator->Add("\n");
636
  }
637

    
638
  accumulator->Add("}\n\n");
639
}
640

    
641

    
642
void EntryFrame::Iterate(ObjectVisitor* v) const {
643
  StackHandlerIterator it(this, top_handler());
644
  ASSERT(!it.done());
645
  StackHandler* handler = it.handler();
646
  ASSERT(handler->is_entry());
647
  handler->Iterate(v);
648
  // Make sure that there's the entry frame does not contain more than
649
  // one stack handler.
650
  if (kDebug) {
651
    it.Advance();
652
    ASSERT(it.done());
653
  }
654
}
655

    
656

    
657
void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
658
  const int offset = StandardFrameConstants::kContextOffset;
659
  Object** base = &Memory::Object_at(sp());
660
  Object** limit = &Memory::Object_at(fp() + offset) + 1;
661
  for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
662
    StackHandler* handler = it.handler();
663
    // Traverse pointers down to - but not including - the next
664
    // handler in the handler chain. Update the base to skip the
665
    // handler and allow the handler to traverse its own pointers.
666
    const Address address = handler->address();
667
    v->VisitPointers(base, reinterpret_cast<Object**>(address));
668
    base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize);
669
    // Traverse the pointers in the handler itself.
670
    handler->Iterate(v);
671
  }
672
  v->VisitPointers(base, limit);
673
}
674

    
675

    
676
void JavaScriptFrame::Iterate(ObjectVisitor* v) const {
677
  IterateExpressions(v);
678

    
679
  // Traverse callee-saved registers, receiver, and parameters.
680
  const int kBaseOffset = JavaScriptFrameConstants::kSavedRegistersOffset;
681
  const int kLimitOffset = JavaScriptFrameConstants::kReceiverOffset;
682
  Object** base = &Memory::Object_at(fp() + kBaseOffset);
683
  Object** limit = &Memory::Object_at(pp() + kLimitOffset) + 1;
684
  v->VisitPointers(base, limit);
685
}
686

    
687

    
688
void InternalFrame::Iterate(ObjectVisitor* v) const {
689
  // Internal frames only have object pointers on the expression stack
690
  // as they never have any arguments.
691
  IterateExpressions(v);
692
}
693

    
694

    
695
// -------------------------------------------------------------------------
696

    
697

    
698
JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) {
699
  ASSERT(n >= 0);
700
  for (int i = 0; i <= n; i++) {
701
    while (!iterator_.frame()->is_java_script()) iterator_.Advance();
702
    if (i == n) return JavaScriptFrame::cast(iterator_.frame());
703
    iterator_.Advance();
704
  }
705
  UNREACHABLE();
706
  return NULL;
707
}
708

    
709

    
710
// -------------------------------------------------------------------------
711

    
712

    
713
int NumRegs(RegList reglist) {
714
  int n = 0;
715
  while (reglist != 0) {
716
    n++;
717
    reglist &= reglist - 1;  // clear one bit
718
  }
719
  return n;
720
}
721

    
722

    
723
int JSCallerSavedCode(int n) {
724
  static int reg_code[kNumJSCallerSaved];
725
  static bool initialized = false;
726
  if (!initialized) {
727
    initialized = true;
728
    int i = 0;
729
    for (int r = 0; r < kNumRegs; r++)
730
      if ((kJSCallerSaved & (1 << r)) != 0)
731
        reg_code[i++] = r;
732

    
733
    ASSERT(i == kNumJSCallerSaved);
734
  }
735
  ASSERT(0 <= n && n < kNumJSCallerSaved);
736
  return reg_code[n];
737
}
738

    
739

    
740
} }  // namespace v8::internal