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