blob: 568295bd1fbb19167efa2350eee26374c33d5274 [file] [log] [blame]
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001// Copyright 2006-2008 Google Inc. 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 "scopeinfo.h"
32#include "string-stream.h"
33#include "top.h"
34#include "zone-inl.h"
35
36namespace v8 { namespace internal {
37
38
39DEFINE_int(max_stack_trace_source_length, 300,
40 "maximum length of function source code printed in a stack trace.");
41
42
43// -------------------------------------------------------------------------
44
45
46// Iterator that supports traversing the stack handlers of a
47// particular frame. Needs to know the top of the handler chain.
48class StackHandlerIterator BASE_EMBEDDED {
49 public:
50 StackHandlerIterator(const StackFrame* frame, StackHandler* handler)
51 : limit_(frame->fp()), handler_(handler) {
52 // Make sure the handler has already been unwound to this frame.
53 ASSERT(frame->sp() <= handler->address());
54 }
55
56 StackHandler* handler() const { return handler_; }
57
58 bool done() { return handler_->address() > limit_; }
59 void Advance() {
60 ASSERT(!done());
61 handler_ = handler_->next();
62 }
63
64 private:
65 const Address limit_;
66 StackHandler* handler_;
67};
68
69
70// -------------------------------------------------------------------------
71
72
73#define INITIALIZE_SINGLETON(type, field) field##_(this),
74StackFrameIterator::StackFrameIterator()
75 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
76 frame_(NULL), handler_(NULL), thread(Top::GetCurrentThread()) {
77 Reset();
78}
79StackFrameIterator::StackFrameIterator(ThreadLocalTop* t)
80 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
81 frame_(NULL), handler_(NULL), thread(t) {
82 Reset();
83}
84#undef INITIALIZE_SINGLETON
85
86
87void StackFrameIterator::Advance() {
88 ASSERT(!done());
89 // Compute the state of the calling frame before restoring
90 // callee-saved registers and unwinding handlers. This allows the
91 // frame code that computes the caller state to access the top
92 // handler and the value of any callee-saved register if needed.
93 StackFrame::State state;
94 StackFrame::Type type = frame_->GetCallerState(&state);
95
96 // Restore any callee-saved registers to the register buffer. Avoid
97 // the virtual call if the platform doesn't have any callee-saved
98 // registers.
99 if (kNumJSCalleeSaved > 0) {
100 frame_->RestoreCalleeSavedRegisters(register_buffer());
101 }
102
103 // Unwind handlers corresponding to the current frame.
104 StackHandlerIterator it(frame_, handler_);
105 while (!it.done()) it.Advance();
106 handler_ = it.handler();
107
108 // Advance to the calling frame.
109 frame_ = SingletonFor(type, &state);
110
111 // When we're done iterating over the stack frames, the handler
112 // chain must have been completely unwound.
113 ASSERT(!done() || handler_ == NULL);
114}
115
116
117void StackFrameIterator::Reset() {
118 Address fp = Top::c_entry_fp(thread);
119 StackFrame::State state;
120 StackFrame::Type type = ExitFrame::GetStateForFramePointer(fp, &state);
121 frame_ = SingletonFor(type, &state);
122 handler_ = StackHandler::FromAddress(Top::handler(thread));
123 // Zap the register buffer in debug mode.
124 if (kDebug) {
125 Object** buffer = register_buffer();
126 for (int i = 0; i < kNumJSCalleeSaved; i++) {
127 buffer[i] = reinterpret_cast<Object*>(kZapValue);
128 }
129 }
130}
131
132
133Object** StackFrameIterator::RestoreCalleeSavedForTopHandler(Object** buffer) {
134 ASSERT(kNumJSCalleeSaved > 0);
135 // Traverse the frames until we find the frame containing the top
136 // handler. Such a frame is guaranteed to always exists by the
137 // callers of this function.
138 for (StackFrameIterator it; true; it.Advance()) {
139 StackHandlerIterator handlers(it.frame(), it.handler());
140 if (!handlers.done()) {
141 memcpy(buffer, it.register_buffer(), kNumJSCalleeSaved * kPointerSize);
142 return buffer;
143 }
144 }
145}
146
147
148StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type,
149 StackFrame::State* state) {
150#define FRAME_TYPE_CASE(type, field) \
151 case StackFrame::type: result = &field##_; break;
152
153 StackFrame* result = NULL;
154 switch (type) {
155 case StackFrame::NONE: return NULL;
156 STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
157 default: break;
158 }
159 ASSERT(result != NULL);
160 result->state_ = *state;
161 return result;
162
163#undef FRAME_TYPE_CASE
164}
165
166
167// -------------------------------------------------------------------------
168
169
170JavaScriptFrameIterator::JavaScriptFrameIterator(StackFrame::Id id) {
171 while (true) {
172 Advance();
173 if (frame()->id() == id) return;
174 }
175}
176
177
178void JavaScriptFrameIterator::Advance() {
179 do {
180 iterator_.Advance();
181 } while (!iterator_.done() && !iterator_.frame()->is_java_script());
182}
183
184
185void JavaScriptFrameIterator::AdvanceToArgumentsFrame() {
186 if (!frame()->has_adapted_arguments()) return;
187 iterator_.Advance();
188 ASSERT(iterator_.frame()->is_arguments_adaptor());
189}
190
191
192void JavaScriptFrameIterator::Reset() {
193 iterator_.Reset();
194 Advance();
195}
196
197
198// -------------------------------------------------------------------------
199
200
201void StackHandler::Cook(Code* code) {
202 ASSERT(code->contains(pc()));
203 set_pc(AddressFrom<Address>(pc() - code->instruction_start()));
204}
205
206
207void StackHandler::Uncook(Code* code) {
208 set_pc(code->instruction_start() + OffsetFrom(pc()));
209 ASSERT(code->contains(pc()));
210}
211
212
213// -------------------------------------------------------------------------
214
215
216bool StackFrame::HasHandler() const {
217 StackHandlerIterator it(this, top_handler());
218 return !it.done();
219}
220
221
222void StackFrame::CookFramesForThread(ThreadLocalTop* thread) {
223 ASSERT(!thread->stack_is_cooked());
224 for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
225 it.frame()->Cook();
226 }
227 thread->set_stack_is_cooked(true);
228}
229
230
231void StackFrame::UncookFramesForThread(ThreadLocalTop* thread) {
232 ASSERT(thread->stack_is_cooked());
233 for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
234 it.frame()->Uncook();
235 }
236 thread->set_stack_is_cooked(false);
237}
238
239
240void StackFrame::Cook() {
241 Code* code = FindCode();
242 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
243 it.handler()->Cook(code);
244 }
245 ASSERT(code->contains(pc()));
246 set_pc(AddressFrom<Address>(pc() - code->instruction_start()));
247}
248
249
250void StackFrame::Uncook() {
251 Code* code = FindCode();
252 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
253 it.handler()->Uncook(code);
254 }
255 set_pc(code->instruction_start() + OffsetFrom(pc()));
256 ASSERT(code->contains(pc()));
257}
258
259
260Code* EntryFrame::FindCode() const {
261 return Heap::js_entry_code();
262}
263
264
265StackFrame::Type EntryFrame::GetCallerState(State* state) const {
266 const int offset = EntryFrameConstants::kCallerFPOffset;
267 Address fp = Memory::Address_at(this->fp() + offset);
268 return ExitFrame::GetStateForFramePointer(fp, state);
269}
270
271
272Code* EntryConstructFrame::FindCode() const {
273 return Heap::js_construct_entry_code();
274}
275
276
277Code* ExitFrame::FindCode() const {
278 return Heap::c_entry_code();
279}
280
281
282StackFrame::Type ExitFrame::GetCallerState(State* state) const {
283 // Setup the caller state.
284 state->sp = pp();
285 state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset);
286#ifdef USE_OLD_CALLING_CONVENTIONS
287 state->pp = Memory::Address_at(fp() + ExitFrameConstants::kCallerPPOffset);
288#endif
289 state->pc_address
290 = reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset);
291 return ComputeType(state);
292}
293
294
295Address ExitFrame::GetCallerStackPointer() const {
296 return fp() + ExitFrameConstants::kPPDisplacement;
297}
298
299
300Code* ExitDebugFrame::FindCode() const {
301 return Heap::c_entry_debug_break_code();
302}
303
304
305RegList ExitFrame::FindCalleeSavedRegisters() const {
306 // Exit frames save all - if any - callee-saved registers.
307 return kJSCalleeSaved;
308}
309
310
311Address StandardFrame::GetExpressionAddress(int n) const {
312 ASSERT(0 <= n && n < ComputeExpressionsCount());
313 if (kNumJSCalleeSaved > 0 && n < kNumJSCalleeSaved) {
314 return reinterpret_cast<Address>(top_register_buffer() + n);
315 } else {
316 const int offset = StandardFrameConstants::kExpressionsOffset;
317 return fp() + offset - (n - kNumJSCalleeSaved) * kPointerSize;
318 }
319}
320
321
322int StandardFrame::ComputeExpressionsCount() const {
323 const int offset =
324 StandardFrameConstants::kExpressionsOffset + kPointerSize;
325 Address base = fp() + offset;
326 Address limit = sp();
327 ASSERT(base >= limit); // stack grows downwards
328 // Include register-allocated locals in number of expressions.
329 return (base - limit) / kPointerSize + kNumJSCalleeSaved;
330}
331
332
333StackFrame::Type StandardFrame::GetCallerState(State* state) const {
334 state->sp = caller_sp();
335 state->fp = caller_fp();
336#ifdef USE_OLD_CALLING_CONVENTIONS
337 state->pp = caller_pp();
338#endif
339 state->pc_address = reinterpret_cast<Address*>(ComputePCAddress(fp()));
340 return ComputeType(state);
341}
342
343
344bool StandardFrame::IsExpressionInsideHandler(int n) const {
345 Address address = GetExpressionAddress(n);
346 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
347 if (it.handler()->includes(address)) return true;
348 }
349 return false;
350}
351
352
353Object* JavaScriptFrame::GetParameter(int index) const {
354 ASSERT(index >= 0 && index < ComputeParametersCount());
355 const int offset = JavaScriptFrameConstants::kParam0Offset;
356 return Memory::Object_at(pp() + offset - (index * kPointerSize));
357}
358
359
360int JavaScriptFrame::ComputeParametersCount() const {
361 Address base = pp() + JavaScriptFrameConstants::kReceiverOffset;
362 Address limit = fp() + JavaScriptFrameConstants::kSavedRegistersOffset;
363 int result = (base - limit) / kPointerSize;
364 if (kNumJSCalleeSaved > 0) {
365 return result - NumRegs(FindCalleeSavedRegisters());
366 } else {
367 return result;
368 }
369}
370
371
372bool JavaScriptFrame::IsConstructor() const {
373 Address pc = has_adapted_arguments()
374 ? Memory::Address_at(ComputePCAddress(caller_fp()))
375 : caller_pc();
376 return IsConstructTrampolineFrame(pc);
377}
378
379
380Code* ArgumentsAdaptorFrame::FindCode() const {
381 return Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline);
382}
383
384
385Code* InternalFrame::FindCode() const {
386 const int offset = InternalFrameConstants::kCodeOffset;
387 Object* code = Memory::Object_at(fp() + offset);
388 if (code == NULL) {
389 // The code object isn't set; find it and set it.
390 code = Heap::FindCodeObject(pc());
391 ASSERT(!code->IsFailure());
392 Memory::Object_at(fp() + offset) = code;
393 }
394 ASSERT(code != NULL);
395 return Code::cast(code);
396}
397
398
399void StackFrame::PrintIndex(StringStream* accumulator,
400 PrintMode mode,
401 int index) {
402 accumulator->Add((mode == OVERVIEW) ? "%5d: " : "[%d]: ", index);
403}
404
405
406void JavaScriptFrame::Print(StringStream* accumulator,
407 PrintMode mode,
408 int index) const {
409 HandleScope scope;
410 Object* receiver = this->receiver();
411 Object* function = this->function();
412
413 accumulator->PrintSecurityTokenIfChanged(function);
414 PrintIndex(accumulator, mode, index);
415 Code* code = NULL;
416 if (IsConstructor()) accumulator->Add("new ");
417 accumulator->PrintFunction(function, receiver, &code);
418 accumulator->Add("(this=%o", receiver);
419
420 // Get scope information for nicer output, if possible. If code is
421 // NULL, or doesn't contain scope info, info will return 0 for the
422 // number of parameters, stack slots, or context slots.
423 ScopeInfo<PreallocatedStorage> info(code);
424
425 // Print the parameters.
426 int parameters_count = ComputeParametersCount();
427 for (int i = 0; i < parameters_count; i++) {
428 accumulator->Add(",");
429 // If we have a name for the parameter we print it. Nameless
430 // parameters are either because we have more actual parameters
431 // than formal parameters or because we have no scope information.
432 if (i < info.number_of_parameters()) {
433 accumulator->PrintName(*info.parameter_name(i));
434 accumulator->Add("=");
435 }
436 accumulator->Add("%o", GetParameter(i));
437 }
438
439 accumulator->Add(")");
440 if (mode == OVERVIEW) {
441 accumulator->Add("\n");
442 return;
443 }
444 accumulator->Add(" {\n");
445
446 // Compute the number of locals and expression stack elements.
447 int stack_locals_count = info.number_of_stack_slots();
448 int heap_locals_count = info.number_of_context_slots();
449 int expressions_count = ComputeExpressionsCount();
450
451 // Print stack-allocated local variables.
452 if (stack_locals_count > 0) {
453 accumulator->Add(" // stack-allocated locals\n");
454 }
455 for (int i = 0; i < stack_locals_count; i++) {
456 accumulator->Add(" var ");
457 accumulator->PrintName(*info.stack_slot_name(i));
458 accumulator->Add(" = ");
459 if (i < expressions_count) {
460 accumulator->Add("%o", GetExpression(i));
461 } else {
462 accumulator->Add("// no expression found - inconsistent frame?");
463 }
464 accumulator->Add("\n");
465 }
466
467 // Try to get hold of the context of this frame.
468 Context* context = NULL;
469 if (this->context() != NULL && this->context()->IsContext()) {
470 context = Context::cast(this->context());
471 }
472
473 // Print heap-allocated local variables.
474 if (heap_locals_count > Context::MIN_CONTEXT_SLOTS) {
475 accumulator->Add(" // heap-allocated locals\n");
476 }
477 for (int i = Context::MIN_CONTEXT_SLOTS; i < heap_locals_count; i++) {
478 accumulator->Add(" var ");
479 accumulator->PrintName(*info.context_slot_name(i));
480 accumulator->Add(" = ");
481 if (context != NULL) {
482 if (i < context->length()) {
483 accumulator->Add("%o", context->get(i));
484 } else {
485 accumulator->Add(
486 "// warning: missing context slot - inconsistent frame?");
487 }
488 } else {
489 accumulator->Add("// warning: no context found - inconsistent frame?");
490 }
491 accumulator->Add("\n");
492 }
493
494 // Print the expression stack.
495 int expressions_start = Max(stack_locals_count, kNumJSCalleeSaved);
496 if (expressions_start < expressions_count) {
497 accumulator->Add(" // expression stack (top to bottom)\n");
498 }
499 for (int i = expressions_count - 1; i >= expressions_start; i--) {
500 if (IsExpressionInsideHandler(i)) continue;
501 accumulator->Add(" [%02d] : %o\n", i, GetExpression(i));
502 }
503
504 // Print details about the function.
505 if (FLAG_max_stack_trace_source_length != 0 && code != NULL) {
506 SharedFunctionInfo* shared = JSFunction::cast(function)->shared();
507 accumulator->Add("--------- s o u r c e c o d e ---------\n");
508 shared->SourceCodePrint(accumulator, FLAG_max_stack_trace_source_length);
509 accumulator->Add("\n-----------------------------------------\n");
510 }
511
512 accumulator->Add("}\n\n");
513}
514
515
516void ArgumentsAdaptorFrame::Print(StringStream* accumulator,
517 PrintMode mode,
518 int index) const {
519 int actual = ComputeParametersCount();
520 int expected = -1;
521 Object* function = this->function();
522 if (function->IsJSFunction()) {
523 expected = JSFunction::cast(function)->shared()->formal_parameter_count();
524 }
525
526 PrintIndex(accumulator, mode, index);
527 accumulator->Add("arguments adaptor frame: %d->%d", actual, expected);
528 if (mode == OVERVIEW) {
529 accumulator->Add("\n");
530 return;
531 }
532 accumulator->Add(" {\n");
533
534 // Print actual arguments.
535 if (actual > 0) accumulator->Add(" // actual arguments\n");
536 for (int i = 0; i < actual; i++) {
537 accumulator->Add(" [%02d] : %o", i, GetParameter(i));
538 if (expected != -1 && i >= expected) {
539 accumulator->Add(" // not passed to callee");
540 }
541 accumulator->Add("\n");
542 }
543
544 accumulator->Add("}\n\n");
545}
546
547
548void EntryFrame::Iterate(ObjectVisitor* v) const {
549 StackHandlerIterator it(this, top_handler());
550 ASSERT(!it.done());
551 StackHandler* handler = it.handler();
552 ASSERT(handler->is_entry());
553 handler->Iterate(v);
554 // Make sure that there's the entry frame does not contain more than
555 // one stack handler.
556 if (kDebug) {
557 it.Advance();
558 ASSERT(it.done());
559 }
560}
561
562
563void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
564 const int offset = StandardFrameConstants::kContextOffset;
565 Object** base = &Memory::Object_at(sp());
566 Object** limit = &Memory::Object_at(fp() + offset) + 1;
567 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
568 StackHandler* handler = it.handler();
569 // Traverse pointers down to - but not including - the next
570 // handler in the handler chain. Update the base to skip the
571 // handler and allow the handler to traverse its own pointers.
572 const Address address = handler->address();
573 v->VisitPointers(base, reinterpret_cast<Object**>(address));
574 base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize);
575 // Traverse the pointers in the handler itself.
576 handler->Iterate(v);
577 }
578 v->VisitPointers(base, limit);
579}
580
581
582void JavaScriptFrame::Iterate(ObjectVisitor* v) const {
583 IterateExpressions(v);
584
585 // Traverse callee-saved registers, receiver, and parameters.
586 const int kBaseOffset = JavaScriptFrameConstants::kSavedRegistersOffset;
587 const int kLimitOffset = JavaScriptFrameConstants::kReceiverOffset;
588 Object** base = &Memory::Object_at(fp() + kBaseOffset);
589 Object** limit = &Memory::Object_at(pp() + kLimitOffset) + 1;
590 v->VisitPointers(base, limit);
591}
592
593
594void InternalFrame::Iterate(ObjectVisitor* v) const {
595 // Internal frames only have object pointers on the expression stack
596 // as they never have any arguments.
597 IterateExpressions(v);
598}
599
600
601// -------------------------------------------------------------------------
602
603
604JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) {
605 ASSERT(n >= 0);
606 for (int i = 0; i <= n; i++) {
607 while (!iterator_.frame()->is_java_script()) iterator_.Advance();
608 if (i == n) return JavaScriptFrame::cast(iterator_.frame());
609 iterator_.Advance();
610 }
611 UNREACHABLE();
612 return NULL;
613}
614
615
616// -------------------------------------------------------------------------
617
618
619int NumRegs(RegList reglist) {
620 int n = 0;
621 while (reglist != 0) {
622 n++;
623 reglist &= reglist - 1; // clear one bit
624 }
625 return n;
626}
627
628
629int JSCallerSavedCode(int n) {
630 static int reg_code[kNumJSCallerSaved];
631 static bool initialized = false;
632 if (!initialized) {
633 initialized = true;
634 int i = 0;
635 for (int r = 0; r < kNumRegs; r++)
636 if ((kJSCallerSaved & (1 << r)) != 0)
637 reg_code[i++] = r;
638
639 ASSERT(i == kNumJSCallerSaved);
640 }
641 ASSERT(0 <= n && n < kNumJSCallerSaved);
642 return reg_code[n];
643}
644
645
646int JSCalleeSavedCode(int n) {
647 static int reg_code[kNumJSCalleeSaved + 1]; // avoid zero-size array error
648 static bool initialized = false;
649 if (!initialized) {
650 initialized = true;
651 int i = 0;
652 for (int r = 0; r < kNumRegs; r++)
653 if ((kJSCalleeSaved & (1 << r)) != 0)
654 reg_code[i++] = r;
655
656 ASSERT(i == kNumJSCalleeSaved);
657 }
658 ASSERT(0 <= n && n < kNumJSCalleeSaved);
659 return reg_code[n];
660}
661
662
663RegList JSCalleeSavedList(int n) {
664 // avoid zero-size array error
665 static RegList reg_list[kNumJSCalleeSaved + 1];
666 static bool initialized = false;
667 if (!initialized) {
668 initialized = true;
669 reg_list[0] = 0;
670 for (int i = 0; i < kNumJSCalleeSaved; i++)
671 reg_list[i+1] = reg_list[i] + (1 << JSCalleeSavedCode(i));
672 }
673 ASSERT(0 <= n && n <= kNumJSCalleeSaved);
674 return reg_list[n];
675}
676
677
678} } // namespace v8::internal