blob: dd0ea00c0e78bb8c06861215a5c3dbda7965054b [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"
35#include "zone-inl.h"
36
kasperl@chromium.org71affb52009-05-26 05:44:31 +000037namespace v8 {
38namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040// Iterator that supports traversing the stack handlers of a
41// particular frame. Needs to know the top of the handler chain.
42class StackHandlerIterator BASE_EMBEDDED {
43 public:
44 StackHandlerIterator(const StackFrame* frame, StackHandler* handler)
45 : limit_(frame->fp()), handler_(handler) {
46 // Make sure the handler has already been unwound to this frame.
47 ASSERT(frame->sp() <= handler->address());
48 }
49
50 StackHandler* handler() const { return handler_; }
51
52 bool done() { return handler_->address() > limit_; }
53 void Advance() {
54 ASSERT(!done());
55 handler_ = handler_->next();
56 }
57
58 private:
59 const Address limit_;
60 StackHandler* handler_;
61};
62
63
64// -------------------------------------------------------------------------
65
66
67#define INITIALIZE_SINGLETON(type, field) field##_(this),
68StackFrameIterator::StackFrameIterator()
69 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000070 frame_(NULL), handler_(NULL), thread_(Top::GetCurrentThread()),
71 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000072 Reset();
73}
74StackFrameIterator::StackFrameIterator(ThreadLocalTop* t)
75 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000076 frame_(NULL), handler_(NULL), thread_(t),
77 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000078 Reset();
79}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000080StackFrameIterator::StackFrameIterator(bool use_top, Address fp, Address sp)
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000081 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000082 frame_(NULL), handler_(NULL),
83 thread_(use_top ? Top::GetCurrentThread() : NULL),
84 fp_(use_top ? NULL : fp), sp_(sp),
85 advance_(use_top ? &StackFrameIterator::AdvanceWithHandler :
86 &StackFrameIterator::AdvanceWithoutHandler) {
87 if (use_top || fp != NULL) {
88 Reset();
89 }
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000090 JavaScriptFrame_.DisableHeapAccess();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000091}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000092
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000093#undef INITIALIZE_SINGLETON
94
95
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000096void StackFrameIterator::AdvanceWithHandler() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097 ASSERT(!done());
98 // Compute the state of the calling frame before restoring
99 // callee-saved registers and unwinding handlers. This allows the
100 // frame code that computes the caller state to access the top
101 // handler and the value of any callee-saved register if needed.
102 StackFrame::State state;
103 StackFrame::Type type = frame_->GetCallerState(&state);
104
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105 // Unwind handlers corresponding to the current frame.
106 StackHandlerIterator it(frame_, handler_);
107 while (!it.done()) it.Advance();
108 handler_ = it.handler();
109
110 // Advance to the calling frame.
111 frame_ = SingletonFor(type, &state);
112
113 // When we're done iterating over the stack frames, the handler
114 // chain must have been completely unwound.
115 ASSERT(!done() || handler_ == NULL);
116}
117
118
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000119void StackFrameIterator::AdvanceWithoutHandler() {
120 // A simpler version of Advance which doesn't care about handler.
121 ASSERT(!done());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000122 StackFrame::State state;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000123 StackFrame::Type type = frame_->GetCallerState(&state);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000124 frame_ = SingletonFor(type, &state);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000125}
126
127
128void StackFrameIterator::Reset() {
129 StackFrame::State state;
130 StackFrame::Type type;
131 if (thread_ != NULL) {
132 type = ExitFrame::GetStateForFramePointer(Top::c_entry_fp(thread_), &state);
133 handler_ = StackHandler::FromAddress(Top::handler(thread_));
134 } else {
135 ASSERT(fp_ != NULL);
136 state.fp = fp_;
137 state.sp = sp_;
138 state.pc_address =
139 reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp_));
140 type = StackFrame::ComputeType(&state);
141 if (SingletonFor(type) == NULL) return;
142 }
143 frame_ = SingletonFor(type, &state);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000144}
145
146
147StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type,
148 StackFrame::State* state) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 if (type == StackFrame::NONE) return NULL;
150 StackFrame* result = SingletonFor(type);
151 ASSERT(result != NULL);
152 result->state_ = *state;
153 return result;
154}
155
156
157StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000158#define FRAME_TYPE_CASE(type, field) \
159 case StackFrame::type: result = &field##_; break;
160
161 StackFrame* result = NULL;
162 switch (type) {
163 case StackFrame::NONE: return NULL;
164 STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
165 default: break;
166 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000167 return result;
168
169#undef FRAME_TYPE_CASE
170}
171
172
173// -------------------------------------------------------------------------
174
175
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000176StackTraceFrameIterator::StackTraceFrameIterator() {
177 if (!done() && !frame()->function()->IsJSFunction()) Advance();
178}
179
180
181void StackTraceFrameIterator::Advance() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000182 while (true) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000183 JavaScriptFrameIterator::Advance();
184 if (done()) return;
185 if (frame()->function()->IsJSFunction()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000186 }
187}
188
189
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000190// -------------------------------------------------------------------------
191
192
193SafeStackFrameIterator::SafeStackFrameIterator(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000194 Address fp, Address sp, Address low_bound, Address high_bound) :
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000195 low_bound_(low_bound), high_bound_(high_bound),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000196 is_valid_top_(
197 IsWithinBounds(low_bound, high_bound,
198 Top::c_entry_fp(Top::GetCurrentThread())) &&
199 Top::handler(Top::GetCurrentThread()) != NULL),
200 is_valid_fp_(IsWithinBounds(low_bound, high_bound, fp)),
201 is_working_iterator_(is_valid_top_ || is_valid_fp_),
202 iteration_done_(!is_working_iterator_),
203 iterator_(is_valid_top_, is_valid_fp_ ? fp : NULL, sp) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000204}
205
206
207void SafeStackFrameIterator::Advance() {
208 ASSERT(is_working_iterator_);
209 ASSERT(!done());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000210 StackFrame* last_frame = iterator_.frame();
211 Address last_sp = last_frame->sp(), last_fp = last_frame->fp();
212 // Before advancing to the next stack frame, perform pointer validity tests
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000213 iteration_done_ = !IsValidFrame(last_frame) ||
214 !CanIterateHandles(last_frame, iterator_.handler()) ||
215 !IsValidCaller(last_frame);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000216 if (iteration_done_) return;
217
218 iterator_.Advance();
219 if (iterator_.done()) return;
220 // Check that we have actually moved to the previous frame in the stack
221 StackFrame* prev_frame = iterator_.frame();
222 iteration_done_ = prev_frame->sp() < last_sp || prev_frame->fp() < last_fp;
223}
224
225
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000226bool SafeStackFrameIterator::CanIterateHandles(StackFrame* frame,
227 StackHandler* handler) {
228 // If StackIterator iterates over StackHandles, verify that
229 // StackHandlerIterator can be instantiated (see StackHandlerIterator
230 // constructor.)
231 return !is_valid_top_ || (frame->sp() <= handler->address());
232}
233
234
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000235bool SafeStackFrameIterator::IsValidFrame(StackFrame* frame) const {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000236 return IsValidStackAddress(frame->sp()) && IsValidStackAddress(frame->fp());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000237}
238
239
240bool SafeStackFrameIterator::IsValidCaller(StackFrame* frame) {
241 StackFrame::State state;
ager@chromium.org41826e72009-03-30 13:30:57 +0000242 if (frame->is_entry() || frame->is_entry_construct()) {
243 // See EntryFrame::GetCallerState. It computes the caller FP address
244 // and calls ExitFrame::GetStateForFramePointer on it. We need to be
245 // sure that caller FP address is valid.
246 Address caller_fp = Memory::Address_at(
247 frame->fp() + EntryFrameConstants::kCallerFPOffset);
248 if (!IsValidStackAddress(caller_fp)) {
249 return false;
250 }
251 } else if (frame->is_arguments_adaptor()) {
252 // See ArgumentsAdaptorFrame::GetCallerStackPointer. It assumes that
253 // the number of arguments is stored on stack as Smi. We need to check
254 // that it really an Smi.
255 Object* number_of_args = reinterpret_cast<ArgumentsAdaptorFrame*>(frame)->
256 GetExpression(0);
257 if (!number_of_args->IsSmi()) {
258 return false;
259 }
260 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000261 frame->ComputeCallerState(&state);
262 return IsValidStackAddress(state.sp) && IsValidStackAddress(state.fp) &&
263 iterator_.SingletonFor(frame->GetCallerState(&state)) != NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000264}
265
266
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000267void SafeStackFrameIterator::Reset() {
268 if (is_working_iterator_) {
269 iterator_.Reset();
270 iteration_done_ = false;
271 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000272}
273
274
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000275// -------------------------------------------------------------------------
276
277
278#ifdef ENABLE_LOGGING_AND_PROFILING
279SafeStackTraceFrameIterator::SafeStackTraceFrameIterator(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000280 Address fp, Address sp, Address low_bound, Address high_bound) :
281 SafeJavaScriptFrameIterator(fp, sp, low_bound, high_bound) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000282 if (!done() && !frame()->is_java_script()) Advance();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000283}
284
285
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000286void SafeStackTraceFrameIterator::Advance() {
287 while (true) {
288 SafeJavaScriptFrameIterator::Advance();
289 if (done()) return;
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000290 if (frame()->is_java_script()) return;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000291 }
292}
293#endif
294
295
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000296// -------------------------------------------------------------------------
297
298
299void StackHandler::Cook(Code* code) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000300 ASSERT(MarkCompactCollector::IsCompacting());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000301 ASSERT(code->contains(pc()));
302 set_pc(AddressFrom<Address>(pc() - code->instruction_start()));
303}
304
305
306void StackHandler::Uncook(Code* code) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000307 ASSERT(MarkCompactCollector::IsCompacting());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000308 set_pc(code->instruction_start() + OffsetFrom(pc()));
309 ASSERT(code->contains(pc()));
310}
311
312
313// -------------------------------------------------------------------------
314
315
316bool StackFrame::HasHandler() const {
317 StackHandlerIterator it(this, top_handler());
318 return !it.done();
319}
320
321
322void StackFrame::CookFramesForThread(ThreadLocalTop* thread) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000323 // Only cooking frames when the collector is compacting and thus moving code
324 // around.
325 ASSERT(MarkCompactCollector::IsCompacting());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000326 ASSERT(!thread->stack_is_cooked());
327 for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
328 it.frame()->Cook();
329 }
330 thread->set_stack_is_cooked(true);
331}
332
333
334void StackFrame::UncookFramesForThread(ThreadLocalTop* thread) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000335 // Only uncooking frames when the collector is compacting and thus moving code
336 // around.
337 ASSERT(MarkCompactCollector::IsCompacting());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000338 ASSERT(thread->stack_is_cooked());
339 for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
340 it.frame()->Uncook();
341 }
342 thread->set_stack_is_cooked(false);
343}
344
345
346void StackFrame::Cook() {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000347 Code* code = this->code();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000348 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
349 it.handler()->Cook(code);
350 }
351 ASSERT(code->contains(pc()));
352 set_pc(AddressFrom<Address>(pc() - code->instruction_start()));
353}
354
355
356void StackFrame::Uncook() {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000357 Code* code = this->code();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000358 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
359 it.handler()->Uncook(code);
360 }
361 set_pc(code->instruction_start() + OffsetFrom(pc()));
362 ASSERT(code->contains(pc()));
363}
364
365
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000366StackFrame::Type StackFrame::GetCallerState(State* state) const {
367 ComputeCallerState(state);
368 return ComputeType(state);
369}
370
371
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000372Code* EntryFrame::code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000373 return Heap::js_entry_code();
374}
375
376
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000377void EntryFrame::ComputeCallerState(State* state) const {
378 GetCallerState(state);
379}
380
381
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000382StackFrame::Type EntryFrame::GetCallerState(State* state) const {
383 const int offset = EntryFrameConstants::kCallerFPOffset;
384 Address fp = Memory::Address_at(this->fp() + offset);
385 return ExitFrame::GetStateForFramePointer(fp, state);
386}
387
388
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000389Code* EntryConstructFrame::code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000390 return Heap::js_construct_entry_code();
391}
392
393
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000394Code* ExitFrame::code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000395 return Heap::c_entry_code();
396}
397
398
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000399void ExitFrame::ComputeCallerState(State* state) const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400 // Setup the caller state.
401 state->sp = pp();
402 state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000403 state->pc_address
404 = reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000405}
406
407
408Address ExitFrame::GetCallerStackPointer() const {
409 return fp() + ExitFrameConstants::kPPDisplacement;
410}
411
412
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000413Code* ExitDebugFrame::code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414 return Heap::c_entry_debug_break_code();
415}
416
417
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000418Address StandardFrame::GetExpressionAddress(int n) const {
kasper.lund7276f142008-07-30 08:49:36 +0000419 const int offset = StandardFrameConstants::kExpressionsOffset;
420 return fp() + offset - n * kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000421}
422
423
424int StandardFrame::ComputeExpressionsCount() const {
425 const int offset =
426 StandardFrameConstants::kExpressionsOffset + kPointerSize;
427 Address base = fp() + offset;
428 Address limit = sp();
429 ASSERT(base >= limit); // stack grows downwards
430 // Include register-allocated locals in number of expressions.
kasper.lund7276f142008-07-30 08:49:36 +0000431 return (base - limit) / kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000432}
433
434
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000435void StandardFrame::ComputeCallerState(State* state) const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000436 state->sp = caller_sp();
437 state->fp = caller_fp();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000438 state->pc_address = reinterpret_cast<Address*>(ComputePCAddress(fp()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000439}
440
441
442bool StandardFrame::IsExpressionInsideHandler(int n) const {
443 Address address = GetExpressionAddress(n);
444 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
445 if (it.handler()->includes(address)) return true;
446 }
447 return false;
448}
449
450
451Object* JavaScriptFrame::GetParameter(int index) const {
452 ASSERT(index >= 0 && index < ComputeParametersCount());
453 const int offset = JavaScriptFrameConstants::kParam0Offset;
454 return Memory::Object_at(pp() + offset - (index * kPointerSize));
455}
456
457
458int JavaScriptFrame::ComputeParametersCount() const {
459 Address base = pp() + JavaScriptFrameConstants::kReceiverOffset;
460 Address limit = fp() + JavaScriptFrameConstants::kSavedRegistersOffset;
kasper.lund7276f142008-07-30 08:49:36 +0000461 return (base - limit) / kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000462}
463
464
465bool JavaScriptFrame::IsConstructor() const {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000466 Address fp = caller_fp();
467 if (has_adapted_arguments()) {
468 // Skip the arguments adaptor frame and look at the real caller.
469 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
470 }
471 return IsConstructFrame(fp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000472}
473
474
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000475Code* JavaScriptFrame::code() const {
476 JSFunction* function = JSFunction::cast(this->function());
477 return function->shared()->code();
478}
479
480
481Code* ArgumentsAdaptorFrame::code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000482 return Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline);
483}
484
485
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000486Code* InternalFrame::code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000487 const int offset = InternalFrameConstants::kCodeOffset;
488 Object* code = Memory::Object_at(fp() + offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000489 ASSERT(code != NULL);
490 return Code::cast(code);
491}
492
493
494void StackFrame::PrintIndex(StringStream* accumulator,
495 PrintMode mode,
496 int index) {
497 accumulator->Add((mode == OVERVIEW) ? "%5d: " : "[%d]: ", index);
498}
499
500
501void JavaScriptFrame::Print(StringStream* accumulator,
502 PrintMode mode,
503 int index) const {
504 HandleScope scope;
505 Object* receiver = this->receiver();
506 Object* function = this->function();
507
508 accumulator->PrintSecurityTokenIfChanged(function);
509 PrintIndex(accumulator, mode, index);
510 Code* code = NULL;
511 if (IsConstructor()) accumulator->Add("new ");
512 accumulator->PrintFunction(function, receiver, &code);
513 accumulator->Add("(this=%o", receiver);
514
515 // Get scope information for nicer output, if possible. If code is
516 // NULL, or doesn't contain scope info, info will return 0 for the
517 // number of parameters, stack slots, or context slots.
518 ScopeInfo<PreallocatedStorage> info(code);
519
520 // Print the parameters.
521 int parameters_count = ComputeParametersCount();
522 for (int i = 0; i < parameters_count; i++) {
523 accumulator->Add(",");
524 // If we have a name for the parameter we print it. Nameless
525 // parameters are either because we have more actual parameters
526 // than formal parameters or because we have no scope information.
527 if (i < info.number_of_parameters()) {
528 accumulator->PrintName(*info.parameter_name(i));
529 accumulator->Add("=");
530 }
531 accumulator->Add("%o", GetParameter(i));
532 }
533
534 accumulator->Add(")");
535 if (mode == OVERVIEW) {
536 accumulator->Add("\n");
537 return;
538 }
539 accumulator->Add(" {\n");
540
541 // Compute the number of locals and expression stack elements.
542 int stack_locals_count = info.number_of_stack_slots();
543 int heap_locals_count = info.number_of_context_slots();
544 int expressions_count = ComputeExpressionsCount();
545
546 // Print stack-allocated local variables.
547 if (stack_locals_count > 0) {
548 accumulator->Add(" // stack-allocated locals\n");
549 }
550 for (int i = 0; i < stack_locals_count; i++) {
551 accumulator->Add(" var ");
552 accumulator->PrintName(*info.stack_slot_name(i));
553 accumulator->Add(" = ");
554 if (i < expressions_count) {
555 accumulator->Add("%o", GetExpression(i));
556 } else {
557 accumulator->Add("// no expression found - inconsistent frame?");
558 }
559 accumulator->Add("\n");
560 }
561
562 // Try to get hold of the context of this frame.
563 Context* context = NULL;
564 if (this->context() != NULL && this->context()->IsContext()) {
565 context = Context::cast(this->context());
566 }
567
568 // Print heap-allocated local variables.
569 if (heap_locals_count > Context::MIN_CONTEXT_SLOTS) {
570 accumulator->Add(" // heap-allocated locals\n");
571 }
572 for (int i = Context::MIN_CONTEXT_SLOTS; i < heap_locals_count; i++) {
573 accumulator->Add(" var ");
574 accumulator->PrintName(*info.context_slot_name(i));
575 accumulator->Add(" = ");
576 if (context != NULL) {
577 if (i < context->length()) {
578 accumulator->Add("%o", context->get(i));
579 } else {
580 accumulator->Add(
581 "// warning: missing context slot - inconsistent frame?");
582 }
583 } else {
584 accumulator->Add("// warning: no context found - inconsistent frame?");
585 }
586 accumulator->Add("\n");
587 }
588
589 // Print the expression stack.
kasper.lund7276f142008-07-30 08:49:36 +0000590 int expressions_start = stack_locals_count;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000591 if (expressions_start < expressions_count) {
592 accumulator->Add(" // expression stack (top to bottom)\n");
593 }
594 for (int i = expressions_count - 1; i >= expressions_start; i--) {
595 if (IsExpressionInsideHandler(i)) continue;
596 accumulator->Add(" [%02d] : %o\n", i, GetExpression(i));
597 }
598
599 // Print details about the function.
600 if (FLAG_max_stack_trace_source_length != 0 && code != NULL) {
601 SharedFunctionInfo* shared = JSFunction::cast(function)->shared();
602 accumulator->Add("--------- s o u r c e c o d e ---------\n");
603 shared->SourceCodePrint(accumulator, FLAG_max_stack_trace_source_length);
604 accumulator->Add("\n-----------------------------------------\n");
605 }
606
607 accumulator->Add("}\n\n");
608}
609
610
611void ArgumentsAdaptorFrame::Print(StringStream* accumulator,
612 PrintMode mode,
613 int index) const {
614 int actual = ComputeParametersCount();
615 int expected = -1;
616 Object* function = this->function();
617 if (function->IsJSFunction()) {
618 expected = JSFunction::cast(function)->shared()->formal_parameter_count();
619 }
620
621 PrintIndex(accumulator, mode, index);
622 accumulator->Add("arguments adaptor frame: %d->%d", actual, expected);
623 if (mode == OVERVIEW) {
624 accumulator->Add("\n");
625 return;
626 }
627 accumulator->Add(" {\n");
628
629 // Print actual arguments.
630 if (actual > 0) accumulator->Add(" // actual arguments\n");
631 for (int i = 0; i < actual; i++) {
632 accumulator->Add(" [%02d] : %o", i, GetParameter(i));
633 if (expected != -1 && i >= expected) {
634 accumulator->Add(" // not passed to callee");
635 }
636 accumulator->Add("\n");
637 }
638
639 accumulator->Add("}\n\n");
640}
641
642
643void EntryFrame::Iterate(ObjectVisitor* v) const {
644 StackHandlerIterator it(this, top_handler());
645 ASSERT(!it.done());
646 StackHandler* handler = it.handler();
647 ASSERT(handler->is_entry());
648 handler->Iterate(v);
649 // Make sure that there's the entry frame does not contain more than
650 // one stack handler.
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000651#ifdef DEBUG
652 it.Advance();
653 ASSERT(it.done());
654#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000655}
656
657
658void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
659 const int offset = StandardFrameConstants::kContextOffset;
660 Object** base = &Memory::Object_at(sp());
661 Object** limit = &Memory::Object_at(fp() + offset) + 1;
662 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
663 StackHandler* handler = it.handler();
664 // Traverse pointers down to - but not including - the next
665 // handler in the handler chain. Update the base to skip the
666 // handler and allow the handler to traverse its own pointers.
667 const Address address = handler->address();
668 v->VisitPointers(base, reinterpret_cast<Object**>(address));
669 base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize);
670 // Traverse the pointers in the handler itself.
671 handler->Iterate(v);
672 }
673 v->VisitPointers(base, limit);
674}
675
676
677void JavaScriptFrame::Iterate(ObjectVisitor* v) const {
678 IterateExpressions(v);
679
680 // Traverse callee-saved registers, receiver, and parameters.
681 const int kBaseOffset = JavaScriptFrameConstants::kSavedRegistersOffset;
682 const int kLimitOffset = JavaScriptFrameConstants::kReceiverOffset;
683 Object** base = &Memory::Object_at(fp() + kBaseOffset);
684 Object** limit = &Memory::Object_at(pp() + kLimitOffset) + 1;
685 v->VisitPointers(base, limit);
686}
687
688
689void InternalFrame::Iterate(ObjectVisitor* v) const {
690 // Internal frames only have object pointers on the expression stack
691 // as they never have any arguments.
692 IterateExpressions(v);
693}
694
695
696// -------------------------------------------------------------------------
697
698
699JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) {
700 ASSERT(n >= 0);
701 for (int i = 0; i <= n; i++) {
702 while (!iterator_.frame()->is_java_script()) iterator_.Advance();
703 if (i == n) return JavaScriptFrame::cast(iterator_.frame());
704 iterator_.Advance();
705 }
706 UNREACHABLE();
707 return NULL;
708}
709
710
711// -------------------------------------------------------------------------
712
713
714int NumRegs(RegList reglist) {
715 int n = 0;
716 while (reglist != 0) {
717 n++;
718 reglist &= reglist - 1; // clear one bit
719 }
720 return n;
721}
722
723
724int JSCallerSavedCode(int n) {
725 static int reg_code[kNumJSCallerSaved];
726 static bool initialized = false;
727 if (!initialized) {
728 initialized = true;
729 int i = 0;
730 for (int r = 0; r < kNumRegs; r++)
731 if ((kJSCallerSaved & (1 << r)) != 0)
732 reg_code[i++] = r;
733
734 ASSERT(i == kNumJSCallerSaved);
735 }
736 ASSERT(0 <= n && n < kNumJSCallerSaved);
737 return reg_code[n];
738}
739
740
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000741} } // namespace v8::internal