blob: 24550a2ed07f0afeadd3d062a245d0ea2a36987e [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"
kasperl@chromium.org061ef742009-02-27 12:16:20 +000031#include "mark-compact.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032#include "scopeinfo.h"
33#include "string-stream.h"
34#include "top.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035
kasperl@chromium.org71affb52009-05-26 05:44:31 +000036namespace v8 {
37namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039// 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
ager@chromium.orgeadaf222009-06-16 09:43:10 +000051 bool done() {
52 return handler_ == NULL || handler_->address() > limit_;
53 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054 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)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000071 frame_(NULL), handler_(NULL), thread_(Top::GetCurrentThread()),
72 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073 Reset();
74}
75StackFrameIterator::StackFrameIterator(ThreadLocalTop* t)
76 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000077 frame_(NULL), handler_(NULL), thread_(t),
78 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000079 Reset();
80}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000081StackFrameIterator::StackFrameIterator(bool use_top, Address fp, Address sp)
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000082 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000083 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 }
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000091 JavaScriptFrame_.DisableHeapAccess();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000092}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000093
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000094#undef INITIALIZE_SINGLETON
95
96
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000097void StackFrameIterator::AdvanceWithHandler() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098 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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000106 // 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
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000120void StackFrameIterator::AdvanceWithoutHandler() {
121 // A simpler version of Advance which doesn't care about handler.
122 ASSERT(!done());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123 StackFrame::State state;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000124 StackFrame::Type type = frame_->GetCallerState(&state);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000125 frame_ = SingletonFor(type, &state);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000126}
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);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000145}
146
147
148StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type,
149 StackFrame::State* state) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000150 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) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000159#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 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000168 return result;
169
170#undef FRAME_TYPE_CASE
171}
172
173
174// -------------------------------------------------------------------------
175
176
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000177StackTraceFrameIterator::StackTraceFrameIterator() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000178 if (!done() && !IsValidFrame()) Advance();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000179}
180
181
182void StackTraceFrameIterator::Advance() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000183 while (true) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000184 JavaScriptFrameIterator::Advance();
185 if (done()) return;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000186 if (IsValidFrame()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000187 }
188}
189
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000198
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000199// -------------------------------------------------------------------------
200
201
202SafeStackFrameIterator::SafeStackFrameIterator(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000203 Address fp, Address sp, Address low_bound, Address high_bound) :
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000204 low_bound_(low_bound), high_bound_(high_bound),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000205 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) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000213}
214
215
216void SafeStackFrameIterator::Advance() {
217 ASSERT(is_working_iterator_);
218 ASSERT(!done());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000219 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
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000222 iteration_done_ = !IsValidFrame(last_frame) ||
223 !CanIterateHandles(last_frame, iterator_.handler()) ||
224 !IsValidCaller(last_frame);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000225 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
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000235bool 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
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000244bool SafeStackFrameIterator::IsValidFrame(StackFrame* frame) const {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000245 return IsValidStackAddress(frame->sp()) && IsValidStackAddress(frame->fp());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000246}
247
248
249bool SafeStackFrameIterator::IsValidCaller(StackFrame* frame) {
250 StackFrame::State state;
ager@chromium.org41826e72009-03-30 13:30:57 +0000251 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 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000270 frame->ComputeCallerState(&state);
271 return IsValidStackAddress(state.sp) && IsValidStackAddress(state.fp) &&
272 iterator_.SingletonFor(frame->GetCallerState(&state)) != NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000273}
274
275
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000276void SafeStackFrameIterator::Reset() {
277 if (is_working_iterator_) {
278 iterator_.Reset();
279 iteration_done_ = false;
280 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000281}
282
283
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000284// -------------------------------------------------------------------------
285
286
287#ifdef ENABLE_LOGGING_AND_PROFILING
288SafeStackTraceFrameIterator::SafeStackTraceFrameIterator(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000289 Address fp, Address sp, Address low_bound, Address high_bound) :
290 SafeJavaScriptFrameIterator(fp, sp, low_bound, high_bound) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000291 if (!done() && !frame()->is_java_script()) Advance();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000292}
293
294
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000295void SafeStackTraceFrameIterator::Advance() {
296 while (true) {
297 SafeJavaScriptFrameIterator::Advance();
298 if (done()) return;
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000299 if (frame()->is_java_script()) return;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000300 }
301}
302#endif
303
304
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000305// -------------------------------------------------------------------------
306
307
308void StackHandler::Cook(Code* code) {
309 ASSERT(code->contains(pc()));
310 set_pc(AddressFrom<Address>(pc() - code->instruction_start()));
311}
312
313
314void StackHandler::Uncook(Code* code) {
315 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) {
330 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) {
339 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() {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000348 Code* code = this->code();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000349 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
350 it.handler()->Cook(code);
351 }
352 ASSERT(code->contains(pc()));
353 set_pc(AddressFrom<Address>(pc() - code->instruction_start()));
354}
355
356
357void StackFrame::Uncook() {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000358 Code* code = this->code();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000359 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
360 it.handler()->Uncook(code);
361 }
362 set_pc(code->instruction_start() + OffsetFrom(pc()));
363 ASSERT(code->contains(pc()));
364}
365
366
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000367StackFrame::Type StackFrame::GetCallerState(State* state) const {
368 ComputeCallerState(state);
369 return ComputeType(state);
370}
371
372
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000373Code* EntryFrame::code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000374 return Heap::js_entry_code();
375}
376
377
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000378void EntryFrame::ComputeCallerState(State* state) const {
379 GetCallerState(state);
380}
381
382
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000383StackFrame::Type EntryFrame::GetCallerState(State* state) const {
384 const int offset = EntryFrameConstants::kCallerFPOffset;
385 Address fp = Memory::Address_at(this->fp() + offset);
386 return ExitFrame::GetStateForFramePointer(fp, state);
387}
388
389
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000390Code* EntryConstructFrame::code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000391 return Heap::js_construct_entry_code();
392}
393
394
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000395Object*& ExitFrame::code_slot() const {
396 const int offset = ExitFrameConstants::kCodeOffset;
397 return Memory::Object_at(fp() + offset);
398}
399
400
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000401Code* ExitFrame::code() const {
ager@chromium.org5c838252010-02-19 08:53:10 +0000402 return Code::cast(code_slot());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000403}
404
405
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000406void ExitFrame::ComputeCallerState(State* state) const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000407 // Setup the caller state.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000408 state->sp = caller_sp();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000409 state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000410 state->pc_address
411 = reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000412}
413
414
415Address ExitFrame::GetCallerStackPointer() const {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000416 return fp() + ExitFrameConstants::kCallerSPDisplacement;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000417}
418
419
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000420Address StandardFrame::GetExpressionAddress(int n) const {
kasper.lund7276f142008-07-30 08:49:36 +0000421 const int offset = StandardFrameConstants::kExpressionsOffset;
422 return fp() + offset - n * kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000423}
424
425
426int StandardFrame::ComputeExpressionsCount() const {
427 const int offset =
428 StandardFrameConstants::kExpressionsOffset + kPointerSize;
429 Address base = fp() + offset;
430 Address limit = sp();
431 ASSERT(base >= limit); // stack grows downwards
432 // Include register-allocated locals in number of expressions.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000433 return static_cast<int>((base - limit) / kPointerSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000434}
435
436
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000437void StandardFrame::ComputeCallerState(State* state) const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000438 state->sp = caller_sp();
439 state->fp = caller_fp();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440 state->pc_address = reinterpret_cast<Address*>(ComputePCAddress(fp()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000441}
442
443
444bool StandardFrame::IsExpressionInsideHandler(int n) const {
445 Address address = GetExpressionAddress(n);
446 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
447 if (it.handler()->includes(address)) return true;
448 }
449 return false;
450}
451
452
453Object* JavaScriptFrame::GetParameter(int index) const {
454 ASSERT(index >= 0 && index < ComputeParametersCount());
455 const int offset = JavaScriptFrameConstants::kParam0Offset;
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000456 return Memory::Object_at(caller_sp() + offset - (index * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000457}
458
459
460int JavaScriptFrame::ComputeParametersCount() const {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000461 Address base = caller_sp() + JavaScriptFrameConstants::kReceiverOffset;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000462 Address limit = fp() + JavaScriptFrameConstants::kSavedRegistersOffset;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000463 return static_cast<int>((base - limit) / kPointerSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000464}
465
466
467bool JavaScriptFrame::IsConstructor() const {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000468 Address fp = caller_fp();
469 if (has_adapted_arguments()) {
470 // Skip the arguments adaptor frame and look at the real caller.
471 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
472 }
473 return IsConstructFrame(fp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000474}
475
476
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000477Code* JavaScriptFrame::code() const {
478 JSFunction* function = JSFunction::cast(this->function());
479 return function->shared()->code();
480}
481
482
483Code* ArgumentsAdaptorFrame::code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000484 return Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline);
485}
486
487
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000488Code* InternalFrame::code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000489 const int offset = InternalFrameConstants::kCodeOffset;
490 Object* code = Memory::Object_at(fp() + offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000491 ASSERT(code != NULL);
492 return Code::cast(code);
493}
494
495
496void StackFrame::PrintIndex(StringStream* accumulator,
497 PrintMode mode,
498 int index) {
499 accumulator->Add((mode == OVERVIEW) ? "%5d: " : "[%d]: ", index);
500}
501
502
503void JavaScriptFrame::Print(StringStream* accumulator,
504 PrintMode mode,
505 int index) const {
506 HandleScope scope;
507 Object* receiver = this->receiver();
508 Object* function = this->function();
509
510 accumulator->PrintSecurityTokenIfChanged(function);
511 PrintIndex(accumulator, mode, index);
512 Code* code = NULL;
513 if (IsConstructor()) accumulator->Add("new ");
514 accumulator->PrintFunction(function, receiver, &code);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000515
516 if (function->IsJSFunction()) {
517 Handle<SharedFunctionInfo> shared(JSFunction::cast(function)->shared());
518 Object* script_obj = shared->script();
519 if (script_obj->IsScript()) {
520 Handle<Script> script(Script::cast(script_obj));
521 accumulator->Add(" [");
522 accumulator->PrintName(script->name());
523
524 Address pc = this->pc();
525 if (code != NULL && code->kind() == Code::FUNCTION &&
526 pc >= code->instruction_start() && pc < code->relocation_start()) {
527 int source_pos = code->SourcePosition(pc);
528 int line = GetScriptLineNumberSafe(script, source_pos) + 1;
529 accumulator->Add(":%d", line);
530 } else {
531 int function_start_pos = shared->start_position();
532 int line = GetScriptLineNumberSafe(script, function_start_pos) + 1;
533 accumulator->Add(":~%d", line);
534 }
535
536 accumulator->Add("] ");
537 }
538 }
539
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540 accumulator->Add("(this=%o", receiver);
541
542 // Get scope information for nicer output, if possible. If code is
543 // NULL, or doesn't contain scope info, info will return 0 for the
544 // number of parameters, stack slots, or context slots.
545 ScopeInfo<PreallocatedStorage> info(code);
546
547 // Print the parameters.
548 int parameters_count = ComputeParametersCount();
549 for (int i = 0; i < parameters_count; i++) {
550 accumulator->Add(",");
551 // If we have a name for the parameter we print it. Nameless
552 // parameters are either because we have more actual parameters
553 // than formal parameters or because we have no scope information.
554 if (i < info.number_of_parameters()) {
555 accumulator->PrintName(*info.parameter_name(i));
556 accumulator->Add("=");
557 }
558 accumulator->Add("%o", GetParameter(i));
559 }
560
561 accumulator->Add(")");
562 if (mode == OVERVIEW) {
563 accumulator->Add("\n");
564 return;
565 }
566 accumulator->Add(" {\n");
567
568 // Compute the number of locals and expression stack elements.
569 int stack_locals_count = info.number_of_stack_slots();
570 int heap_locals_count = info.number_of_context_slots();
571 int expressions_count = ComputeExpressionsCount();
572
573 // Print stack-allocated local variables.
574 if (stack_locals_count > 0) {
575 accumulator->Add(" // stack-allocated locals\n");
576 }
577 for (int i = 0; i < stack_locals_count; i++) {
578 accumulator->Add(" var ");
579 accumulator->PrintName(*info.stack_slot_name(i));
580 accumulator->Add(" = ");
581 if (i < expressions_count) {
582 accumulator->Add("%o", GetExpression(i));
583 } else {
584 accumulator->Add("// no expression found - inconsistent frame?");
585 }
586 accumulator->Add("\n");
587 }
588
589 // Try to get hold of the context of this frame.
590 Context* context = NULL;
591 if (this->context() != NULL && this->context()->IsContext()) {
592 context = Context::cast(this->context());
593 }
594
595 // Print heap-allocated local variables.
596 if (heap_locals_count > Context::MIN_CONTEXT_SLOTS) {
597 accumulator->Add(" // heap-allocated locals\n");
598 }
599 for (int i = Context::MIN_CONTEXT_SLOTS; i < heap_locals_count; i++) {
600 accumulator->Add(" var ");
601 accumulator->PrintName(*info.context_slot_name(i));
602 accumulator->Add(" = ");
603 if (context != NULL) {
604 if (i < context->length()) {
605 accumulator->Add("%o", context->get(i));
606 } else {
607 accumulator->Add(
608 "// warning: missing context slot - inconsistent frame?");
609 }
610 } else {
611 accumulator->Add("// warning: no context found - inconsistent frame?");
612 }
613 accumulator->Add("\n");
614 }
615
616 // Print the expression stack.
kasper.lund7276f142008-07-30 08:49:36 +0000617 int expressions_start = stack_locals_count;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000618 if (expressions_start < expressions_count) {
619 accumulator->Add(" // expression stack (top to bottom)\n");
620 }
621 for (int i = expressions_count - 1; i >= expressions_start; i--) {
622 if (IsExpressionInsideHandler(i)) continue;
623 accumulator->Add(" [%02d] : %o\n", i, GetExpression(i));
624 }
625
626 // Print details about the function.
627 if (FLAG_max_stack_trace_source_length != 0 && code != NULL) {
628 SharedFunctionInfo* shared = JSFunction::cast(function)->shared();
629 accumulator->Add("--------- s o u r c e c o d e ---------\n");
630 shared->SourceCodePrint(accumulator, FLAG_max_stack_trace_source_length);
631 accumulator->Add("\n-----------------------------------------\n");
632 }
633
634 accumulator->Add("}\n\n");
635}
636
637
638void ArgumentsAdaptorFrame::Print(StringStream* accumulator,
639 PrintMode mode,
640 int index) const {
641 int actual = ComputeParametersCount();
642 int expected = -1;
643 Object* function = this->function();
644 if (function->IsJSFunction()) {
645 expected = JSFunction::cast(function)->shared()->formal_parameter_count();
646 }
647
648 PrintIndex(accumulator, mode, index);
649 accumulator->Add("arguments adaptor frame: %d->%d", actual, expected);
650 if (mode == OVERVIEW) {
651 accumulator->Add("\n");
652 return;
653 }
654 accumulator->Add(" {\n");
655
656 // Print actual arguments.
657 if (actual > 0) accumulator->Add(" // actual arguments\n");
658 for (int i = 0; i < actual; i++) {
659 accumulator->Add(" [%02d] : %o", i, GetParameter(i));
660 if (expected != -1 && i >= expected) {
661 accumulator->Add(" // not passed to callee");
662 }
663 accumulator->Add("\n");
664 }
665
666 accumulator->Add("}\n\n");
667}
668
669
670void EntryFrame::Iterate(ObjectVisitor* v) const {
671 StackHandlerIterator it(this, top_handler());
672 ASSERT(!it.done());
673 StackHandler* handler = it.handler();
674 ASSERT(handler->is_entry());
675 handler->Iterate(v);
676 // Make sure that there's the entry frame does not contain more than
677 // one stack handler.
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000678#ifdef DEBUG
679 it.Advance();
680 ASSERT(it.done());
681#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000682}
683
684
685void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
686 const int offset = StandardFrameConstants::kContextOffset;
687 Object** base = &Memory::Object_at(sp());
688 Object** limit = &Memory::Object_at(fp() + offset) + 1;
689 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
690 StackHandler* handler = it.handler();
691 // Traverse pointers down to - but not including - the next
692 // handler in the handler chain. Update the base to skip the
693 // handler and allow the handler to traverse its own pointers.
694 const Address address = handler->address();
695 v->VisitPointers(base, reinterpret_cast<Object**>(address));
696 base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize);
697 // Traverse the pointers in the handler itself.
698 handler->Iterate(v);
699 }
700 v->VisitPointers(base, limit);
701}
702
703
704void JavaScriptFrame::Iterate(ObjectVisitor* v) const {
705 IterateExpressions(v);
706
707 // Traverse callee-saved registers, receiver, and parameters.
708 const int kBaseOffset = JavaScriptFrameConstants::kSavedRegistersOffset;
709 const int kLimitOffset = JavaScriptFrameConstants::kReceiverOffset;
710 Object** base = &Memory::Object_at(fp() + kBaseOffset);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000711 Object** limit = &Memory::Object_at(caller_sp() + kLimitOffset) + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000712 v->VisitPointers(base, limit);
713}
714
715
716void InternalFrame::Iterate(ObjectVisitor* v) const {
717 // Internal frames only have object pointers on the expression stack
718 // as they never have any arguments.
719 IterateExpressions(v);
720}
721
722
723// -------------------------------------------------------------------------
724
725
726JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) {
727 ASSERT(n >= 0);
728 for (int i = 0; i <= n; i++) {
729 while (!iterator_.frame()->is_java_script()) iterator_.Advance();
730 if (i == n) return JavaScriptFrame::cast(iterator_.frame());
731 iterator_.Advance();
732 }
733 UNREACHABLE();
734 return NULL;
735}
736
737
738// -------------------------------------------------------------------------
739
740
741int NumRegs(RegList reglist) {
742 int n = 0;
743 while (reglist != 0) {
744 n++;
745 reglist &= reglist - 1; // clear one bit
746 }
747 return n;
748}
749
750
751int JSCallerSavedCode(int n) {
752 static int reg_code[kNumJSCallerSaved];
753 static bool initialized = false;
754 if (!initialized) {
755 initialized = true;
756 int i = 0;
757 for (int r = 0; r < kNumRegs; r++)
758 if ((kJSCallerSaved & (1 << r)) != 0)
759 reg_code[i++] = r;
760
761 ASSERT(i == kNumJSCallerSaved);
762 }
763 ASSERT(0 <= n && n < kNumJSCallerSaved);
764 return reg_code[n];
765}
766
767
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000768} } // namespace v8::internal