blob: 7f28ff175a080647f8c0ba1ec57c9061077e4596 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
Ben Murdochb0fe1622011-05-05 13:52:32 +010030#include "ast.h"
31#include "deoptimizer.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000032#include "frames-inl.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010033#include "full-codegen.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000034#include "mark-compact.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010035#include "safepoint-table.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000036#include "scopeinfo.h"
37#include "string-stream.h"
38#include "top.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000039
40namespace v8 {
41namespace internal {
42
Kristian Monsen80d68ea2010-09-08 11:05:35 +010043PcToCodeCache::PcToCodeCacheEntry
44 PcToCodeCache::cache_[PcToCodeCache::kPcToCodeCacheSize];
45
46int SafeStackFrameIterator::active_count_ = 0;
47
Steve Blocka7e24c12009-10-30 11:49:00 +000048// Iterator that supports traversing the stack handlers of a
49// particular frame. Needs to know the top of the handler chain.
50class StackHandlerIterator BASE_EMBEDDED {
51 public:
52 StackHandlerIterator(const StackFrame* frame, StackHandler* handler)
53 : limit_(frame->fp()), handler_(handler) {
54 // Make sure the handler has already been unwound to this frame.
55 ASSERT(frame->sp() <= handler->address());
56 }
57
58 StackHandler* handler() const { return handler_; }
59
60 bool done() {
61 return handler_ == NULL || handler_->address() > limit_;
62 }
63 void Advance() {
64 ASSERT(!done());
65 handler_ = handler_->next();
66 }
67
68 private:
69 const Address limit_;
70 StackHandler* handler_;
71};
72
73
74// -------------------------------------------------------------------------
75
76
77#define INITIALIZE_SINGLETON(type, field) field##_(this),
78StackFrameIterator::StackFrameIterator()
79 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
80 frame_(NULL), handler_(NULL), thread_(Top::GetCurrentThread()),
81 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
82 Reset();
83}
84StackFrameIterator::StackFrameIterator(ThreadLocalTop* t)
85 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
86 frame_(NULL), handler_(NULL), thread_(t),
87 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
88 Reset();
89}
90StackFrameIterator::StackFrameIterator(bool use_top, Address fp, Address sp)
91 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
92 frame_(NULL), handler_(NULL),
93 thread_(use_top ? Top::GetCurrentThread() : NULL),
94 fp_(use_top ? NULL : fp), sp_(sp),
95 advance_(use_top ? &StackFrameIterator::AdvanceWithHandler :
96 &StackFrameIterator::AdvanceWithoutHandler) {
97 if (use_top || fp != NULL) {
98 Reset();
99 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000100}
101
102#undef INITIALIZE_SINGLETON
103
104
105void StackFrameIterator::AdvanceWithHandler() {
106 ASSERT(!done());
107 // Compute the state of the calling frame before restoring
108 // callee-saved registers and unwinding handlers. This allows the
109 // frame code that computes the caller state to access the top
110 // handler and the value of any callee-saved register if needed.
111 StackFrame::State state;
112 StackFrame::Type type = frame_->GetCallerState(&state);
113
114 // Unwind handlers corresponding to the current frame.
115 StackHandlerIterator it(frame_, handler_);
116 while (!it.done()) it.Advance();
117 handler_ = it.handler();
118
119 // Advance to the calling frame.
120 frame_ = SingletonFor(type, &state);
121
122 // When we're done iterating over the stack frames, the handler
123 // chain must have been completely unwound.
124 ASSERT(!done() || handler_ == NULL);
125}
126
127
128void StackFrameIterator::AdvanceWithoutHandler() {
129 // A simpler version of Advance which doesn't care about handler.
130 ASSERT(!done());
131 StackFrame::State state;
132 StackFrame::Type type = frame_->GetCallerState(&state);
133 frame_ = SingletonFor(type, &state);
134}
135
136
137void StackFrameIterator::Reset() {
138 StackFrame::State state;
139 StackFrame::Type type;
140 if (thread_ != NULL) {
141 type = ExitFrame::GetStateForFramePointer(Top::c_entry_fp(thread_), &state);
142 handler_ = StackHandler::FromAddress(Top::handler(thread_));
143 } else {
144 ASSERT(fp_ != NULL);
145 state.fp = fp_;
146 state.sp = sp_;
147 state.pc_address =
148 reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp_));
149 type = StackFrame::ComputeType(&state);
Steve Blocka7e24c12009-10-30 11:49:00 +0000150 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100151 if (SingletonFor(type) == NULL) return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000152 frame_ = SingletonFor(type, &state);
153}
154
155
156StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type,
157 StackFrame::State* state) {
158 if (type == StackFrame::NONE) return NULL;
159 StackFrame* result = SingletonFor(type);
160 ASSERT(result != NULL);
161 result->state_ = *state;
162 return result;
163}
164
165
166StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type) {
167#define FRAME_TYPE_CASE(type, field) \
168 case StackFrame::type: result = &field##_; break;
169
170 StackFrame* result = NULL;
171 switch (type) {
172 case StackFrame::NONE: return NULL;
173 STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
174 default: break;
175 }
176 return result;
177
178#undef FRAME_TYPE_CASE
179}
180
181
182// -------------------------------------------------------------------------
183
184
185StackTraceFrameIterator::StackTraceFrameIterator() {
Leon Clarke4515c472010-02-03 11:58:03 +0000186 if (!done() && !IsValidFrame()) Advance();
Steve Blocka7e24c12009-10-30 11:49:00 +0000187}
188
189
190void StackTraceFrameIterator::Advance() {
191 while (true) {
192 JavaScriptFrameIterator::Advance();
193 if (done()) return;
Leon Clarke4515c472010-02-03 11:58:03 +0000194 if (IsValidFrame()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000195 }
196}
197
Leon Clarke4515c472010-02-03 11:58:03 +0000198bool StackTraceFrameIterator::IsValidFrame() {
199 if (!frame()->function()->IsJSFunction()) return false;
200 Object* script = JSFunction::cast(frame()->function())->shared()->script();
201 // Don't show functions from native scripts to user.
202 return (script->IsScript() &&
203 Script::TYPE_NATIVE != Script::cast(script)->type()->value());
204}
205
Steve Blocka7e24c12009-10-30 11:49:00 +0000206
207// -------------------------------------------------------------------------
208
209
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100210bool SafeStackFrameIterator::ExitFrameValidator::IsValidFP(Address fp) {
211 if (!validator_.IsValid(fp)) return false;
212 Address sp = ExitFrame::ComputeStackPointer(fp);
213 if (!validator_.IsValid(sp)) return false;
214 StackFrame::State state;
215 ExitFrame::FillState(fp, sp, &state);
216 if (!validator_.IsValid(reinterpret_cast<Address>(state.pc_address))) {
217 return false;
218 }
219 return *state.pc_address != NULL;
220}
221
222
Steve Blocka7e24c12009-10-30 11:49:00 +0000223SafeStackFrameIterator::SafeStackFrameIterator(
224 Address fp, Address sp, Address low_bound, Address high_bound) :
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100225 maintainer_(),
226 stack_validator_(low_bound, high_bound),
227 is_valid_top_(IsValidTop(low_bound, high_bound)),
Steve Blocka7e24c12009-10-30 11:49:00 +0000228 is_valid_fp_(IsWithinBounds(low_bound, high_bound, fp)),
229 is_working_iterator_(is_valid_top_ || is_valid_fp_),
230 iteration_done_(!is_working_iterator_),
231 iterator_(is_valid_top_, is_valid_fp_ ? fp : NULL, sp) {
232}
233
234
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100235bool SafeStackFrameIterator::IsValidTop(Address low_bound, Address high_bound) {
236 Address fp = Top::c_entry_fp(Top::GetCurrentThread());
237 ExitFrameValidator validator(low_bound, high_bound);
238 if (!validator.IsValidFP(fp)) return false;
239 return Top::handler(Top::GetCurrentThread()) != NULL;
240}
241
242
Steve Blocka7e24c12009-10-30 11:49:00 +0000243void SafeStackFrameIterator::Advance() {
244 ASSERT(is_working_iterator_);
245 ASSERT(!done());
246 StackFrame* last_frame = iterator_.frame();
247 Address last_sp = last_frame->sp(), last_fp = last_frame->fp();
248 // Before advancing to the next stack frame, perform pointer validity tests
249 iteration_done_ = !IsValidFrame(last_frame) ||
250 !CanIterateHandles(last_frame, iterator_.handler()) ||
251 !IsValidCaller(last_frame);
252 if (iteration_done_) return;
253
254 iterator_.Advance();
255 if (iterator_.done()) return;
256 // Check that we have actually moved to the previous frame in the stack
257 StackFrame* prev_frame = iterator_.frame();
258 iteration_done_ = prev_frame->sp() < last_sp || prev_frame->fp() < last_fp;
259}
260
261
262bool SafeStackFrameIterator::CanIterateHandles(StackFrame* frame,
263 StackHandler* handler) {
264 // If StackIterator iterates over StackHandles, verify that
265 // StackHandlerIterator can be instantiated (see StackHandlerIterator
266 // constructor.)
267 return !is_valid_top_ || (frame->sp() <= handler->address());
268}
269
270
271bool SafeStackFrameIterator::IsValidFrame(StackFrame* frame) const {
272 return IsValidStackAddress(frame->sp()) && IsValidStackAddress(frame->fp());
273}
274
275
276bool SafeStackFrameIterator::IsValidCaller(StackFrame* frame) {
277 StackFrame::State state;
278 if (frame->is_entry() || frame->is_entry_construct()) {
279 // See EntryFrame::GetCallerState. It computes the caller FP address
280 // and calls ExitFrame::GetStateForFramePointer on it. We need to be
281 // sure that caller FP address is valid.
282 Address caller_fp = Memory::Address_at(
283 frame->fp() + EntryFrameConstants::kCallerFPOffset);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100284 ExitFrameValidator validator(stack_validator_);
285 if (!validator.IsValidFP(caller_fp)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000286 } else if (frame->is_arguments_adaptor()) {
287 // See ArgumentsAdaptorFrame::GetCallerStackPointer. It assumes that
288 // the number of arguments is stored on stack as Smi. We need to check
289 // that it really an Smi.
290 Object* number_of_args = reinterpret_cast<ArgumentsAdaptorFrame*>(frame)->
291 GetExpression(0);
292 if (!number_of_args->IsSmi()) {
293 return false;
294 }
295 }
296 frame->ComputeCallerState(&state);
297 return IsValidStackAddress(state.sp) && IsValidStackAddress(state.fp) &&
298 iterator_.SingletonFor(frame->GetCallerState(&state)) != NULL;
299}
300
301
302void SafeStackFrameIterator::Reset() {
303 if (is_working_iterator_) {
304 iterator_.Reset();
305 iteration_done_ = false;
306 }
307}
308
309
310// -------------------------------------------------------------------------
311
312
313#ifdef ENABLE_LOGGING_AND_PROFILING
314SafeStackTraceFrameIterator::SafeStackTraceFrameIterator(
315 Address fp, Address sp, Address low_bound, Address high_bound) :
316 SafeJavaScriptFrameIterator(fp, sp, low_bound, high_bound) {
317 if (!done() && !frame()->is_java_script()) Advance();
318}
319
320
321void SafeStackTraceFrameIterator::Advance() {
322 while (true) {
323 SafeJavaScriptFrameIterator::Advance();
324 if (done()) return;
325 if (frame()->is_java_script()) return;
326 }
327}
328#endif
329
330
Ben Murdochb0fe1622011-05-05 13:52:32 +0100331Code* StackFrame::GetSafepointData(Address pc,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100332 SafepointEntry* safepoint_entry,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100333 unsigned* stack_slots) {
334 PcToCodeCache::PcToCodeCacheEntry* entry = PcToCodeCache::GetCacheEntry(pc);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100335 SafepointEntry cached_safepoint_entry = entry->safepoint_entry;
336 if (!entry->safepoint_entry.is_valid()) {
337 entry->safepoint_entry = entry->code->GetSafepointEntry(pc);
338 ASSERT(entry->safepoint_entry.is_valid());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100339 } else {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100340 ASSERT(entry->safepoint_entry.Equals(entry->code->GetSafepointEntry(pc)));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100341 }
342
343 // Fill in the results and return the code.
344 Code* code = entry->code;
Ben Murdochb8e0da22011-05-16 14:20:40 +0100345 *safepoint_entry = entry->safepoint_entry;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100346 *stack_slots = code->stack_slots();
347 return code;
348}
349
350
Steve Blocka7e24c12009-10-30 11:49:00 +0000351bool StackFrame::HasHandler() const {
352 StackHandlerIterator it(this, top_handler());
353 return !it.done();
354}
355
Ben Murdochb0fe1622011-05-05 13:52:32 +0100356
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100357void StackFrame::IteratePc(ObjectVisitor* v,
358 Address* pc_address,
359 Code* holder) {
360 Address pc = *pc_address;
361 ASSERT(holder->contains(pc));
362 unsigned pc_offset = static_cast<unsigned>(pc - holder->instruction_start());
363 Object* code = holder;
364 v->VisitPointer(&code);
365 if (code != holder) {
366 holder = reinterpret_cast<Code*>(code);
367 pc = holder->instruction_start() + pc_offset;
368 *pc_address = pc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000369 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000370}
371
372
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100373StackFrame::Type StackFrame::ComputeType(State* state) {
374 ASSERT(state->fp != NULL);
375 if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
376 return ARGUMENTS_ADAPTOR;
Steve Blocka7e24c12009-10-30 11:49:00 +0000377 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100378 // The marker and function offsets overlap. If the marker isn't a
379 // smi then the frame is a JavaScript frame -- and the marker is
380 // really the function.
381 const int offset = StandardFrameConstants::kMarkerOffset;
382 Object* marker = Memory::Object_at(state->fp + offset);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100383 if (!marker->IsSmi()) {
384 // If we're using a "safe" stack iterator, we treat optimized
385 // frames as normal JavaScript frames to avoid having to look
386 // into the heap to determine the state. This is safe as long
387 // as nobody tries to GC...
388 if (SafeStackFrameIterator::is_active()) return JAVA_SCRIPT;
389 Code::Kind kind = GetContainingCode(*(state->pc_address))->kind();
390 ASSERT(kind == Code::FUNCTION || kind == Code::OPTIMIZED_FUNCTION);
391 return (kind == Code::OPTIMIZED_FUNCTION) ? OPTIMIZED : JAVA_SCRIPT;
392 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100393 return static_cast<StackFrame::Type>(Smi::cast(marker)->value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000394}
395
396
Steve Blocka7e24c12009-10-30 11:49:00 +0000397
398StackFrame::Type StackFrame::GetCallerState(State* state) const {
399 ComputeCallerState(state);
400 return ComputeType(state);
401}
402
403
Iain Merrick75681382010-08-19 15:07:18 +0100404Code* EntryFrame::unchecked_code() const {
405 return Heap::raw_unchecked_js_entry_code();
Steve Blocka7e24c12009-10-30 11:49:00 +0000406}
407
408
409void EntryFrame::ComputeCallerState(State* state) const {
410 GetCallerState(state);
411}
412
413
Steve Block6ded16b2010-05-10 14:33:55 +0100414void EntryFrame::SetCallerFp(Address caller_fp) {
415 const int offset = EntryFrameConstants::kCallerFPOffset;
416 Memory::Address_at(this->fp() + offset) = caller_fp;
417}
418
419
Steve Blocka7e24c12009-10-30 11:49:00 +0000420StackFrame::Type EntryFrame::GetCallerState(State* state) const {
421 const int offset = EntryFrameConstants::kCallerFPOffset;
422 Address fp = Memory::Address_at(this->fp() + offset);
423 return ExitFrame::GetStateForFramePointer(fp, state);
424}
425
426
Iain Merrick75681382010-08-19 15:07:18 +0100427Code* EntryConstructFrame::unchecked_code() const {
428 return Heap::raw_unchecked_js_construct_entry_code();
Steve Blocka7e24c12009-10-30 11:49:00 +0000429}
430
431
Steve Blockd0582a62009-12-15 09:54:21 +0000432Object*& ExitFrame::code_slot() const {
433 const int offset = ExitFrameConstants::kCodeOffset;
434 return Memory::Object_at(fp() + offset);
435}
436
437
Iain Merrick75681382010-08-19 15:07:18 +0100438Code* ExitFrame::unchecked_code() const {
439 return reinterpret_cast<Code*>(code_slot());
Steve Blocka7e24c12009-10-30 11:49:00 +0000440}
441
442
443void ExitFrame::ComputeCallerState(State* state) const {
444 // Setup the caller state.
445 state->sp = caller_sp();
446 state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset);
447 state->pc_address
448 = reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset);
449}
450
451
Steve Block6ded16b2010-05-10 14:33:55 +0100452void ExitFrame::SetCallerFp(Address caller_fp) {
453 Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset) = caller_fp;
454}
455
456
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100457void ExitFrame::Iterate(ObjectVisitor* v) const {
458 // The arguments are traversed as part of the expression stack of
459 // the calling frame.
460 IteratePc(v, pc_address(), code());
461 v->VisitPointer(&code_slot());
462}
463
464
Steve Blocka7e24c12009-10-30 11:49:00 +0000465Address ExitFrame::GetCallerStackPointer() const {
466 return fp() + ExitFrameConstants::kCallerSPDisplacement;
467}
468
469
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100470StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
471 if (fp == 0) return NONE;
472 Address sp = ComputeStackPointer(fp);
473 FillState(fp, sp, state);
474 ASSERT(*state->pc_address != NULL);
475 return EXIT;
476}
477
478
479void ExitFrame::FillState(Address fp, Address sp, State* state) {
480 state->sp = sp;
481 state->fp = fp;
482 state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize);
483}
484
485
Steve Blocka7e24c12009-10-30 11:49:00 +0000486Address StandardFrame::GetExpressionAddress(int n) const {
487 const int offset = StandardFrameConstants::kExpressionsOffset;
488 return fp() + offset - n * kPointerSize;
489}
490
491
492int StandardFrame::ComputeExpressionsCount() const {
493 const int offset =
494 StandardFrameConstants::kExpressionsOffset + kPointerSize;
495 Address base = fp() + offset;
496 Address limit = sp();
497 ASSERT(base >= limit); // stack grows downwards
498 // Include register-allocated locals in number of expressions.
Steve Blockd0582a62009-12-15 09:54:21 +0000499 return static_cast<int>((base - limit) / kPointerSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000500}
501
502
503void StandardFrame::ComputeCallerState(State* state) const {
504 state->sp = caller_sp();
505 state->fp = caller_fp();
506 state->pc_address = reinterpret_cast<Address*>(ComputePCAddress(fp()));
507}
508
509
Steve Block6ded16b2010-05-10 14:33:55 +0100510void StandardFrame::SetCallerFp(Address caller_fp) {
511 Memory::Address_at(fp() + StandardFrameConstants::kCallerFPOffset) =
512 caller_fp;
513}
514
515
Steve Blocka7e24c12009-10-30 11:49:00 +0000516bool StandardFrame::IsExpressionInsideHandler(int n) const {
517 Address address = GetExpressionAddress(n);
518 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
519 if (it.handler()->includes(address)) return true;
520 }
521 return false;
522}
523
524
Ben Murdochb0fe1622011-05-05 13:52:32 +0100525void OptimizedFrame::Iterate(ObjectVisitor* v) const {
526#ifdef DEBUG
527 // Make sure that optimized frames do not contain any stack handlers.
528 StackHandlerIterator it(this, top_handler());
529 ASSERT(it.done());
530#endif
531
532 // Make sure that we're not doing "safe" stack frame iteration. We cannot
533 // possibly find pointers in optimized frames in that state.
534 ASSERT(!SafeStackFrameIterator::is_active());
535
536 // Compute the safepoint information.
537 unsigned stack_slots = 0;
Ben Murdochb8e0da22011-05-16 14:20:40 +0100538 SafepointEntry safepoint_entry;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100539 Code* code = StackFrame::GetSafepointData(
540 pc(), &safepoint_entry, &stack_slots);
541 unsigned slot_space = stack_slots * kPointerSize;
542
543 // Visit the outgoing parameters. This is usually dealt with by the
544 // callee, but while GC'ing we artificially lower the number of
545 // arguments to zero and let the caller deal with it.
546 Object** parameters_base = &Memory::Object_at(sp());
547 Object** parameters_limit = &Memory::Object_at(
548 fp() + JavaScriptFrameConstants::kFunctionOffset - slot_space);
549
Ben Murdochb8e0da22011-05-16 14:20:40 +0100550 // Visit the parameters that may be on top of the saved registers.
551 if (safepoint_entry.argument_count() > 0) {
552 v->VisitPointers(parameters_base,
553 parameters_base + safepoint_entry.argument_count());
554 parameters_base += safepoint_entry.argument_count();
555 }
556
557 // Skip saved double registers.
558 if (safepoint_entry.has_doubles()) {
559 parameters_base += DoubleRegister::kNumAllocatableRegisters *
560 kDoubleSize / kPointerSize;
561 }
562
Ben Murdochb0fe1622011-05-05 13:52:32 +0100563 // Visit the registers that contain pointers if any.
Ben Murdochb8e0da22011-05-16 14:20:40 +0100564 if (safepoint_entry.HasRegisters()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100565 for (int i = kNumSafepointRegisters - 1; i >=0; i--) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100566 if (safepoint_entry.HasRegisterAt(i)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100567 int reg_stack_index = MacroAssembler::SafepointRegisterStackIndex(i);
568 v->VisitPointer(parameters_base + reg_stack_index);
569 }
570 }
571 // Skip the words containing the register values.
572 parameters_base += kNumSafepointRegisters;
573 }
574
575 // We're done dealing with the register bits.
Ben Murdochb8e0da22011-05-16 14:20:40 +0100576 uint8_t* safepoint_bits = safepoint_entry.bits();
577 safepoint_bits += kNumSafepointRegisters >> kBitsPerByteLog2;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100578
579 // Visit the rest of the parameters.
580 v->VisitPointers(parameters_base, parameters_limit);
581
582 // Visit pointer spill slots and locals.
583 for (unsigned index = 0; index < stack_slots; index++) {
584 int byte_index = index >> kBitsPerByteLog2;
585 int bit_index = index & (kBitsPerByte - 1);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100586 if ((safepoint_bits[byte_index] & (1U << bit_index)) != 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100587 v->VisitPointer(parameters_limit + index);
588 }
589 }
590
591 // Visit the context and the function.
592 Object** fixed_base = &Memory::Object_at(
593 fp() + JavaScriptFrameConstants::kFunctionOffset);
594 Object** fixed_limit = &Memory::Object_at(fp());
595 v->VisitPointers(fixed_base, fixed_limit);
596
597 // Visit the return address in the callee and incoming arguments.
598 IteratePc(v, pc_address(), code);
599 IterateArguments(v);
600}
601
602
Steve Blocka7e24c12009-10-30 11:49:00 +0000603Object* JavaScriptFrame::GetParameter(int index) const {
604 ASSERT(index >= 0 && index < ComputeParametersCount());
605 const int offset = JavaScriptFrameConstants::kParam0Offset;
606 return Memory::Object_at(caller_sp() + offset - (index * kPointerSize));
607}
608
609
610int JavaScriptFrame::ComputeParametersCount() const {
611 Address base = caller_sp() + JavaScriptFrameConstants::kReceiverOffset;
612 Address limit = fp() + JavaScriptFrameConstants::kSavedRegistersOffset;
Steve Blockd0582a62009-12-15 09:54:21 +0000613 return static_cast<int>((base - limit) / kPointerSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000614}
615
616
617bool JavaScriptFrame::IsConstructor() const {
618 Address fp = caller_fp();
619 if (has_adapted_arguments()) {
620 // Skip the arguments adaptor frame and look at the real caller.
621 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
622 }
623 return IsConstructFrame(fp);
624}
625
626
Iain Merrick75681382010-08-19 15:07:18 +0100627Code* JavaScriptFrame::unchecked_code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000628 JSFunction* function = JSFunction::cast(this->function());
Iain Merrick75681382010-08-19 15:07:18 +0100629 return function->unchecked_code();
Steve Blocka7e24c12009-10-30 11:49:00 +0000630}
631
632
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100633int JavaScriptFrame::GetProvidedParametersCount() const {
634 return ComputeParametersCount();
635}
636
637
638Address JavaScriptFrame::GetCallerStackPointer() const {
639 int arguments;
640 if (Heap::gc_state() != Heap::NOT_IN_GC ||
641 SafeStackFrameIterator::is_active()) {
642 // If the we are currently iterating the safe stack the
643 // arguments for frames are traversed as if they were
644 // expression stack elements of the calling frame. The reason for
645 // this rather strange decision is that we cannot access the
646 // function during mark-compact GCs when objects may have been marked.
647 // In fact accessing heap objects (like function->shared() below)
648 // at all during GC is problematic.
649 arguments = 0;
650 } else {
651 // Compute the number of arguments by getting the number of formal
652 // parameters of the function. We must remember to take the
653 // receiver into account (+1).
654 JSFunction* function = JSFunction::cast(this->function());
655 arguments = function->shared()->formal_parameter_count() + 1;
656 }
657 const int offset = StandardFrameConstants::kCallerSPOffset;
658 return fp() + offset + (arguments * kPointerSize);
659}
660
661
Ben Murdochb0fe1622011-05-05 13:52:32 +0100662void JavaScriptFrame::GetFunctions(List<JSFunction*>* functions) {
663 ASSERT(functions->length() == 0);
664 functions->Add(JSFunction::cast(function()));
665}
666
667
668void JavaScriptFrame::Summarize(List<FrameSummary>* functions) {
669 ASSERT(functions->length() == 0);
670 Code* code_pointer = code();
671 int offset = static_cast<int>(pc() - code_pointer->address());
672 FrameSummary summary(receiver(),
673 JSFunction::cast(function()),
674 code_pointer,
675 offset,
676 IsConstructor());
677 functions->Add(summary);
678}
679
680
681void FrameSummary::Print() {
682 PrintF("receiver: ");
683 receiver_->ShortPrint();
684 PrintF("\nfunction: ");
685 function_->shared()->DebugName()->ShortPrint();
686 PrintF("\ncode: ");
687 code_->ShortPrint();
688 if (code_->kind() == Code::FUNCTION) PrintF(" NON-OPT");
689 if (code_->kind() == Code::OPTIMIZED_FUNCTION) PrintF(" OPT");
690 PrintF("\npc: %d\n", offset_);
691}
692
693
694void OptimizedFrame::Summarize(List<FrameSummary>* frames) {
695 ASSERT(frames->length() == 0);
696 ASSERT(is_optimized());
697
698 int deopt_index = AstNode::kNoNumber;
699 DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
700
701 // BUG(3243555): Since we don't have a lazy-deopt registered at
702 // throw-statements, we can't use the translation at the call-site of
703 // throw. An entry with no deoptimization index indicates a call-site
704 // without a lazy-deopt. As a consequence we are not allowed to inline
705 // functions containing throw.
706 if (deopt_index == Safepoint::kNoDeoptimizationIndex) {
707 JavaScriptFrame::Summarize(frames);
708 return;
709 }
710
711 TranslationIterator it(data->TranslationByteArray(),
712 data->TranslationIndex(deopt_index)->value());
713 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
714 ASSERT(opcode == Translation::BEGIN);
715 int frame_count = it.Next();
716
717 // We create the summary in reverse order because the frames
718 // in the deoptimization translation are ordered bottom-to-top.
719 int i = frame_count;
720 while (i > 0) {
721 opcode = static_cast<Translation::Opcode>(it.Next());
722 if (opcode == Translation::FRAME) {
723 // We don't inline constructor calls, so only the first, outermost
724 // frame can be a constructor frame in case of inlining.
725 bool is_constructor = (i == frame_count) && IsConstructor();
726
727 i--;
728 int ast_id = it.Next();
729 int function_id = it.Next();
730 it.Next(); // Skip height.
731 JSFunction* function =
732 JSFunction::cast(data->LiteralArray()->get(function_id));
733
734 // The translation commands are ordered and the receiver is always
735 // at the first position. Since we are always at a call when we need
736 // to construct a stack trace, the receiver is always in a stack slot.
737 opcode = static_cast<Translation::Opcode>(it.Next());
738 ASSERT(opcode == Translation::STACK_SLOT);
739 int input_slot_index = it.Next();
740
741 // Get the correct receiver in the optimized frame.
742 Object* receiver = NULL;
743 // Positive index means the value is spilled to the locals area. Negative
744 // means it is stored in the incoming parameter area.
745 if (input_slot_index >= 0) {
746 receiver = GetExpression(input_slot_index);
747 } else {
748 // Index -1 overlaps with last parameter, -n with the first parameter,
749 // (-n - 1) with the receiver with n being the number of parameters
750 // of the outermost, optimized frame.
751 int parameter_count = ComputeParametersCount();
752 int parameter_index = input_slot_index + parameter_count;
753 receiver = (parameter_index == -1)
754 ? this->receiver()
755 : this->GetParameter(parameter_index);
756 }
757
758 Code* code = function->shared()->code();
759 DeoptimizationOutputData* output_data =
760 DeoptimizationOutputData::cast(code->deoptimization_data());
761 unsigned entry = Deoptimizer::GetOutputInfo(output_data,
762 ast_id,
763 function->shared());
764 unsigned pc_offset =
765 FullCodeGenerator::PcField::decode(entry) + Code::kHeaderSize;
766 ASSERT(pc_offset > 0);
767
768 FrameSummary summary(receiver, function, code, pc_offset, is_constructor);
769 frames->Add(summary);
770 } else {
771 // Skip over operands to advance to the next opcode.
772 it.Skip(Translation::NumberOfOperandsFor(opcode));
773 }
774 }
775}
776
777
778DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData(
779 int* deopt_index) {
780 ASSERT(is_optimized());
781
782 JSFunction* opt_function = JSFunction::cast(function());
783 Code* code = opt_function->code();
784
785 // The code object may have been replaced by lazy deoptimization. Fall
786 // back to a slow search in this case to find the original optimized
787 // code object.
788 if (!code->contains(pc())) {
789 code = PcToCodeCache::GcSafeFindCodeForPc(pc());
790 }
791 ASSERT(code != NULL);
792 ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
793
Ben Murdochb8e0da22011-05-16 14:20:40 +0100794 SafepointEntry safepoint_entry = code->GetSafepointEntry(pc());
795 *deopt_index = safepoint_entry.deoptimization_index();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100796 ASSERT(*deopt_index != AstNode::kNoNumber);
797
798 return DeoptimizationInputData::cast(code->deoptimization_data());
799}
800
801
802void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) {
803 ASSERT(functions->length() == 0);
804 ASSERT(is_optimized());
805
806 int deopt_index = AstNode::kNoNumber;
807 DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
808
809 TranslationIterator it(data->TranslationByteArray(),
810 data->TranslationIndex(deopt_index)->value());
811 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
812 ASSERT(opcode == Translation::BEGIN);
813 int frame_count = it.Next();
814
815 // We insert the frames in reverse order because the frames
816 // in the deoptimization translation are ordered bottom-to-top.
817 while (frame_count > 0) {
818 opcode = static_cast<Translation::Opcode>(it.Next());
819 if (opcode == Translation::FRAME) {
820 frame_count--;
821 it.Next(); // Skip ast id.
822 int function_id = it.Next();
823 it.Next(); // Skip height.
824 JSFunction* function =
825 JSFunction::cast(data->LiteralArray()->get(function_id));
826 functions->Add(function);
827 } else {
828 // Skip over operands to advance to the next opcode.
829 it.Skip(Translation::NumberOfOperandsFor(opcode));
830 }
831 }
832}
833
834
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100835Address ArgumentsAdaptorFrame::GetCallerStackPointer() const {
836 const int arguments = Smi::cast(GetExpression(0))->value();
837 const int offset = StandardFrameConstants::kCallerSPOffset;
838 return fp() + offset + (arguments + 1) * kPointerSize;
839}
840
841
842Address InternalFrame::GetCallerStackPointer() const {
843 // Internal frames have no arguments. The stack pointer of the
844 // caller is at a fixed offset from the frame pointer.
845 return fp() + StandardFrameConstants::kCallerSPOffset;
846}
847
848
Iain Merrick75681382010-08-19 15:07:18 +0100849Code* ArgumentsAdaptorFrame::unchecked_code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000850 return Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline);
851}
852
853
Iain Merrick75681382010-08-19 15:07:18 +0100854Code* InternalFrame::unchecked_code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000855 const int offset = InternalFrameConstants::kCodeOffset;
856 Object* code = Memory::Object_at(fp() + offset);
857 ASSERT(code != NULL);
Iain Merrick75681382010-08-19 15:07:18 +0100858 return reinterpret_cast<Code*>(code);
Steve Blocka7e24c12009-10-30 11:49:00 +0000859}
860
861
862void StackFrame::PrintIndex(StringStream* accumulator,
863 PrintMode mode,
864 int index) {
865 accumulator->Add((mode == OVERVIEW) ? "%5d: " : "[%d]: ", index);
866}
867
868
869void JavaScriptFrame::Print(StringStream* accumulator,
870 PrintMode mode,
871 int index) const {
872 HandleScope scope;
873 Object* receiver = this->receiver();
874 Object* function = this->function();
875
876 accumulator->PrintSecurityTokenIfChanged(function);
877 PrintIndex(accumulator, mode, index);
878 Code* code = NULL;
879 if (IsConstructor()) accumulator->Add("new ");
880 accumulator->PrintFunction(function, receiver, &code);
Steve Block6ded16b2010-05-10 14:33:55 +0100881
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100882 Handle<SerializedScopeInfo> scope_info(SerializedScopeInfo::Empty());
883
Steve Block6ded16b2010-05-10 14:33:55 +0100884 if (function->IsJSFunction()) {
885 Handle<SharedFunctionInfo> shared(JSFunction::cast(function)->shared());
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100886 scope_info = Handle<SerializedScopeInfo>(shared->scope_info());
Steve Block6ded16b2010-05-10 14:33:55 +0100887 Object* script_obj = shared->script();
888 if (script_obj->IsScript()) {
889 Handle<Script> script(Script::cast(script_obj));
890 accumulator->Add(" [");
891 accumulator->PrintName(script->name());
892
893 Address pc = this->pc();
894 if (code != NULL && code->kind() == Code::FUNCTION &&
Leon Clarkeac952652010-07-15 11:15:24 +0100895 pc >= code->instruction_start() && pc < code->instruction_end()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100896 int source_pos = code->SourcePosition(pc);
897 int line = GetScriptLineNumberSafe(script, source_pos) + 1;
898 accumulator->Add(":%d", line);
899 } else {
900 int function_start_pos = shared->start_position();
901 int line = GetScriptLineNumberSafe(script, function_start_pos) + 1;
902 accumulator->Add(":~%d", line);
903 }
904
905 accumulator->Add("] ");
906 }
907 }
908
Steve Blocka7e24c12009-10-30 11:49:00 +0000909 accumulator->Add("(this=%o", receiver);
910
911 // Get scope information for nicer output, if possible. If code is
912 // NULL, or doesn't contain scope info, info will return 0 for the
913 // number of parameters, stack slots, or context slots.
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100914 ScopeInfo<PreallocatedStorage> info(*scope_info);
Steve Blocka7e24c12009-10-30 11:49:00 +0000915
916 // Print the parameters.
917 int parameters_count = ComputeParametersCount();
918 for (int i = 0; i < parameters_count; i++) {
919 accumulator->Add(",");
920 // If we have a name for the parameter we print it. Nameless
921 // parameters are either because we have more actual parameters
922 // than formal parameters or because we have no scope information.
923 if (i < info.number_of_parameters()) {
924 accumulator->PrintName(*info.parameter_name(i));
925 accumulator->Add("=");
926 }
927 accumulator->Add("%o", GetParameter(i));
928 }
929
930 accumulator->Add(")");
931 if (mode == OVERVIEW) {
932 accumulator->Add("\n");
933 return;
934 }
935 accumulator->Add(" {\n");
936
937 // Compute the number of locals and expression stack elements.
938 int stack_locals_count = info.number_of_stack_slots();
939 int heap_locals_count = info.number_of_context_slots();
940 int expressions_count = ComputeExpressionsCount();
941
942 // Print stack-allocated local variables.
943 if (stack_locals_count > 0) {
944 accumulator->Add(" // stack-allocated locals\n");
945 }
946 for (int i = 0; i < stack_locals_count; i++) {
947 accumulator->Add(" var ");
948 accumulator->PrintName(*info.stack_slot_name(i));
949 accumulator->Add(" = ");
950 if (i < expressions_count) {
951 accumulator->Add("%o", GetExpression(i));
952 } else {
953 accumulator->Add("// no expression found - inconsistent frame?");
954 }
955 accumulator->Add("\n");
956 }
957
958 // Try to get hold of the context of this frame.
959 Context* context = NULL;
960 if (this->context() != NULL && this->context()->IsContext()) {
961 context = Context::cast(this->context());
962 }
963
964 // Print heap-allocated local variables.
965 if (heap_locals_count > Context::MIN_CONTEXT_SLOTS) {
966 accumulator->Add(" // heap-allocated locals\n");
967 }
968 for (int i = Context::MIN_CONTEXT_SLOTS; i < heap_locals_count; i++) {
969 accumulator->Add(" var ");
970 accumulator->PrintName(*info.context_slot_name(i));
971 accumulator->Add(" = ");
972 if (context != NULL) {
973 if (i < context->length()) {
974 accumulator->Add("%o", context->get(i));
975 } else {
976 accumulator->Add(
977 "// warning: missing context slot - inconsistent frame?");
978 }
979 } else {
980 accumulator->Add("// warning: no context found - inconsistent frame?");
981 }
982 accumulator->Add("\n");
983 }
984
985 // Print the expression stack.
986 int expressions_start = stack_locals_count;
987 if (expressions_start < expressions_count) {
988 accumulator->Add(" // expression stack (top to bottom)\n");
989 }
990 for (int i = expressions_count - 1; i >= expressions_start; i--) {
991 if (IsExpressionInsideHandler(i)) continue;
992 accumulator->Add(" [%02d] : %o\n", i, GetExpression(i));
993 }
994
995 // Print details about the function.
996 if (FLAG_max_stack_trace_source_length != 0 && code != NULL) {
997 SharedFunctionInfo* shared = JSFunction::cast(function)->shared();
998 accumulator->Add("--------- s o u r c e c o d e ---------\n");
999 shared->SourceCodePrint(accumulator, FLAG_max_stack_trace_source_length);
1000 accumulator->Add("\n-----------------------------------------\n");
1001 }
1002
1003 accumulator->Add("}\n\n");
1004}
1005
1006
1007void ArgumentsAdaptorFrame::Print(StringStream* accumulator,
1008 PrintMode mode,
1009 int index) const {
1010 int actual = ComputeParametersCount();
1011 int expected = -1;
1012 Object* function = this->function();
1013 if (function->IsJSFunction()) {
1014 expected = JSFunction::cast(function)->shared()->formal_parameter_count();
1015 }
1016
1017 PrintIndex(accumulator, mode, index);
1018 accumulator->Add("arguments adaptor frame: %d->%d", actual, expected);
1019 if (mode == OVERVIEW) {
1020 accumulator->Add("\n");
1021 return;
1022 }
1023 accumulator->Add(" {\n");
1024
1025 // Print actual arguments.
1026 if (actual > 0) accumulator->Add(" // actual arguments\n");
1027 for (int i = 0; i < actual; i++) {
1028 accumulator->Add(" [%02d] : %o", i, GetParameter(i));
1029 if (expected != -1 && i >= expected) {
1030 accumulator->Add(" // not passed to callee");
1031 }
1032 accumulator->Add("\n");
1033 }
1034
1035 accumulator->Add("}\n\n");
1036}
1037
1038
1039void EntryFrame::Iterate(ObjectVisitor* v) const {
1040 StackHandlerIterator it(this, top_handler());
1041 ASSERT(!it.done());
1042 StackHandler* handler = it.handler();
1043 ASSERT(handler->is_entry());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001044 handler->Iterate(v, code());
Steve Blocka7e24c12009-10-30 11:49:00 +00001045#ifdef DEBUG
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001046 // Make sure that the entry frame does not contain more than one
1047 // stack handler.
Steve Blocka7e24c12009-10-30 11:49:00 +00001048 it.Advance();
1049 ASSERT(it.done());
1050#endif
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001051 IteratePc(v, pc_address(), code());
Steve Blocka7e24c12009-10-30 11:49:00 +00001052}
1053
1054
1055void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
1056 const int offset = StandardFrameConstants::kContextOffset;
1057 Object** base = &Memory::Object_at(sp());
1058 Object** limit = &Memory::Object_at(fp() + offset) + 1;
1059 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
1060 StackHandler* handler = it.handler();
1061 // Traverse pointers down to - but not including - the next
1062 // handler in the handler chain. Update the base to skip the
1063 // handler and allow the handler to traverse its own pointers.
1064 const Address address = handler->address();
1065 v->VisitPointers(base, reinterpret_cast<Object**>(address));
1066 base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize);
1067 // Traverse the pointers in the handler itself.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001068 handler->Iterate(v, code());
Steve Blocka7e24c12009-10-30 11:49:00 +00001069 }
1070 v->VisitPointers(base, limit);
1071}
1072
1073
1074void JavaScriptFrame::Iterate(ObjectVisitor* v) const {
1075 IterateExpressions(v);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001076 IteratePc(v, pc_address(), code());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001077 IterateArguments(v);
1078}
Steve Blocka7e24c12009-10-30 11:49:00 +00001079
Ben Murdochb0fe1622011-05-05 13:52:32 +01001080
1081void JavaScriptFrame::IterateArguments(ObjectVisitor* v) const {
Steve Blocka7e24c12009-10-30 11:49:00 +00001082 // Traverse callee-saved registers, receiver, and parameters.
1083 const int kBaseOffset = JavaScriptFrameConstants::kSavedRegistersOffset;
1084 const int kLimitOffset = JavaScriptFrameConstants::kReceiverOffset;
1085 Object** base = &Memory::Object_at(fp() + kBaseOffset);
1086 Object** limit = &Memory::Object_at(caller_sp() + kLimitOffset) + 1;
1087 v->VisitPointers(base, limit);
1088}
1089
1090
1091void InternalFrame::Iterate(ObjectVisitor* v) const {
1092 // Internal frames only have object pointers on the expression stack
1093 // as they never have any arguments.
1094 IterateExpressions(v);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001095 IteratePc(v, pc_address(), code());
Steve Blocka7e24c12009-10-30 11:49:00 +00001096}
1097
1098
1099// -------------------------------------------------------------------------
1100
1101
1102JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) {
1103 ASSERT(n >= 0);
1104 for (int i = 0; i <= n; i++) {
1105 while (!iterator_.frame()->is_java_script()) iterator_.Advance();
1106 if (i == n) return JavaScriptFrame::cast(iterator_.frame());
1107 iterator_.Advance();
1108 }
1109 UNREACHABLE();
1110 return NULL;
1111}
1112
1113
1114// -------------------------------------------------------------------------
1115
1116
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001117Code* PcToCodeCache::GcSafeCastToCode(HeapObject* object, Address pc) {
1118 Code* code = reinterpret_cast<Code*>(object);
1119 ASSERT(code != NULL && code->contains(pc));
1120 return code;
1121}
1122
1123
1124Code* PcToCodeCache::GcSafeFindCodeForPc(Address pc) {
1125 // Check if the pc points into a large object chunk.
1126 LargeObjectChunk* chunk = Heap::lo_space()->FindChunkContainingPc(pc);
1127 if (chunk != NULL) return GcSafeCastToCode(chunk->GetObject(), pc);
1128
1129 // Iterate through the 8K page until we reach the end or find an
1130 // object starting after the pc.
1131 Page* page = Page::FromAddress(pc);
1132 HeapObjectIterator iterator(page, Heap::GcSafeSizeOfOldObjectFunction());
1133 HeapObject* previous = NULL;
1134 while (true) {
1135 HeapObject* next = iterator.next();
1136 if (next == NULL || next->address() >= pc) {
1137 return GcSafeCastToCode(previous, pc);
1138 }
1139 previous = next;
1140 }
1141}
1142
Ben Murdochb0fe1622011-05-05 13:52:32 +01001143
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001144PcToCodeCache::PcToCodeCacheEntry* PcToCodeCache::GetCacheEntry(Address pc) {
1145 Counters::pc_to_code.Increment();
1146 ASSERT(IsPowerOf2(kPcToCodeCacheSize));
1147 uint32_t hash = ComputeIntegerHash(
1148 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(pc)));
1149 uint32_t index = hash & (kPcToCodeCacheSize - 1);
1150 PcToCodeCacheEntry* entry = cache(index);
1151 if (entry->pc == pc) {
1152 Counters::pc_to_code_cached.Increment();
1153 ASSERT(entry->code == GcSafeFindCodeForPc(pc));
1154 } else {
1155 // Because this code may be interrupted by a profiling signal that
1156 // also queries the cache, we cannot update pc before the code has
1157 // been set. Otherwise, we risk trying to use a cache entry before
1158 // the code has been computed.
1159 entry->code = GcSafeFindCodeForPc(pc);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001160 entry->safepoint_entry.Reset();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001161 entry->pc = pc;
1162 }
1163 return entry;
1164}
1165
1166
1167// -------------------------------------------------------------------------
1168
Steve Blocka7e24c12009-10-30 11:49:00 +00001169int NumRegs(RegList reglist) {
1170 int n = 0;
1171 while (reglist != 0) {
1172 n++;
1173 reglist &= reglist - 1; // clear one bit
1174 }
1175 return n;
1176}
1177
1178
1179int JSCallerSavedCode(int n) {
1180 static int reg_code[kNumJSCallerSaved];
1181 static bool initialized = false;
1182 if (!initialized) {
1183 initialized = true;
1184 int i = 0;
1185 for (int r = 0; r < kNumRegs; r++)
1186 if ((kJSCallerSaved & (1 << r)) != 0)
1187 reg_code[i++] = r;
1188
1189 ASSERT(i == kNumJSCallerSaved);
1190 }
1191 ASSERT(0 <= n && n < kNumJSCallerSaved);
1192 return reg_code[n];
1193}
1194
1195
Steve Block6ded16b2010-05-10 14:33:55 +01001196#define DEFINE_WRAPPER(type, field) \
1197class field##_Wrapper : public ZoneObject { \
1198 public: /* NOLINT */ \
1199 field##_Wrapper(const field& original) : frame_(original) { \
1200 } \
1201 field frame_; \
1202};
1203STACK_FRAME_TYPE_LIST(DEFINE_WRAPPER)
1204#undef DEFINE_WRAPPER
1205
1206static StackFrame* AllocateFrameCopy(StackFrame* frame) {
1207#define FRAME_TYPE_CASE(type, field) \
1208 case StackFrame::type: { \
1209 field##_Wrapper* wrapper = \
1210 new field##_Wrapper(*(reinterpret_cast<field*>(frame))); \
1211 return &wrapper->frame_; \
1212 }
1213
1214 switch (frame->type()) {
1215 STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
1216 default: UNREACHABLE();
1217 }
1218#undef FRAME_TYPE_CASE
1219 return NULL;
1220}
1221
1222Vector<StackFrame*> CreateStackMap() {
1223 ZoneList<StackFrame*> list(10);
1224 for (StackFrameIterator it; !it.done(); it.Advance()) {
1225 StackFrame* frame = AllocateFrameCopy(it.frame());
1226 list.Add(frame);
1227 }
1228 return list.ToVector();
1229}
1230
1231
Steve Blocka7e24c12009-10-30 11:49:00 +00001232} } // namespace v8::internal