blob: 88c723d6932d2eabae3a1bfd86c1604c81fa9d15 [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
37namespace v8 { namespace internal {
38
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
51 bool done() { return handler_->address() > limit_; }
52 void Advance() {
53 ASSERT(!done());
54 handler_ = handler_->next();
55 }
56
57 private:
58 const Address limit_;
59 StackHandler* handler_;
60};
61
62
63// -------------------------------------------------------------------------
64
65
66#define INITIALIZE_SINGLETON(type, field) field##_(this),
67StackFrameIterator::StackFrameIterator()
68 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000069 frame_(NULL), handler_(NULL), thread_(Top::GetCurrentThread()),
70 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000071 Reset();
72}
73StackFrameIterator::StackFrameIterator(ThreadLocalTop* t)
74 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000075 frame_(NULL), handler_(NULL), thread_(t),
76 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000077 Reset();
78}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000079StackFrameIterator::StackFrameIterator(bool use_top, Address fp, Address sp)
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000080 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000081 frame_(NULL), handler_(NULL),
82 thread_(use_top ? Top::GetCurrentThread() : NULL),
83 fp_(use_top ? NULL : fp), sp_(sp),
84 advance_(use_top ? &StackFrameIterator::AdvanceWithHandler :
85 &StackFrameIterator::AdvanceWithoutHandler) {
86 if (use_top || fp != NULL) {
87 Reset();
88 }
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000089 JavaScriptFrame_.DisableHeapAccess();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000090}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000091
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000092#undef INITIALIZE_SINGLETON
93
94
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000095void StackFrameIterator::AdvanceWithHandler() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096 ASSERT(!done());
97 // Compute the state of the calling frame before restoring
98 // callee-saved registers and unwinding handlers. This allows the
99 // frame code that computes the caller state to access the top
100 // handler and the value of any callee-saved register if needed.
101 StackFrame::State state;
102 StackFrame::Type type = frame_->GetCallerState(&state);
103
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000104 // Unwind handlers corresponding to the current frame.
105 StackHandlerIterator it(frame_, handler_);
106 while (!it.done()) it.Advance();
107 handler_ = it.handler();
108
109 // Advance to the calling frame.
110 frame_ = SingletonFor(type, &state);
111
112 // When we're done iterating over the stack frames, the handler
113 // chain must have been completely unwound.
114 ASSERT(!done() || handler_ == NULL);
115}
116
117
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000118void StackFrameIterator::AdvanceWithoutHandler() {
119 // A simpler version of Advance which doesn't care about handler.
120 ASSERT(!done());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000121 StackFrame::State state;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000122 StackFrame::Type type = frame_->GetCallerState(&state);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123 frame_ = SingletonFor(type, &state);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000124}
125
126
127void StackFrameIterator::Reset() {
128 StackFrame::State state;
129 StackFrame::Type type;
130 if (thread_ != NULL) {
131 type = ExitFrame::GetStateForFramePointer(Top::c_entry_fp(thread_), &state);
132 handler_ = StackHandler::FromAddress(Top::handler(thread_));
133 } else {
134 ASSERT(fp_ != NULL);
135 state.fp = fp_;
136 state.sp = sp_;
137 state.pc_address =
138 reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp_));
139 type = StackFrame::ComputeType(&state);
140 if (SingletonFor(type) == NULL) return;
141 }
142 frame_ = SingletonFor(type, &state);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000143}
144
145
146StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type,
147 StackFrame::State* state) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000148 if (type == StackFrame::NONE) return NULL;
149 StackFrame* result = SingletonFor(type);
150 ASSERT(result != NULL);
151 result->state_ = *state;
152 return result;
153}
154
155
156StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000157#define FRAME_TYPE_CASE(type, field) \
158 case StackFrame::type: result = &field##_; break;
159
160 StackFrame* result = NULL;
161 switch (type) {
162 case StackFrame::NONE: return NULL;
163 STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
164 default: break;
165 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000166 return result;
167
168#undef FRAME_TYPE_CASE
169}
170
171
172// -------------------------------------------------------------------------
173
174
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000175StackTraceFrameIterator::StackTraceFrameIterator() {
176 if (!done() && !frame()->function()->IsJSFunction()) Advance();
177}
178
179
180void StackTraceFrameIterator::Advance() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000181 while (true) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000182 JavaScriptFrameIterator::Advance();
183 if (done()) return;
184 if (frame()->function()->IsJSFunction()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000185 }
186}
187
188
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000189// -------------------------------------------------------------------------
190
191
192SafeStackFrameIterator::SafeStackFrameIterator(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000193 Address fp, Address sp, Address low_bound, Address high_bound) :
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000194 low_bound_(low_bound), high_bound_(high_bound),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000195 is_valid_top_(
196 IsWithinBounds(low_bound, high_bound,
197 Top::c_entry_fp(Top::GetCurrentThread())) &&
198 Top::handler(Top::GetCurrentThread()) != NULL),
199 is_valid_fp_(IsWithinBounds(low_bound, high_bound, fp)),
200 is_working_iterator_(is_valid_top_ || is_valid_fp_),
201 iteration_done_(!is_working_iterator_),
202 iterator_(is_valid_top_, is_valid_fp_ ? fp : NULL, sp) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000203}
204
205
206void SafeStackFrameIterator::Advance() {
207 ASSERT(is_working_iterator_);
208 ASSERT(!done());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000209 StackFrame* last_frame = iterator_.frame();
210 Address last_sp = last_frame->sp(), last_fp = last_frame->fp();
211 // Before advancing to the next stack frame, perform pointer validity tests
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000212 iteration_done_ = !IsValidFrame(last_frame) ||
213 !CanIterateHandles(last_frame, iterator_.handler()) ||
214 !IsValidCaller(last_frame);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000215 if (iteration_done_) return;
216
217 iterator_.Advance();
218 if (iterator_.done()) return;
219 // Check that we have actually moved to the previous frame in the stack
220 StackFrame* prev_frame = iterator_.frame();
221 iteration_done_ = prev_frame->sp() < last_sp || prev_frame->fp() < last_fp;
222}
223
224
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000225bool SafeStackFrameIterator::CanIterateHandles(StackFrame* frame,
226 StackHandler* handler) {
227 // If StackIterator iterates over StackHandles, verify that
228 // StackHandlerIterator can be instantiated (see StackHandlerIterator
229 // constructor.)
230 return !is_valid_top_ || (frame->sp() <= handler->address());
231}
232
233
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000234bool SafeStackFrameIterator::IsValidFrame(StackFrame* frame) const {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000235 return IsValidStackAddress(frame->sp()) && IsValidStackAddress(frame->fp());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000236}
237
238
239bool SafeStackFrameIterator::IsValidCaller(StackFrame* frame) {
240 StackFrame::State state;
ager@chromium.org41826e72009-03-30 13:30:57 +0000241 if (frame->is_entry() || frame->is_entry_construct()) {
242 // See EntryFrame::GetCallerState. It computes the caller FP address
243 // and calls ExitFrame::GetStateForFramePointer on it. We need to be
244 // sure that caller FP address is valid.
245 Address caller_fp = Memory::Address_at(
246 frame->fp() + EntryFrameConstants::kCallerFPOffset);
247 if (!IsValidStackAddress(caller_fp)) {
248 return false;
249 }
250 } else if (frame->is_arguments_adaptor()) {
251 // See ArgumentsAdaptorFrame::GetCallerStackPointer. It assumes that
252 // the number of arguments is stored on stack as Smi. We need to check
253 // that it really an Smi.
254 Object* number_of_args = reinterpret_cast<ArgumentsAdaptorFrame*>(frame)->
255 GetExpression(0);
256 if (!number_of_args->IsSmi()) {
257 return false;
258 }
259 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000260 frame->ComputeCallerState(&state);
261 return IsValidStackAddress(state.sp) && IsValidStackAddress(state.fp) &&
262 iterator_.SingletonFor(frame->GetCallerState(&state)) != NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000263}
264
265
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000266void SafeStackFrameIterator::Reset() {
267 if (is_working_iterator_) {
268 iterator_.Reset();
269 iteration_done_ = false;
270 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000271}
272
273
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000274// -------------------------------------------------------------------------
275
276
277#ifdef ENABLE_LOGGING_AND_PROFILING
278SafeStackTraceFrameIterator::SafeStackTraceFrameIterator(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000279 Address fp, Address sp, Address low_bound, Address high_bound) :
280 SafeJavaScriptFrameIterator(fp, sp, low_bound, high_bound) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000281 if (!done() && !frame()->is_java_script()) Advance();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000282}
283
284
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000285void SafeStackTraceFrameIterator::Advance() {
286 while (true) {
287 SafeJavaScriptFrameIterator::Advance();
288 if (done()) return;
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000289 if (frame()->is_java_script()) return;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000290 }
291}
292#endif
293
294
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000295// -------------------------------------------------------------------------
296
297
298void StackHandler::Cook(Code* code) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000299 ASSERT(MarkCompactCollector::IsCompacting());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000300 ASSERT(code->contains(pc()));
301 set_pc(AddressFrom<Address>(pc() - code->instruction_start()));
302}
303
304
305void StackHandler::Uncook(Code* code) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000306 ASSERT(MarkCompactCollector::IsCompacting());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000307 set_pc(code->instruction_start() + OffsetFrom(pc()));
308 ASSERT(code->contains(pc()));
309}
310
311
312// -------------------------------------------------------------------------
313
314
315bool StackFrame::HasHandler() const {
316 StackHandlerIterator it(this, top_handler());
317 return !it.done();
318}
319
320
321void StackFrame::CookFramesForThread(ThreadLocalTop* thread) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000322 // Only cooking frames when the collector is compacting and thus moving code
323 // around.
324 ASSERT(MarkCompactCollector::IsCompacting());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000325 ASSERT(!thread->stack_is_cooked());
326 for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
327 it.frame()->Cook();
328 }
329 thread->set_stack_is_cooked(true);
330}
331
332
333void StackFrame::UncookFramesForThread(ThreadLocalTop* thread) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000334 // Only uncooking frames when the collector is compacting and thus moving code
335 // around.
336 ASSERT(MarkCompactCollector::IsCompacting());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000337 ASSERT(thread->stack_is_cooked());
338 for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
339 it.frame()->Uncook();
340 }
341 thread->set_stack_is_cooked(false);
342}
343
344
345void StackFrame::Cook() {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000346 Code* code = this->code();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000347 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
348 it.handler()->Cook(code);
349 }
350 ASSERT(code->contains(pc()));
351 set_pc(AddressFrom<Address>(pc() - code->instruction_start()));
352}
353
354
355void StackFrame::Uncook() {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000356 Code* code = this->code();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000357 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
358 it.handler()->Uncook(code);
359 }
360 set_pc(code->instruction_start() + OffsetFrom(pc()));
361 ASSERT(code->contains(pc()));
362}
363
364
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000365StackFrame::Type StackFrame::GetCallerState(State* state) const {
366 ComputeCallerState(state);
367 return ComputeType(state);
368}
369
370
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000371Code* EntryFrame::code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000372 return Heap::js_entry_code();
373}
374
375
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000376void EntryFrame::ComputeCallerState(State* state) const {
377 GetCallerState(state);
378}
379
380
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381StackFrame::Type EntryFrame::GetCallerState(State* state) const {
382 const int offset = EntryFrameConstants::kCallerFPOffset;
383 Address fp = Memory::Address_at(this->fp() + offset);
384 return ExitFrame::GetStateForFramePointer(fp, state);
385}
386
387
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000388Code* EntryConstructFrame::code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000389 return Heap::js_construct_entry_code();
390}
391
392
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000393Code* ExitFrame::code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000394 return Heap::c_entry_code();
395}
396
397
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000398void ExitFrame::ComputeCallerState(State* state) const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399 // Setup the caller state.
400 state->sp = pp();
401 state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000402 state->pc_address
403 = reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000404}
405
406
407Address ExitFrame::GetCallerStackPointer() const {
408 return fp() + ExitFrameConstants::kPPDisplacement;
409}
410
411
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000412Code* ExitDebugFrame::code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000413 return Heap::c_entry_debug_break_code();
414}
415
416
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000417Address StandardFrame::GetExpressionAddress(int n) const {
kasper.lund7276f142008-07-30 08:49:36 +0000418 const int offset = StandardFrameConstants::kExpressionsOffset;
419 return fp() + offset - n * kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000420}
421
422
423int StandardFrame::ComputeExpressionsCount() const {
424 const int offset =
425 StandardFrameConstants::kExpressionsOffset + kPointerSize;
426 Address base = fp() + offset;
427 Address limit = sp();
428 ASSERT(base >= limit); // stack grows downwards
429 // Include register-allocated locals in number of expressions.
kasper.lund7276f142008-07-30 08:49:36 +0000430 return (base - limit) / kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000431}
432
433
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000434void StandardFrame::ComputeCallerState(State* state) const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000435 state->sp = caller_sp();
436 state->fp = caller_fp();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437 state->pc_address = reinterpret_cast<Address*>(ComputePCAddress(fp()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000438}
439
440
441bool StandardFrame::IsExpressionInsideHandler(int n) const {
442 Address address = GetExpressionAddress(n);
443 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
444 if (it.handler()->includes(address)) return true;
445 }
446 return false;
447}
448
449
450Object* JavaScriptFrame::GetParameter(int index) const {
451 ASSERT(index >= 0 && index < ComputeParametersCount());
452 const int offset = JavaScriptFrameConstants::kParam0Offset;
453 return Memory::Object_at(pp() + offset - (index * kPointerSize));
454}
455
456
457int JavaScriptFrame::ComputeParametersCount() const {
458 Address base = pp() + JavaScriptFrameConstants::kReceiverOffset;
459 Address limit = fp() + JavaScriptFrameConstants::kSavedRegistersOffset;
kasper.lund7276f142008-07-30 08:49:36 +0000460 return (base - limit) / kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000461}
462
463
464bool JavaScriptFrame::IsConstructor() const {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000465 Address fp = caller_fp();
466 if (has_adapted_arguments()) {
467 // Skip the arguments adaptor frame and look at the real caller.
468 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
469 }
470 return IsConstructFrame(fp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000471}
472
473
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000474Code* JavaScriptFrame::code() const {
475 JSFunction* function = JSFunction::cast(this->function());
476 return function->shared()->code();
477}
478
479
480Code* ArgumentsAdaptorFrame::code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000481 return Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline);
482}
483
484
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000485Code* InternalFrame::code() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000486 const int offset = InternalFrameConstants::kCodeOffset;
487 Object* code = Memory::Object_at(fp() + offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000488 ASSERT(code != NULL);
489 return Code::cast(code);
490}
491
492
493void StackFrame::PrintIndex(StringStream* accumulator,
494 PrintMode mode,
495 int index) {
496 accumulator->Add((mode == OVERVIEW) ? "%5d: " : "[%d]: ", index);
497}
498
499
500void JavaScriptFrame::Print(StringStream* accumulator,
501 PrintMode mode,
502 int index) const {
503 HandleScope scope;
504 Object* receiver = this->receiver();
505 Object* function = this->function();
506
507 accumulator->PrintSecurityTokenIfChanged(function);
508 PrintIndex(accumulator, mode, index);
509 Code* code = NULL;
510 if (IsConstructor()) accumulator->Add("new ");
511 accumulator->PrintFunction(function, receiver, &code);
512 accumulator->Add("(this=%o", receiver);
513
514 // Get scope information for nicer output, if possible. If code is
515 // NULL, or doesn't contain scope info, info will return 0 for the
516 // number of parameters, stack slots, or context slots.
517 ScopeInfo<PreallocatedStorage> info(code);
518
519 // Print the parameters.
520 int parameters_count = ComputeParametersCount();
521 for (int i = 0; i < parameters_count; i++) {
522 accumulator->Add(",");
523 // If we have a name for the parameter we print it. Nameless
524 // parameters are either because we have more actual parameters
525 // than formal parameters or because we have no scope information.
526 if (i < info.number_of_parameters()) {
527 accumulator->PrintName(*info.parameter_name(i));
528 accumulator->Add("=");
529 }
530 accumulator->Add("%o", GetParameter(i));
531 }
532
533 accumulator->Add(")");
534 if (mode == OVERVIEW) {
535 accumulator->Add("\n");
536 return;
537 }
538 accumulator->Add(" {\n");
539
540 // Compute the number of locals and expression stack elements.
541 int stack_locals_count = info.number_of_stack_slots();
542 int heap_locals_count = info.number_of_context_slots();
543 int expressions_count = ComputeExpressionsCount();
544
545 // Print stack-allocated local variables.
546 if (stack_locals_count > 0) {
547 accumulator->Add(" // stack-allocated locals\n");
548 }
549 for (int i = 0; i < stack_locals_count; i++) {
550 accumulator->Add(" var ");
551 accumulator->PrintName(*info.stack_slot_name(i));
552 accumulator->Add(" = ");
553 if (i < expressions_count) {
554 accumulator->Add("%o", GetExpression(i));
555 } else {
556 accumulator->Add("// no expression found - inconsistent frame?");
557 }
558 accumulator->Add("\n");
559 }
560
561 // Try to get hold of the context of this frame.
562 Context* context = NULL;
563 if (this->context() != NULL && this->context()->IsContext()) {
564 context = Context::cast(this->context());
565 }
566
567 // Print heap-allocated local variables.
568 if (heap_locals_count > Context::MIN_CONTEXT_SLOTS) {
569 accumulator->Add(" // heap-allocated locals\n");
570 }
571 for (int i = Context::MIN_CONTEXT_SLOTS; i < heap_locals_count; i++) {
572 accumulator->Add(" var ");
573 accumulator->PrintName(*info.context_slot_name(i));
574 accumulator->Add(" = ");
575 if (context != NULL) {
576 if (i < context->length()) {
577 accumulator->Add("%o", context->get(i));
578 } else {
579 accumulator->Add(
580 "// warning: missing context slot - inconsistent frame?");
581 }
582 } else {
583 accumulator->Add("// warning: no context found - inconsistent frame?");
584 }
585 accumulator->Add("\n");
586 }
587
588 // Print the expression stack.
kasper.lund7276f142008-07-30 08:49:36 +0000589 int expressions_start = stack_locals_count;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000590 if (expressions_start < expressions_count) {
591 accumulator->Add(" // expression stack (top to bottom)\n");
592 }
593 for (int i = expressions_count - 1; i >= expressions_start; i--) {
594 if (IsExpressionInsideHandler(i)) continue;
595 accumulator->Add(" [%02d] : %o\n", i, GetExpression(i));
596 }
597
598 // Print details about the function.
599 if (FLAG_max_stack_trace_source_length != 0 && code != NULL) {
600 SharedFunctionInfo* shared = JSFunction::cast(function)->shared();
601 accumulator->Add("--------- s o u r c e c o d e ---------\n");
602 shared->SourceCodePrint(accumulator, FLAG_max_stack_trace_source_length);
603 accumulator->Add("\n-----------------------------------------\n");
604 }
605
606 accumulator->Add("}\n\n");
607}
608
609
610void ArgumentsAdaptorFrame::Print(StringStream* accumulator,
611 PrintMode mode,
612 int index) const {
613 int actual = ComputeParametersCount();
614 int expected = -1;
615 Object* function = this->function();
616 if (function->IsJSFunction()) {
617 expected = JSFunction::cast(function)->shared()->formal_parameter_count();
618 }
619
620 PrintIndex(accumulator, mode, index);
621 accumulator->Add("arguments adaptor frame: %d->%d", actual, expected);
622 if (mode == OVERVIEW) {
623 accumulator->Add("\n");
624 return;
625 }
626 accumulator->Add(" {\n");
627
628 // Print actual arguments.
629 if (actual > 0) accumulator->Add(" // actual arguments\n");
630 for (int i = 0; i < actual; i++) {
631 accumulator->Add(" [%02d] : %o", i, GetParameter(i));
632 if (expected != -1 && i >= expected) {
633 accumulator->Add(" // not passed to callee");
634 }
635 accumulator->Add("\n");
636 }
637
638 accumulator->Add("}\n\n");
639}
640
641
642void EntryFrame::Iterate(ObjectVisitor* v) const {
643 StackHandlerIterator it(this, top_handler());
644 ASSERT(!it.done());
645 StackHandler* handler = it.handler();
646 ASSERT(handler->is_entry());
647 handler->Iterate(v);
648 // Make sure that there's the entry frame does not contain more than
649 // one stack handler.
650 if (kDebug) {
651 it.Advance();
652 ASSERT(it.done());
653 }
654}
655
656
657void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
658 const int offset = StandardFrameConstants::kContextOffset;
659 Object** base = &Memory::Object_at(sp());
660 Object** limit = &Memory::Object_at(fp() + offset) + 1;
661 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
662 StackHandler* handler = it.handler();
663 // Traverse pointers down to - but not including - the next
664 // handler in the handler chain. Update the base to skip the
665 // handler and allow the handler to traverse its own pointers.
666 const Address address = handler->address();
667 v->VisitPointers(base, reinterpret_cast<Object**>(address));
668 base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize);
669 // Traverse the pointers in the handler itself.
670 handler->Iterate(v);
671 }
672 v->VisitPointers(base, limit);
673}
674
675
676void JavaScriptFrame::Iterate(ObjectVisitor* v) const {
677 IterateExpressions(v);
678
679 // Traverse callee-saved registers, receiver, and parameters.
680 const int kBaseOffset = JavaScriptFrameConstants::kSavedRegistersOffset;
681 const int kLimitOffset = JavaScriptFrameConstants::kReceiverOffset;
682 Object** base = &Memory::Object_at(fp() + kBaseOffset);
683 Object** limit = &Memory::Object_at(pp() + kLimitOffset) + 1;
684 v->VisitPointers(base, limit);
685}
686
687
688void InternalFrame::Iterate(ObjectVisitor* v) const {
689 // Internal frames only have object pointers on the expression stack
690 // as they never have any arguments.
691 IterateExpressions(v);
692}
693
694
695// -------------------------------------------------------------------------
696
697
698JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) {
699 ASSERT(n >= 0);
700 for (int i = 0; i <= n; i++) {
701 while (!iterator_.frame()->is_java_script()) iterator_.Advance();
702 if (i == n) return JavaScriptFrame::cast(iterator_.frame());
703 iterator_.Advance();
704 }
705 UNREACHABLE();
706 return NULL;
707}
708
709
710// -------------------------------------------------------------------------
711
712
713int NumRegs(RegList reglist) {
714 int n = 0;
715 while (reglist != 0) {
716 n++;
717 reglist &= reglist - 1; // clear one bit
718 }
719 return n;
720}
721
722
723int JSCallerSavedCode(int n) {
724 static int reg_code[kNumJSCallerSaved];
725 static bool initialized = false;
726 if (!initialized) {
727 initialized = true;
728 int i = 0;
729 for (int r = 0; r < kNumRegs; r++)
730 if ((kJSCallerSaved & (1 << r)) != 0)
731 reg_code[i++] = r;
732
733 ASSERT(i == kNumJSCallerSaved);
734 }
735 ASSERT(0 <= n && n < kNumJSCallerSaved);
736 return reg_code[n];
737}
738
739
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000740} } // namespace v8::internal