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