blob: ef976a0a6eb3846e3b38d3d196a1982ed4533cb1 [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)
kasper.lund7276f142008-07-30 08:49:36 +000076 frame_(NULL), handler_(NULL), thread_(Top::GetCurrentThread()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000077 Reset();
78}
79StackFrameIterator::StackFrameIterator(ThreadLocalTop* t)
80 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
kasper.lund7276f142008-07-30 08:49:36 +000081 frame_(NULL), handler_(NULL), thread_(t) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000082 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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096 // Unwind handlers corresponding to the current frame.
97 StackHandlerIterator it(frame_, handler_);
98 while (!it.done()) it.Advance();
99 handler_ = it.handler();
100
101 // Advance to the calling frame.
102 frame_ = SingletonFor(type, &state);
103
104 // When we're done iterating over the stack frames, the handler
105 // chain must have been completely unwound.
106 ASSERT(!done() || handler_ == NULL);
107}
108
109
110void StackFrameIterator::Reset() {
kasper.lund7276f142008-07-30 08:49:36 +0000111 Address fp = Top::c_entry_fp(thread_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000112 StackFrame::State state;
113 StackFrame::Type type = ExitFrame::GetStateForFramePointer(fp, &state);
114 frame_ = SingletonFor(type, &state);
kasper.lund7276f142008-07-30 08:49:36 +0000115 handler_ = StackHandler::FromAddress(Top::handler(thread_));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000116}
117
118
119StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type,
120 StackFrame::State* state) {
121#define FRAME_TYPE_CASE(type, field) \
122 case StackFrame::type: result = &field##_; break;
123
124 StackFrame* result = NULL;
125 switch (type) {
126 case StackFrame::NONE: return NULL;
127 STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
128 default: break;
129 }
130 ASSERT(result != NULL);
131 result->state_ = *state;
132 return result;
133
134#undef FRAME_TYPE_CASE
135}
136
137
138// -------------------------------------------------------------------------
139
140
141JavaScriptFrameIterator::JavaScriptFrameIterator(StackFrame::Id id) {
142 while (true) {
143 Advance();
144 if (frame()->id() == id) return;
145 }
146}
147
148
149void JavaScriptFrameIterator::Advance() {
150 do {
151 iterator_.Advance();
152 } while (!iterator_.done() && !iterator_.frame()->is_java_script());
153}
154
155
156void JavaScriptFrameIterator::AdvanceToArgumentsFrame() {
157 if (!frame()->has_adapted_arguments()) return;
158 iterator_.Advance();
159 ASSERT(iterator_.frame()->is_arguments_adaptor());
160}
161
162
163void JavaScriptFrameIterator::Reset() {
164 iterator_.Reset();
165 Advance();
166}
167
168
169// -------------------------------------------------------------------------
170
171
172void StackHandler::Cook(Code* code) {
173 ASSERT(code->contains(pc()));
174 set_pc(AddressFrom<Address>(pc() - code->instruction_start()));
175}
176
177
178void StackHandler::Uncook(Code* code) {
179 set_pc(code->instruction_start() + OffsetFrom(pc()));
180 ASSERT(code->contains(pc()));
181}
182
183
184// -------------------------------------------------------------------------
185
186
187bool StackFrame::HasHandler() const {
188 StackHandlerIterator it(this, top_handler());
189 return !it.done();
190}
191
192
193void StackFrame::CookFramesForThread(ThreadLocalTop* thread) {
194 ASSERT(!thread->stack_is_cooked());
195 for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
196 it.frame()->Cook();
197 }
198 thread->set_stack_is_cooked(true);
199}
200
201
202void StackFrame::UncookFramesForThread(ThreadLocalTop* thread) {
203 ASSERT(thread->stack_is_cooked());
204 for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
205 it.frame()->Uncook();
206 }
207 thread->set_stack_is_cooked(false);
208}
209
210
211void StackFrame::Cook() {
212 Code* code = FindCode();
213 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
214 it.handler()->Cook(code);
215 }
216 ASSERT(code->contains(pc()));
217 set_pc(AddressFrom<Address>(pc() - code->instruction_start()));
218}
219
220
221void StackFrame::Uncook() {
222 Code* code = FindCode();
223 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
224 it.handler()->Uncook(code);
225 }
226 set_pc(code->instruction_start() + OffsetFrom(pc()));
227 ASSERT(code->contains(pc()));
228}
229
230
231Code* EntryFrame::FindCode() const {
232 return Heap::js_entry_code();
233}
234
235
236StackFrame::Type EntryFrame::GetCallerState(State* state) const {
237 const int offset = EntryFrameConstants::kCallerFPOffset;
238 Address fp = Memory::Address_at(this->fp() + offset);
239 return ExitFrame::GetStateForFramePointer(fp, state);
240}
241
242
243Code* EntryConstructFrame::FindCode() const {
244 return Heap::js_construct_entry_code();
245}
246
247
248Code* ExitFrame::FindCode() const {
249 return Heap::c_entry_code();
250}
251
252
253StackFrame::Type ExitFrame::GetCallerState(State* state) const {
254 // Setup the caller state.
255 state->sp = pp();
256 state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset);
257#ifdef USE_OLD_CALLING_CONVENTIONS
258 state->pp = Memory::Address_at(fp() + ExitFrameConstants::kCallerPPOffset);
259#endif
260 state->pc_address
261 = reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset);
262 return ComputeType(state);
263}
264
265
266Address ExitFrame::GetCallerStackPointer() const {
267 return fp() + ExitFrameConstants::kPPDisplacement;
268}
269
270
271Code* ExitDebugFrame::FindCode() const {
272 return Heap::c_entry_debug_break_code();
273}
274
275
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000276Address StandardFrame::GetExpressionAddress(int n) const {
kasper.lund7276f142008-07-30 08:49:36 +0000277 const int offset = StandardFrameConstants::kExpressionsOffset;
278 return fp() + offset - n * kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000279}
280
281
282int StandardFrame::ComputeExpressionsCount() const {
283 const int offset =
284 StandardFrameConstants::kExpressionsOffset + kPointerSize;
285 Address base = fp() + offset;
286 Address limit = sp();
287 ASSERT(base >= limit); // stack grows downwards
288 // Include register-allocated locals in number of expressions.
kasper.lund7276f142008-07-30 08:49:36 +0000289 return (base - limit) / kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000290}
291
292
293StackFrame::Type StandardFrame::GetCallerState(State* state) const {
294 state->sp = caller_sp();
295 state->fp = caller_fp();
296#ifdef USE_OLD_CALLING_CONVENTIONS
297 state->pp = caller_pp();
298#endif
299 state->pc_address = reinterpret_cast<Address*>(ComputePCAddress(fp()));
300 return ComputeType(state);
301}
302
303
304bool StandardFrame::IsExpressionInsideHandler(int n) const {
305 Address address = GetExpressionAddress(n);
306 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
307 if (it.handler()->includes(address)) return true;
308 }
309 return false;
310}
311
312
313Object* JavaScriptFrame::GetParameter(int index) const {
314 ASSERT(index >= 0 && index < ComputeParametersCount());
315 const int offset = JavaScriptFrameConstants::kParam0Offset;
316 return Memory::Object_at(pp() + offset - (index * kPointerSize));
317}
318
319
320int JavaScriptFrame::ComputeParametersCount() const {
321 Address base = pp() + JavaScriptFrameConstants::kReceiverOffset;
322 Address limit = fp() + JavaScriptFrameConstants::kSavedRegistersOffset;
kasper.lund7276f142008-07-30 08:49:36 +0000323 return (base - limit) / kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000324}
325
326
327bool JavaScriptFrame::IsConstructor() const {
328 Address pc = has_adapted_arguments()
329 ? Memory::Address_at(ComputePCAddress(caller_fp()))
330 : caller_pc();
331 return IsConstructTrampolineFrame(pc);
332}
333
334
335Code* ArgumentsAdaptorFrame::FindCode() const {
336 return Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline);
337}
338
339
340Code* InternalFrame::FindCode() const {
341 const int offset = InternalFrameConstants::kCodeOffset;
342 Object* code = Memory::Object_at(fp() + offset);
343 if (code == NULL) {
344 // The code object isn't set; find it and set it.
345 code = Heap::FindCodeObject(pc());
346 ASSERT(!code->IsFailure());
347 Memory::Object_at(fp() + offset) = code;
348 }
349 ASSERT(code != NULL);
350 return Code::cast(code);
351}
352
353
354void StackFrame::PrintIndex(StringStream* accumulator,
355 PrintMode mode,
356 int index) {
357 accumulator->Add((mode == OVERVIEW) ? "%5d: " : "[%d]: ", index);
358}
359
360
361void JavaScriptFrame::Print(StringStream* accumulator,
362 PrintMode mode,
363 int index) const {
364 HandleScope scope;
365 Object* receiver = this->receiver();
366 Object* function = this->function();
367
368 accumulator->PrintSecurityTokenIfChanged(function);
369 PrintIndex(accumulator, mode, index);
370 Code* code = NULL;
371 if (IsConstructor()) accumulator->Add("new ");
372 accumulator->PrintFunction(function, receiver, &code);
373 accumulator->Add("(this=%o", receiver);
374
375 // Get scope information for nicer output, if possible. If code is
376 // NULL, or doesn't contain scope info, info will return 0 for the
377 // number of parameters, stack slots, or context slots.
378 ScopeInfo<PreallocatedStorage> info(code);
379
380 // Print the parameters.
381 int parameters_count = ComputeParametersCount();
382 for (int i = 0; i < parameters_count; i++) {
383 accumulator->Add(",");
384 // If we have a name for the parameter we print it. Nameless
385 // parameters are either because we have more actual parameters
386 // than formal parameters or because we have no scope information.
387 if (i < info.number_of_parameters()) {
388 accumulator->PrintName(*info.parameter_name(i));
389 accumulator->Add("=");
390 }
391 accumulator->Add("%o", GetParameter(i));
392 }
393
394 accumulator->Add(")");
395 if (mode == OVERVIEW) {
396 accumulator->Add("\n");
397 return;
398 }
399 accumulator->Add(" {\n");
400
401 // Compute the number of locals and expression stack elements.
402 int stack_locals_count = info.number_of_stack_slots();
403 int heap_locals_count = info.number_of_context_slots();
404 int expressions_count = ComputeExpressionsCount();
405
406 // Print stack-allocated local variables.
407 if (stack_locals_count > 0) {
408 accumulator->Add(" // stack-allocated locals\n");
409 }
410 for (int i = 0; i < stack_locals_count; i++) {
411 accumulator->Add(" var ");
412 accumulator->PrintName(*info.stack_slot_name(i));
413 accumulator->Add(" = ");
414 if (i < expressions_count) {
415 accumulator->Add("%o", GetExpression(i));
416 } else {
417 accumulator->Add("// no expression found - inconsistent frame?");
418 }
419 accumulator->Add("\n");
420 }
421
422 // Try to get hold of the context of this frame.
423 Context* context = NULL;
424 if (this->context() != NULL && this->context()->IsContext()) {
425 context = Context::cast(this->context());
426 }
427
428 // Print heap-allocated local variables.
429 if (heap_locals_count > Context::MIN_CONTEXT_SLOTS) {
430 accumulator->Add(" // heap-allocated locals\n");
431 }
432 for (int i = Context::MIN_CONTEXT_SLOTS; i < heap_locals_count; i++) {
433 accumulator->Add(" var ");
434 accumulator->PrintName(*info.context_slot_name(i));
435 accumulator->Add(" = ");
436 if (context != NULL) {
437 if (i < context->length()) {
438 accumulator->Add("%o", context->get(i));
439 } else {
440 accumulator->Add(
441 "// warning: missing context slot - inconsistent frame?");
442 }
443 } else {
444 accumulator->Add("// warning: no context found - inconsistent frame?");
445 }
446 accumulator->Add("\n");
447 }
448
449 // Print the expression stack.
kasper.lund7276f142008-07-30 08:49:36 +0000450 int expressions_start = stack_locals_count;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000451 if (expressions_start < expressions_count) {
452 accumulator->Add(" // expression stack (top to bottom)\n");
453 }
454 for (int i = expressions_count - 1; i >= expressions_start; i--) {
455 if (IsExpressionInsideHandler(i)) continue;
456 accumulator->Add(" [%02d] : %o\n", i, GetExpression(i));
457 }
458
459 // Print details about the function.
460 if (FLAG_max_stack_trace_source_length != 0 && code != NULL) {
461 SharedFunctionInfo* shared = JSFunction::cast(function)->shared();
462 accumulator->Add("--------- s o u r c e c o d e ---------\n");
463 shared->SourceCodePrint(accumulator, FLAG_max_stack_trace_source_length);
464 accumulator->Add("\n-----------------------------------------\n");
465 }
466
467 accumulator->Add("}\n\n");
468}
469
470
471void ArgumentsAdaptorFrame::Print(StringStream* accumulator,
472 PrintMode mode,
473 int index) const {
474 int actual = ComputeParametersCount();
475 int expected = -1;
476 Object* function = this->function();
477 if (function->IsJSFunction()) {
478 expected = JSFunction::cast(function)->shared()->formal_parameter_count();
479 }
480
481 PrintIndex(accumulator, mode, index);
482 accumulator->Add("arguments adaptor frame: %d->%d", actual, expected);
483 if (mode == OVERVIEW) {
484 accumulator->Add("\n");
485 return;
486 }
487 accumulator->Add(" {\n");
488
489 // Print actual arguments.
490 if (actual > 0) accumulator->Add(" // actual arguments\n");
491 for (int i = 0; i < actual; i++) {
492 accumulator->Add(" [%02d] : %o", i, GetParameter(i));
493 if (expected != -1 && i >= expected) {
494 accumulator->Add(" // not passed to callee");
495 }
496 accumulator->Add("\n");
497 }
498
499 accumulator->Add("}\n\n");
500}
501
502
503void EntryFrame::Iterate(ObjectVisitor* v) const {
504 StackHandlerIterator it(this, top_handler());
505 ASSERT(!it.done());
506 StackHandler* handler = it.handler();
507 ASSERT(handler->is_entry());
508 handler->Iterate(v);
509 // Make sure that there's the entry frame does not contain more than
510 // one stack handler.
511 if (kDebug) {
512 it.Advance();
513 ASSERT(it.done());
514 }
515}
516
517
518void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
519 const int offset = StandardFrameConstants::kContextOffset;
520 Object** base = &Memory::Object_at(sp());
521 Object** limit = &Memory::Object_at(fp() + offset) + 1;
522 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
523 StackHandler* handler = it.handler();
524 // Traverse pointers down to - but not including - the next
525 // handler in the handler chain. Update the base to skip the
526 // handler and allow the handler to traverse its own pointers.
527 const Address address = handler->address();
528 v->VisitPointers(base, reinterpret_cast<Object**>(address));
529 base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize);
530 // Traverse the pointers in the handler itself.
531 handler->Iterate(v);
532 }
533 v->VisitPointers(base, limit);
534}
535
536
537void JavaScriptFrame::Iterate(ObjectVisitor* v) const {
538 IterateExpressions(v);
539
540 // Traverse callee-saved registers, receiver, and parameters.
541 const int kBaseOffset = JavaScriptFrameConstants::kSavedRegistersOffset;
542 const int kLimitOffset = JavaScriptFrameConstants::kReceiverOffset;
543 Object** base = &Memory::Object_at(fp() + kBaseOffset);
544 Object** limit = &Memory::Object_at(pp() + kLimitOffset) + 1;
545 v->VisitPointers(base, limit);
546}
547
548
549void InternalFrame::Iterate(ObjectVisitor* v) const {
550 // Internal frames only have object pointers on the expression stack
551 // as they never have any arguments.
552 IterateExpressions(v);
553}
554
555
556// -------------------------------------------------------------------------
557
558
559JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) {
560 ASSERT(n >= 0);
561 for (int i = 0; i <= n; i++) {
562 while (!iterator_.frame()->is_java_script()) iterator_.Advance();
563 if (i == n) return JavaScriptFrame::cast(iterator_.frame());
564 iterator_.Advance();
565 }
566 UNREACHABLE();
567 return NULL;
568}
569
570
571// -------------------------------------------------------------------------
572
573
574int NumRegs(RegList reglist) {
575 int n = 0;
576 while (reglist != 0) {
577 n++;
578 reglist &= reglist - 1; // clear one bit
579 }
580 return n;
581}
582
583
584int JSCallerSavedCode(int n) {
585 static int reg_code[kNumJSCallerSaved];
586 static bool initialized = false;
587 if (!initialized) {
588 initialized = true;
589 int i = 0;
590 for (int r = 0; r < kNumRegs; r++)
591 if ((kJSCallerSaved & (1 << r)) != 0)
592 reg_code[i++] = r;
593
594 ASSERT(i == kNumJSCallerSaved);
595 }
596 ASSERT(0 <= n && n < kNumJSCallerSaved);
597 return reg_code[n];
598}
599
600
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000601} } // namespace v8::internal