blob: 3af72887e9fd434e1a1308a745451ef913199e75 [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,
332 uint8_t** safepoint_entry,
333 unsigned* stack_slots) {
334 PcToCodeCache::PcToCodeCacheEntry* entry = PcToCodeCache::GetCacheEntry(pc);
335 uint8_t* cached_safepoint_entry = entry->safepoint_entry;
336 if (cached_safepoint_entry == NULL) {
337 cached_safepoint_entry = entry->code->GetSafepointEntry(pc);
338 ASSERT(cached_safepoint_entry != NULL); // No safepoint found.
339 entry->safepoint_entry = cached_safepoint_entry;
340 } else {
341 ASSERT(cached_safepoint_entry == entry->code->GetSafepointEntry(pc));
342 }
343
344 // Fill in the results and return the code.
345 Code* code = entry->code;
346 *safepoint_entry = cached_safepoint_entry;
347 *stack_slots = code->stack_slots();
348 return code;
349}
350
351
Steve Blocka7e24c12009-10-30 11:49:00 +0000352bool StackFrame::HasHandler() const {
353 StackHandlerIterator it(this, top_handler());
354 return !it.done();
355}
356
Ben Murdochb0fe1622011-05-05 13:52:32 +0100357
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100358void StackFrame::IteratePc(ObjectVisitor* v,
359 Address* pc_address,
360 Code* holder) {
361 Address pc = *pc_address;
362 ASSERT(holder->contains(pc));
363 unsigned pc_offset = static_cast<unsigned>(pc - holder->instruction_start());
364 Object* code = holder;
365 v->VisitPointer(&code);
366 if (code != holder) {
367 holder = reinterpret_cast<Code*>(code);
368 pc = holder->instruction_start() + pc_offset;
369 *pc_address = pc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000370 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000371}
372
373
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100374StackFrame::Type StackFrame::ComputeType(State* state) {
375 ASSERT(state->fp != NULL);
376 if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
377 return ARGUMENTS_ADAPTOR;
Steve Blocka7e24c12009-10-30 11:49:00 +0000378 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100379 // The marker and function offsets overlap. If the marker isn't a
380 // smi then the frame is a JavaScript frame -- and the marker is
381 // really the function.
382 const int offset = StandardFrameConstants::kMarkerOffset;
383 Object* marker = Memory::Object_at(state->fp + offset);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100384 if (!marker->IsSmi()) {
385 // If we're using a "safe" stack iterator, we treat optimized
386 // frames as normal JavaScript frames to avoid having to look
387 // into the heap to determine the state. This is safe as long
388 // as nobody tries to GC...
389 if (SafeStackFrameIterator::is_active()) return JAVA_SCRIPT;
390 Code::Kind kind = GetContainingCode(*(state->pc_address))->kind();
391 ASSERT(kind == Code::FUNCTION || kind == Code::OPTIMIZED_FUNCTION);
392 return (kind == Code::OPTIMIZED_FUNCTION) ? OPTIMIZED : JAVA_SCRIPT;
393 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100394 return static_cast<StackFrame::Type>(Smi::cast(marker)->value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000395}
396
397
Steve Blocka7e24c12009-10-30 11:49:00 +0000398
399StackFrame::Type StackFrame::GetCallerState(State* state) const {
400 ComputeCallerState(state);
401 return ComputeType(state);
402}
403
404
Iain Merrick75681382010-08-19 15:07:18 +0100405Code* EntryFrame::unchecked_code() const {
406 return Heap::raw_unchecked_js_entry_code();
Steve Blocka7e24c12009-10-30 11:49:00 +0000407}
408
409
410void EntryFrame::ComputeCallerState(State* state) const {
411 GetCallerState(state);
412}
413
414
Steve Block6ded16b2010-05-10 14:33:55 +0100415void EntryFrame::SetCallerFp(Address caller_fp) {
416 const int offset = EntryFrameConstants::kCallerFPOffset;
417 Memory::Address_at(this->fp() + offset) = caller_fp;
418}
419
420
Steve Blocka7e24c12009-10-30 11:49:00 +0000421StackFrame::Type EntryFrame::GetCallerState(State* state) const {
422 const int offset = EntryFrameConstants::kCallerFPOffset;
423 Address fp = Memory::Address_at(this->fp() + offset);
424 return ExitFrame::GetStateForFramePointer(fp, state);
425}
426
427
Iain Merrick75681382010-08-19 15:07:18 +0100428Code* EntryConstructFrame::unchecked_code() const {
429 return Heap::raw_unchecked_js_construct_entry_code();
Steve Blocka7e24c12009-10-30 11:49:00 +0000430}
431
432
Steve Blockd0582a62009-12-15 09:54:21 +0000433Object*& ExitFrame::code_slot() const {
434 const int offset = ExitFrameConstants::kCodeOffset;
435 return Memory::Object_at(fp() + offset);
436}
437
438
Iain Merrick75681382010-08-19 15:07:18 +0100439Code* ExitFrame::unchecked_code() const {
440 return reinterpret_cast<Code*>(code_slot());
Steve Blocka7e24c12009-10-30 11:49:00 +0000441}
442
443
444void ExitFrame::ComputeCallerState(State* state) const {
445 // Setup the caller state.
446 state->sp = caller_sp();
447 state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset);
448 state->pc_address
449 = reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset);
450}
451
452
Steve Block6ded16b2010-05-10 14:33:55 +0100453void ExitFrame::SetCallerFp(Address caller_fp) {
454 Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset) = caller_fp;
455}
456
457
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100458void ExitFrame::Iterate(ObjectVisitor* v) const {
459 // The arguments are traversed as part of the expression stack of
460 // the calling frame.
461 IteratePc(v, pc_address(), code());
462 v->VisitPointer(&code_slot());
463}
464
465
Steve Blocka7e24c12009-10-30 11:49:00 +0000466Address ExitFrame::GetCallerStackPointer() const {
467 return fp() + ExitFrameConstants::kCallerSPDisplacement;
468}
469
470
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100471StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
472 if (fp == 0) return NONE;
473 Address sp = ComputeStackPointer(fp);
474 FillState(fp, sp, state);
475 ASSERT(*state->pc_address != NULL);
476 return EXIT;
477}
478
479
480void ExitFrame::FillState(Address fp, Address sp, State* state) {
481 state->sp = sp;
482 state->fp = fp;
483 state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize);
484}
485
486
Steve Blocka7e24c12009-10-30 11:49:00 +0000487Address StandardFrame::GetExpressionAddress(int n) const {
488 const int offset = StandardFrameConstants::kExpressionsOffset;
489 return fp() + offset - n * kPointerSize;
490}
491
492
493int StandardFrame::ComputeExpressionsCount() const {
494 const int offset =
495 StandardFrameConstants::kExpressionsOffset + kPointerSize;
496 Address base = fp() + offset;
497 Address limit = sp();
498 ASSERT(base >= limit); // stack grows downwards
499 // Include register-allocated locals in number of expressions.
Steve Blockd0582a62009-12-15 09:54:21 +0000500 return static_cast<int>((base - limit) / kPointerSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000501}
502
503
504void StandardFrame::ComputeCallerState(State* state) const {
505 state->sp = caller_sp();
506 state->fp = caller_fp();
507 state->pc_address = reinterpret_cast<Address*>(ComputePCAddress(fp()));
508}
509
510
Steve Block6ded16b2010-05-10 14:33:55 +0100511void StandardFrame::SetCallerFp(Address caller_fp) {
512 Memory::Address_at(fp() + StandardFrameConstants::kCallerFPOffset) =
513 caller_fp;
514}
515
516
Steve Blocka7e24c12009-10-30 11:49:00 +0000517bool StandardFrame::IsExpressionInsideHandler(int n) const {
518 Address address = GetExpressionAddress(n);
519 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
520 if (it.handler()->includes(address)) return true;
521 }
522 return false;
523}
524
525
Ben Murdochb0fe1622011-05-05 13:52:32 +0100526void OptimizedFrame::Iterate(ObjectVisitor* v) const {
527#ifdef DEBUG
528 // Make sure that optimized frames do not contain any stack handlers.
529 StackHandlerIterator it(this, top_handler());
530 ASSERT(it.done());
531#endif
532
533 // Make sure that we're not doing "safe" stack frame iteration. We cannot
534 // possibly find pointers in optimized frames in that state.
535 ASSERT(!SafeStackFrameIterator::is_active());
536
537 // Compute the safepoint information.
538 unsigned stack_slots = 0;
539 uint8_t* safepoint_entry = NULL;
540 Code* code = StackFrame::GetSafepointData(
541 pc(), &safepoint_entry, &stack_slots);
542 unsigned slot_space = stack_slots * kPointerSize;
543
544 // Visit the outgoing parameters. This is usually dealt with by the
545 // callee, but while GC'ing we artificially lower the number of
546 // arguments to zero and let the caller deal with it.
547 Object** parameters_base = &Memory::Object_at(sp());
548 Object** parameters_limit = &Memory::Object_at(
549 fp() + JavaScriptFrameConstants::kFunctionOffset - slot_space);
550
551 // Visit the registers that contain pointers if any.
552 if (SafepointTable::HasRegisters(safepoint_entry)) {
553 for (int i = kNumSafepointRegisters - 1; i >=0; i--) {
554 if (SafepointTable::HasRegisterAt(safepoint_entry, i)) {
555 int reg_stack_index = MacroAssembler::SafepointRegisterStackIndex(i);
556 v->VisitPointer(parameters_base + reg_stack_index);
557 }
558 }
559 // Skip the words containing the register values.
560 parameters_base += kNumSafepointRegisters;
561 }
562
563 // We're done dealing with the register bits.
564 safepoint_entry += kNumSafepointRegisters >> kBitsPerByteLog2;
565
566 // Visit the rest of the parameters.
567 v->VisitPointers(parameters_base, parameters_limit);
568
569 // Visit pointer spill slots and locals.
570 for (unsigned index = 0; index < stack_slots; index++) {
571 int byte_index = index >> kBitsPerByteLog2;
572 int bit_index = index & (kBitsPerByte - 1);
573 if ((safepoint_entry[byte_index] & (1U << bit_index)) != 0) {
574 v->VisitPointer(parameters_limit + index);
575 }
576 }
577
578 // Visit the context and the function.
579 Object** fixed_base = &Memory::Object_at(
580 fp() + JavaScriptFrameConstants::kFunctionOffset);
581 Object** fixed_limit = &Memory::Object_at(fp());
582 v->VisitPointers(fixed_base, fixed_limit);
583
584 // Visit the return address in the callee and incoming arguments.
585 IteratePc(v, pc_address(), code);
586 IterateArguments(v);
587}
588
589
Steve Blocka7e24c12009-10-30 11:49:00 +0000590Object* JavaScriptFrame::GetParameter(int index) const {
591 ASSERT(index >= 0 && index < ComputeParametersCount());
592 const int offset = JavaScriptFrameConstants::kParam0Offset;
593 return Memory::Object_at(caller_sp() + offset - (index * kPointerSize));
594}
595
596
597int JavaScriptFrame::ComputeParametersCount() const {
598 Address base = caller_sp() + JavaScriptFrameConstants::kReceiverOffset;
599 Address limit = fp() + JavaScriptFrameConstants::kSavedRegistersOffset;
Steve Blockd0582a62009-12-15 09:54:21 +0000600 return static_cast<int>((base - limit) / kPointerSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000601}
602
603
604bool JavaScriptFrame::IsConstructor() const {
605 Address fp = caller_fp();
606 if (has_adapted_arguments()) {
607 // Skip the arguments adaptor frame and look at the real caller.
608 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
609 }
610 return IsConstructFrame(fp);
611}
612
613
Iain Merrick75681382010-08-19 15:07:18 +0100614Code* JavaScriptFrame::unchecked_code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000615 JSFunction* function = JSFunction::cast(this->function());
Iain Merrick75681382010-08-19 15:07:18 +0100616 return function->unchecked_code();
Steve Blocka7e24c12009-10-30 11:49:00 +0000617}
618
619
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100620int JavaScriptFrame::GetProvidedParametersCount() const {
621 return ComputeParametersCount();
622}
623
624
625Address JavaScriptFrame::GetCallerStackPointer() const {
626 int arguments;
627 if (Heap::gc_state() != Heap::NOT_IN_GC ||
628 SafeStackFrameIterator::is_active()) {
629 // If the we are currently iterating the safe stack the
630 // arguments for frames are traversed as if they were
631 // expression stack elements of the calling frame. The reason for
632 // this rather strange decision is that we cannot access the
633 // function during mark-compact GCs when objects may have been marked.
634 // In fact accessing heap objects (like function->shared() below)
635 // at all during GC is problematic.
636 arguments = 0;
637 } else {
638 // Compute the number of arguments by getting the number of formal
639 // parameters of the function. We must remember to take the
640 // receiver into account (+1).
641 JSFunction* function = JSFunction::cast(this->function());
642 arguments = function->shared()->formal_parameter_count() + 1;
643 }
644 const int offset = StandardFrameConstants::kCallerSPOffset;
645 return fp() + offset + (arguments * kPointerSize);
646}
647
648
Ben Murdochb0fe1622011-05-05 13:52:32 +0100649void JavaScriptFrame::GetFunctions(List<JSFunction*>* functions) {
650 ASSERT(functions->length() == 0);
651 functions->Add(JSFunction::cast(function()));
652}
653
654
655void JavaScriptFrame::Summarize(List<FrameSummary>* functions) {
656 ASSERT(functions->length() == 0);
657 Code* code_pointer = code();
658 int offset = static_cast<int>(pc() - code_pointer->address());
659 FrameSummary summary(receiver(),
660 JSFunction::cast(function()),
661 code_pointer,
662 offset,
663 IsConstructor());
664 functions->Add(summary);
665}
666
667
668void FrameSummary::Print() {
669 PrintF("receiver: ");
670 receiver_->ShortPrint();
671 PrintF("\nfunction: ");
672 function_->shared()->DebugName()->ShortPrint();
673 PrintF("\ncode: ");
674 code_->ShortPrint();
675 if (code_->kind() == Code::FUNCTION) PrintF(" NON-OPT");
676 if (code_->kind() == Code::OPTIMIZED_FUNCTION) PrintF(" OPT");
677 PrintF("\npc: %d\n", offset_);
678}
679
680
681void OptimizedFrame::Summarize(List<FrameSummary>* frames) {
682 ASSERT(frames->length() == 0);
683 ASSERT(is_optimized());
684
685 int deopt_index = AstNode::kNoNumber;
686 DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
687
688 // BUG(3243555): Since we don't have a lazy-deopt registered at
689 // throw-statements, we can't use the translation at the call-site of
690 // throw. An entry with no deoptimization index indicates a call-site
691 // without a lazy-deopt. As a consequence we are not allowed to inline
692 // functions containing throw.
693 if (deopt_index == Safepoint::kNoDeoptimizationIndex) {
694 JavaScriptFrame::Summarize(frames);
695 return;
696 }
697
698 TranslationIterator it(data->TranslationByteArray(),
699 data->TranslationIndex(deopt_index)->value());
700 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
701 ASSERT(opcode == Translation::BEGIN);
702 int frame_count = it.Next();
703
704 // We create the summary in reverse order because the frames
705 // in the deoptimization translation are ordered bottom-to-top.
706 int i = frame_count;
707 while (i > 0) {
708 opcode = static_cast<Translation::Opcode>(it.Next());
709 if (opcode == Translation::FRAME) {
710 // We don't inline constructor calls, so only the first, outermost
711 // frame can be a constructor frame in case of inlining.
712 bool is_constructor = (i == frame_count) && IsConstructor();
713
714 i--;
715 int ast_id = it.Next();
716 int function_id = it.Next();
717 it.Next(); // Skip height.
718 JSFunction* function =
719 JSFunction::cast(data->LiteralArray()->get(function_id));
720
721 // The translation commands are ordered and the receiver is always
722 // at the first position. Since we are always at a call when we need
723 // to construct a stack trace, the receiver is always in a stack slot.
724 opcode = static_cast<Translation::Opcode>(it.Next());
725 ASSERT(opcode == Translation::STACK_SLOT);
726 int input_slot_index = it.Next();
727
728 // Get the correct receiver in the optimized frame.
729 Object* receiver = NULL;
730 // Positive index means the value is spilled to the locals area. Negative
731 // means it is stored in the incoming parameter area.
732 if (input_slot_index >= 0) {
733 receiver = GetExpression(input_slot_index);
734 } else {
735 // Index -1 overlaps with last parameter, -n with the first parameter,
736 // (-n - 1) with the receiver with n being the number of parameters
737 // of the outermost, optimized frame.
738 int parameter_count = ComputeParametersCount();
739 int parameter_index = input_slot_index + parameter_count;
740 receiver = (parameter_index == -1)
741 ? this->receiver()
742 : this->GetParameter(parameter_index);
743 }
744
745 Code* code = function->shared()->code();
746 DeoptimizationOutputData* output_data =
747 DeoptimizationOutputData::cast(code->deoptimization_data());
748 unsigned entry = Deoptimizer::GetOutputInfo(output_data,
749 ast_id,
750 function->shared());
751 unsigned pc_offset =
752 FullCodeGenerator::PcField::decode(entry) + Code::kHeaderSize;
753 ASSERT(pc_offset > 0);
754
755 FrameSummary summary(receiver, function, code, pc_offset, is_constructor);
756 frames->Add(summary);
757 } else {
758 // Skip over operands to advance to the next opcode.
759 it.Skip(Translation::NumberOfOperandsFor(opcode));
760 }
761 }
762}
763
764
765DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData(
766 int* deopt_index) {
767 ASSERT(is_optimized());
768
769 JSFunction* opt_function = JSFunction::cast(function());
770 Code* code = opt_function->code();
771
772 // The code object may have been replaced by lazy deoptimization. Fall
773 // back to a slow search in this case to find the original optimized
774 // code object.
775 if (!code->contains(pc())) {
776 code = PcToCodeCache::GcSafeFindCodeForPc(pc());
777 }
778 ASSERT(code != NULL);
779 ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
780
781 SafepointTable table(code);
782 unsigned pc_offset = static_cast<unsigned>(pc() - code->instruction_start());
783 for (unsigned i = 0; i < table.length(); i++) {
784 if (table.GetPcOffset(i) == pc_offset) {
785 *deopt_index = table.GetDeoptimizationIndex(i);
786 break;
787 }
788 }
789 ASSERT(*deopt_index != AstNode::kNoNumber);
790
791 return DeoptimizationInputData::cast(code->deoptimization_data());
792}
793
794
795void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) {
796 ASSERT(functions->length() == 0);
797 ASSERT(is_optimized());
798
799 int deopt_index = AstNode::kNoNumber;
800 DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
801
802 TranslationIterator it(data->TranslationByteArray(),
803 data->TranslationIndex(deopt_index)->value());
804 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
805 ASSERT(opcode == Translation::BEGIN);
806 int frame_count = it.Next();
807
808 // We insert the frames in reverse order because the frames
809 // in the deoptimization translation are ordered bottom-to-top.
810 while (frame_count > 0) {
811 opcode = static_cast<Translation::Opcode>(it.Next());
812 if (opcode == Translation::FRAME) {
813 frame_count--;
814 it.Next(); // Skip ast id.
815 int function_id = it.Next();
816 it.Next(); // Skip height.
817 JSFunction* function =
818 JSFunction::cast(data->LiteralArray()->get(function_id));
819 functions->Add(function);
820 } else {
821 // Skip over operands to advance to the next opcode.
822 it.Skip(Translation::NumberOfOperandsFor(opcode));
823 }
824 }
825}
826
827
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100828Address ArgumentsAdaptorFrame::GetCallerStackPointer() const {
829 const int arguments = Smi::cast(GetExpression(0))->value();
830 const int offset = StandardFrameConstants::kCallerSPOffset;
831 return fp() + offset + (arguments + 1) * kPointerSize;
832}
833
834
835Address InternalFrame::GetCallerStackPointer() const {
836 // Internal frames have no arguments. The stack pointer of the
837 // caller is at a fixed offset from the frame pointer.
838 return fp() + StandardFrameConstants::kCallerSPOffset;
839}
840
841
Iain Merrick75681382010-08-19 15:07:18 +0100842Code* ArgumentsAdaptorFrame::unchecked_code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000843 return Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline);
844}
845
846
Iain Merrick75681382010-08-19 15:07:18 +0100847Code* InternalFrame::unchecked_code() const {
Steve Blocka7e24c12009-10-30 11:49:00 +0000848 const int offset = InternalFrameConstants::kCodeOffset;
849 Object* code = Memory::Object_at(fp() + offset);
850 ASSERT(code != NULL);
Iain Merrick75681382010-08-19 15:07:18 +0100851 return reinterpret_cast<Code*>(code);
Steve Blocka7e24c12009-10-30 11:49:00 +0000852}
853
854
855void StackFrame::PrintIndex(StringStream* accumulator,
856 PrintMode mode,
857 int index) {
858 accumulator->Add((mode == OVERVIEW) ? "%5d: " : "[%d]: ", index);
859}
860
861
862void JavaScriptFrame::Print(StringStream* accumulator,
863 PrintMode mode,
864 int index) const {
865 HandleScope scope;
866 Object* receiver = this->receiver();
867 Object* function = this->function();
868
869 accumulator->PrintSecurityTokenIfChanged(function);
870 PrintIndex(accumulator, mode, index);
871 Code* code = NULL;
872 if (IsConstructor()) accumulator->Add("new ");
873 accumulator->PrintFunction(function, receiver, &code);
Steve Block6ded16b2010-05-10 14:33:55 +0100874
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100875 Handle<SerializedScopeInfo> scope_info(SerializedScopeInfo::Empty());
876
Steve Block6ded16b2010-05-10 14:33:55 +0100877 if (function->IsJSFunction()) {
878 Handle<SharedFunctionInfo> shared(JSFunction::cast(function)->shared());
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100879 scope_info = Handle<SerializedScopeInfo>(shared->scope_info());
Steve Block6ded16b2010-05-10 14:33:55 +0100880 Object* script_obj = shared->script();
881 if (script_obj->IsScript()) {
882 Handle<Script> script(Script::cast(script_obj));
883 accumulator->Add(" [");
884 accumulator->PrintName(script->name());
885
886 Address pc = this->pc();
887 if (code != NULL && code->kind() == Code::FUNCTION &&
Leon Clarkeac952652010-07-15 11:15:24 +0100888 pc >= code->instruction_start() && pc < code->instruction_end()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100889 int source_pos = code->SourcePosition(pc);
890 int line = GetScriptLineNumberSafe(script, source_pos) + 1;
891 accumulator->Add(":%d", line);
892 } else {
893 int function_start_pos = shared->start_position();
894 int line = GetScriptLineNumberSafe(script, function_start_pos) + 1;
895 accumulator->Add(":~%d", line);
896 }
897
898 accumulator->Add("] ");
899 }
900 }
901
Steve Blocka7e24c12009-10-30 11:49:00 +0000902 accumulator->Add("(this=%o", receiver);
903
904 // Get scope information for nicer output, if possible. If code is
905 // NULL, or doesn't contain scope info, info will return 0 for the
906 // number of parameters, stack slots, or context slots.
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100907 ScopeInfo<PreallocatedStorage> info(*scope_info);
Steve Blocka7e24c12009-10-30 11:49:00 +0000908
909 // Print the parameters.
910 int parameters_count = ComputeParametersCount();
911 for (int i = 0; i < parameters_count; i++) {
912 accumulator->Add(",");
913 // If we have a name for the parameter we print it. Nameless
914 // parameters are either because we have more actual parameters
915 // than formal parameters or because we have no scope information.
916 if (i < info.number_of_parameters()) {
917 accumulator->PrintName(*info.parameter_name(i));
918 accumulator->Add("=");
919 }
920 accumulator->Add("%o", GetParameter(i));
921 }
922
923 accumulator->Add(")");
924 if (mode == OVERVIEW) {
925 accumulator->Add("\n");
926 return;
927 }
928 accumulator->Add(" {\n");
929
930 // Compute the number of locals and expression stack elements.
931 int stack_locals_count = info.number_of_stack_slots();
932 int heap_locals_count = info.number_of_context_slots();
933 int expressions_count = ComputeExpressionsCount();
934
935 // Print stack-allocated local variables.
936 if (stack_locals_count > 0) {
937 accumulator->Add(" // stack-allocated locals\n");
938 }
939 for (int i = 0; i < stack_locals_count; i++) {
940 accumulator->Add(" var ");
941 accumulator->PrintName(*info.stack_slot_name(i));
942 accumulator->Add(" = ");
943 if (i < expressions_count) {
944 accumulator->Add("%o", GetExpression(i));
945 } else {
946 accumulator->Add("// no expression found - inconsistent frame?");
947 }
948 accumulator->Add("\n");
949 }
950
951 // Try to get hold of the context of this frame.
952 Context* context = NULL;
953 if (this->context() != NULL && this->context()->IsContext()) {
954 context = Context::cast(this->context());
955 }
956
957 // Print heap-allocated local variables.
958 if (heap_locals_count > Context::MIN_CONTEXT_SLOTS) {
959 accumulator->Add(" // heap-allocated locals\n");
960 }
961 for (int i = Context::MIN_CONTEXT_SLOTS; i < heap_locals_count; i++) {
962 accumulator->Add(" var ");
963 accumulator->PrintName(*info.context_slot_name(i));
964 accumulator->Add(" = ");
965 if (context != NULL) {
966 if (i < context->length()) {
967 accumulator->Add("%o", context->get(i));
968 } else {
969 accumulator->Add(
970 "// warning: missing context slot - inconsistent frame?");
971 }
972 } else {
973 accumulator->Add("// warning: no context found - inconsistent frame?");
974 }
975 accumulator->Add("\n");
976 }
977
978 // Print the expression stack.
979 int expressions_start = stack_locals_count;
980 if (expressions_start < expressions_count) {
981 accumulator->Add(" // expression stack (top to bottom)\n");
982 }
983 for (int i = expressions_count - 1; i >= expressions_start; i--) {
984 if (IsExpressionInsideHandler(i)) continue;
985 accumulator->Add(" [%02d] : %o\n", i, GetExpression(i));
986 }
987
988 // Print details about the function.
989 if (FLAG_max_stack_trace_source_length != 0 && code != NULL) {
990 SharedFunctionInfo* shared = JSFunction::cast(function)->shared();
991 accumulator->Add("--------- s o u r c e c o d e ---------\n");
992 shared->SourceCodePrint(accumulator, FLAG_max_stack_trace_source_length);
993 accumulator->Add("\n-----------------------------------------\n");
994 }
995
996 accumulator->Add("}\n\n");
997}
998
999
1000void ArgumentsAdaptorFrame::Print(StringStream* accumulator,
1001 PrintMode mode,
1002 int index) const {
1003 int actual = ComputeParametersCount();
1004 int expected = -1;
1005 Object* function = this->function();
1006 if (function->IsJSFunction()) {
1007 expected = JSFunction::cast(function)->shared()->formal_parameter_count();
1008 }
1009
1010 PrintIndex(accumulator, mode, index);
1011 accumulator->Add("arguments adaptor frame: %d->%d", actual, expected);
1012 if (mode == OVERVIEW) {
1013 accumulator->Add("\n");
1014 return;
1015 }
1016 accumulator->Add(" {\n");
1017
1018 // Print actual arguments.
1019 if (actual > 0) accumulator->Add(" // actual arguments\n");
1020 for (int i = 0; i < actual; i++) {
1021 accumulator->Add(" [%02d] : %o", i, GetParameter(i));
1022 if (expected != -1 && i >= expected) {
1023 accumulator->Add(" // not passed to callee");
1024 }
1025 accumulator->Add("\n");
1026 }
1027
1028 accumulator->Add("}\n\n");
1029}
1030
1031
1032void EntryFrame::Iterate(ObjectVisitor* v) const {
1033 StackHandlerIterator it(this, top_handler());
1034 ASSERT(!it.done());
1035 StackHandler* handler = it.handler();
1036 ASSERT(handler->is_entry());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001037 handler->Iterate(v, code());
Steve Blocka7e24c12009-10-30 11:49:00 +00001038#ifdef DEBUG
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001039 // Make sure that the entry frame does not contain more than one
1040 // stack handler.
Steve Blocka7e24c12009-10-30 11:49:00 +00001041 it.Advance();
1042 ASSERT(it.done());
1043#endif
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001044 IteratePc(v, pc_address(), code());
Steve Blocka7e24c12009-10-30 11:49:00 +00001045}
1046
1047
1048void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
1049 const int offset = StandardFrameConstants::kContextOffset;
1050 Object** base = &Memory::Object_at(sp());
1051 Object** limit = &Memory::Object_at(fp() + offset) + 1;
1052 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
1053 StackHandler* handler = it.handler();
1054 // Traverse pointers down to - but not including - the next
1055 // handler in the handler chain. Update the base to skip the
1056 // handler and allow the handler to traverse its own pointers.
1057 const Address address = handler->address();
1058 v->VisitPointers(base, reinterpret_cast<Object**>(address));
1059 base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize);
1060 // Traverse the pointers in the handler itself.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001061 handler->Iterate(v, code());
Steve Blocka7e24c12009-10-30 11:49:00 +00001062 }
1063 v->VisitPointers(base, limit);
1064}
1065
1066
1067void JavaScriptFrame::Iterate(ObjectVisitor* v) const {
1068 IterateExpressions(v);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001069 IteratePc(v, pc_address(), code());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001070 IterateArguments(v);
1071}
Steve Blocka7e24c12009-10-30 11:49:00 +00001072
Ben Murdochb0fe1622011-05-05 13:52:32 +01001073
1074void JavaScriptFrame::IterateArguments(ObjectVisitor* v) const {
Steve Blocka7e24c12009-10-30 11:49:00 +00001075 // Traverse callee-saved registers, receiver, and parameters.
1076 const int kBaseOffset = JavaScriptFrameConstants::kSavedRegistersOffset;
1077 const int kLimitOffset = JavaScriptFrameConstants::kReceiverOffset;
1078 Object** base = &Memory::Object_at(fp() + kBaseOffset);
1079 Object** limit = &Memory::Object_at(caller_sp() + kLimitOffset) + 1;
1080 v->VisitPointers(base, limit);
1081}
1082
1083
1084void InternalFrame::Iterate(ObjectVisitor* v) const {
1085 // Internal frames only have object pointers on the expression stack
1086 // as they never have any arguments.
1087 IterateExpressions(v);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001088 IteratePc(v, pc_address(), code());
Steve Blocka7e24c12009-10-30 11:49:00 +00001089}
1090
1091
1092// -------------------------------------------------------------------------
1093
1094
1095JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) {
1096 ASSERT(n >= 0);
1097 for (int i = 0; i <= n; i++) {
1098 while (!iterator_.frame()->is_java_script()) iterator_.Advance();
1099 if (i == n) return JavaScriptFrame::cast(iterator_.frame());
1100 iterator_.Advance();
1101 }
1102 UNREACHABLE();
1103 return NULL;
1104}
1105
1106
1107// -------------------------------------------------------------------------
1108
1109
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001110Code* PcToCodeCache::GcSafeCastToCode(HeapObject* object, Address pc) {
1111 Code* code = reinterpret_cast<Code*>(object);
1112 ASSERT(code != NULL && code->contains(pc));
1113 return code;
1114}
1115
1116
1117Code* PcToCodeCache::GcSafeFindCodeForPc(Address pc) {
1118 // Check if the pc points into a large object chunk.
1119 LargeObjectChunk* chunk = Heap::lo_space()->FindChunkContainingPc(pc);
1120 if (chunk != NULL) return GcSafeCastToCode(chunk->GetObject(), pc);
1121
1122 // Iterate through the 8K page until we reach the end or find an
1123 // object starting after the pc.
1124 Page* page = Page::FromAddress(pc);
1125 HeapObjectIterator iterator(page, Heap::GcSafeSizeOfOldObjectFunction());
1126 HeapObject* previous = NULL;
1127 while (true) {
1128 HeapObject* next = iterator.next();
1129 if (next == NULL || next->address() >= pc) {
1130 return GcSafeCastToCode(previous, pc);
1131 }
1132 previous = next;
1133 }
1134}
1135
Ben Murdochb0fe1622011-05-05 13:52:32 +01001136
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001137PcToCodeCache::PcToCodeCacheEntry* PcToCodeCache::GetCacheEntry(Address pc) {
1138 Counters::pc_to_code.Increment();
1139 ASSERT(IsPowerOf2(kPcToCodeCacheSize));
1140 uint32_t hash = ComputeIntegerHash(
1141 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(pc)));
1142 uint32_t index = hash & (kPcToCodeCacheSize - 1);
1143 PcToCodeCacheEntry* entry = cache(index);
1144 if (entry->pc == pc) {
1145 Counters::pc_to_code_cached.Increment();
1146 ASSERT(entry->code == GcSafeFindCodeForPc(pc));
1147 } else {
1148 // Because this code may be interrupted by a profiling signal that
1149 // also queries the cache, we cannot update pc before the code has
1150 // been set. Otherwise, we risk trying to use a cache entry before
1151 // the code has been computed.
1152 entry->code = GcSafeFindCodeForPc(pc);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001153 entry->safepoint_entry = NULL;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001154 entry->pc = pc;
1155 }
1156 return entry;
1157}
1158
1159
1160// -------------------------------------------------------------------------
1161
Steve Blocka7e24c12009-10-30 11:49:00 +00001162int NumRegs(RegList reglist) {
1163 int n = 0;
1164 while (reglist != 0) {
1165 n++;
1166 reglist &= reglist - 1; // clear one bit
1167 }
1168 return n;
1169}
1170
1171
1172int JSCallerSavedCode(int n) {
1173 static int reg_code[kNumJSCallerSaved];
1174 static bool initialized = false;
1175 if (!initialized) {
1176 initialized = true;
1177 int i = 0;
1178 for (int r = 0; r < kNumRegs; r++)
1179 if ((kJSCallerSaved & (1 << r)) != 0)
1180 reg_code[i++] = r;
1181
1182 ASSERT(i == kNumJSCallerSaved);
1183 }
1184 ASSERT(0 <= n && n < kNumJSCallerSaved);
1185 return reg_code[n];
1186}
1187
1188
Steve Block6ded16b2010-05-10 14:33:55 +01001189#define DEFINE_WRAPPER(type, field) \
1190class field##_Wrapper : public ZoneObject { \
1191 public: /* NOLINT */ \
1192 field##_Wrapper(const field& original) : frame_(original) { \
1193 } \
1194 field frame_; \
1195};
1196STACK_FRAME_TYPE_LIST(DEFINE_WRAPPER)
1197#undef DEFINE_WRAPPER
1198
1199static StackFrame* AllocateFrameCopy(StackFrame* frame) {
1200#define FRAME_TYPE_CASE(type, field) \
1201 case StackFrame::type: { \
1202 field##_Wrapper* wrapper = \
1203 new field##_Wrapper(*(reinterpret_cast<field*>(frame))); \
1204 return &wrapper->frame_; \
1205 }
1206
1207 switch (frame->type()) {
1208 STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
1209 default: UNREACHABLE();
1210 }
1211#undef FRAME_TYPE_CASE
1212 return NULL;
1213}
1214
1215Vector<StackFrame*> CreateStackMap() {
1216 ZoneList<StackFrame*> list(10);
1217 for (StackFrameIterator it; !it.done(); it.Advance()) {
1218 StackFrame* frame = AllocateFrameCopy(it.frame());
1219 list.Add(frame);
1220 }
1221 return list.ToVector();
1222}
1223
1224
Steve Blocka7e24c12009-10-30 11:49:00 +00001225} } // namespace v8::internal