• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
30 #include "ast.h"
31 #include "deoptimizer.h"
32 #include "frames-inl.h"
33 #include "full-codegen.h"
34 #include "mark-compact.h"
35 #include "safepoint-table.h"
36 #include "scopeinfo.h"
37 #include "string-stream.h"
38 
39 namespace v8 {
40 namespace internal {
41 
42 // Iterator that supports traversing the stack handlers of a
43 // particular frame. Needs to know the top of the handler chain.
44 class StackHandlerIterator BASE_EMBEDDED {
45  public:
StackHandlerIterator(const StackFrame * frame,StackHandler * handler)46   StackHandlerIterator(const StackFrame* frame, StackHandler* handler)
47       : limit_(frame->fp()), handler_(handler) {
48     // Make sure the handler has already been unwound to this frame.
49     ASSERT(frame->sp() <= handler->address());
50   }
51 
handler() const52   StackHandler* handler() const { return handler_; }
53 
done()54   bool done() {
55     return handler_ == NULL || handler_->address() > limit_;
56   }
Advance()57   void Advance() {
58     ASSERT(!done());
59     handler_ = handler_->next();
60   }
61 
62  private:
63   const Address limit_;
64   StackHandler* handler_;
65 };
66 
67 
68 // -------------------------------------------------------------------------
69 
70 
71 #define INITIALIZE_SINGLETON(type, field) field##_(this),
StackFrameIterator()72 StackFrameIterator::StackFrameIterator()
73     : isolate_(Isolate::Current()),
74       STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
75       frame_(NULL), handler_(NULL),
76       thread_(isolate_->thread_local_top()),
77       fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
78   Reset();
79 }
StackFrameIterator(Isolate * isolate)80 StackFrameIterator::StackFrameIterator(Isolate* isolate)
81     : isolate_(isolate),
82       STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
83       frame_(NULL), handler_(NULL),
84       thread_(isolate_->thread_local_top()),
85       fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
86   Reset();
87 }
StackFrameIterator(Isolate * isolate,ThreadLocalTop * t)88 StackFrameIterator::StackFrameIterator(Isolate* isolate, ThreadLocalTop* t)
89     : isolate_(isolate),
90       STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
91       frame_(NULL), handler_(NULL), thread_(t),
92       fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) {
93   Reset();
94 }
StackFrameIterator(Isolate * isolate,bool use_top,Address fp,Address sp)95 StackFrameIterator::StackFrameIterator(Isolate* isolate,
96                                        bool use_top, Address fp, Address sp)
97     : isolate_(isolate),
98       STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
99       frame_(NULL), handler_(NULL),
100       thread_(use_top ? isolate_->thread_local_top() : NULL),
101       fp_(use_top ? NULL : fp), sp_(sp),
102       advance_(use_top ? &StackFrameIterator::AdvanceWithHandler :
103                &StackFrameIterator::AdvanceWithoutHandler) {
104   if (use_top || fp != NULL) {
105     Reset();
106   }
107 }
108 
109 #undef INITIALIZE_SINGLETON
110 
111 
AdvanceWithHandler()112 void StackFrameIterator::AdvanceWithHandler() {
113   ASSERT(!done());
114   // Compute the state of the calling frame before restoring
115   // callee-saved registers and unwinding handlers. This allows the
116   // frame code that computes the caller state to access the top
117   // handler and the value of any callee-saved register if needed.
118   StackFrame::State state;
119   StackFrame::Type type = frame_->GetCallerState(&state);
120 
121   // Unwind handlers corresponding to the current frame.
122   StackHandlerIterator it(frame_, handler_);
123   while (!it.done()) it.Advance();
124   handler_ = it.handler();
125 
126   // Advance to the calling frame.
127   frame_ = SingletonFor(type, &state);
128 
129   // When we're done iterating over the stack frames, the handler
130   // chain must have been completely unwound.
131   ASSERT(!done() || handler_ == NULL);
132 }
133 
134 
AdvanceWithoutHandler()135 void StackFrameIterator::AdvanceWithoutHandler() {
136   // A simpler version of Advance which doesn't care about handler.
137   ASSERT(!done());
138   StackFrame::State state;
139   StackFrame::Type type = frame_->GetCallerState(&state);
140   frame_ = SingletonFor(type, &state);
141 }
142 
143 
Reset()144 void StackFrameIterator::Reset() {
145   StackFrame::State state;
146   StackFrame::Type type;
147   if (thread_ != NULL) {
148     type = ExitFrame::GetStateForFramePointer(
149         Isolate::c_entry_fp(thread_), &state);
150     handler_ = StackHandler::FromAddress(
151         Isolate::handler(thread_));
152   } else {
153     ASSERT(fp_ != NULL);
154     state.fp = fp_;
155     state.sp = sp_;
156     state.pc_address =
157         reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp_));
158     type = StackFrame::ComputeType(isolate(), &state);
159   }
160   if (SingletonFor(type) == NULL) return;
161   frame_ = SingletonFor(type, &state);
162 }
163 
164 
SingletonFor(StackFrame::Type type,StackFrame::State * state)165 StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type,
166                                              StackFrame::State* state) {
167   if (type == StackFrame::NONE) return NULL;
168   StackFrame* result = SingletonFor(type);
169   ASSERT(result != NULL);
170   result->state_ = *state;
171   return result;
172 }
173 
174 
SingletonFor(StackFrame::Type type)175 StackFrame* StackFrameIterator::SingletonFor(StackFrame::Type type) {
176 #define FRAME_TYPE_CASE(type, field) \
177   case StackFrame::type: result = &field##_; break;
178 
179   StackFrame* result = NULL;
180   switch (type) {
181     case StackFrame::NONE: return NULL;
182     STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
183     default: break;
184   }
185   return result;
186 
187 #undef FRAME_TYPE_CASE
188 }
189 
190 
191 // -------------------------------------------------------------------------
192 
193 
StackTraceFrameIterator()194 StackTraceFrameIterator::StackTraceFrameIterator() {
195   if (!done() && !IsValidFrame()) Advance();
196 }
197 
198 
StackTraceFrameIterator(Isolate * isolate)199 StackTraceFrameIterator::StackTraceFrameIterator(Isolate* isolate)
200     : JavaScriptFrameIterator(isolate) {
201   if (!done() && !IsValidFrame()) Advance();
202 }
203 
204 
Advance()205 void StackTraceFrameIterator::Advance() {
206   while (true) {
207     JavaScriptFrameIterator::Advance();
208     if (done()) return;
209     if (IsValidFrame()) return;
210   }
211 }
212 
IsValidFrame()213 bool StackTraceFrameIterator::IsValidFrame() {
214     if (!frame()->function()->IsJSFunction()) return false;
215     Object* script = JSFunction::cast(frame()->function())->shared()->script();
216     // Don't show functions from native scripts to user.
217     return (script->IsScript() &&
218             Script::TYPE_NATIVE != Script::cast(script)->type()->value());
219 }
220 
221 
222 // -------------------------------------------------------------------------
223 
224 
IsValidFP(Address fp)225 bool SafeStackFrameIterator::ExitFrameValidator::IsValidFP(Address fp) {
226   if (!validator_.IsValid(fp)) return false;
227   Address sp = ExitFrame::ComputeStackPointer(fp);
228   if (!validator_.IsValid(sp)) return false;
229   StackFrame::State state;
230   ExitFrame::FillState(fp, sp, &state);
231   if (!validator_.IsValid(reinterpret_cast<Address>(state.pc_address))) {
232     return false;
233   }
234   return *state.pc_address != NULL;
235 }
236 
237 
ActiveCountMaintainer(Isolate * isolate)238 SafeStackFrameIterator::ActiveCountMaintainer::ActiveCountMaintainer(
239     Isolate* isolate)
240     : isolate_(isolate) {
241   isolate_->set_safe_stack_iterator_counter(
242       isolate_->safe_stack_iterator_counter() + 1);
243 }
244 
245 
~ActiveCountMaintainer()246 SafeStackFrameIterator::ActiveCountMaintainer::~ActiveCountMaintainer() {
247   isolate_->set_safe_stack_iterator_counter(
248       isolate_->safe_stack_iterator_counter() - 1);
249 }
250 
251 
SafeStackFrameIterator(Isolate * isolate,Address fp,Address sp,Address low_bound,Address high_bound)252 SafeStackFrameIterator::SafeStackFrameIterator(
253     Isolate* isolate,
254     Address fp, Address sp, Address low_bound, Address high_bound) :
255     maintainer_(isolate),
256     stack_validator_(low_bound, high_bound),
257     is_valid_top_(IsValidTop(isolate, low_bound, high_bound)),
258     is_valid_fp_(IsWithinBounds(low_bound, high_bound, fp)),
259     is_working_iterator_(is_valid_top_ || is_valid_fp_),
260     iteration_done_(!is_working_iterator_),
261     iterator_(isolate, is_valid_top_, is_valid_fp_ ? fp : NULL, sp) {
262 }
263 
is_active(Isolate * isolate)264 bool SafeStackFrameIterator::is_active(Isolate* isolate) {
265   return isolate->safe_stack_iterator_counter() > 0;
266 }
267 
268 
IsValidTop(Isolate * isolate,Address low_bound,Address high_bound)269 bool SafeStackFrameIterator::IsValidTop(Isolate* isolate,
270                                         Address low_bound, Address high_bound) {
271   ThreadLocalTop* top = isolate->thread_local_top();
272   Address fp = Isolate::c_entry_fp(top);
273   ExitFrameValidator validator(low_bound, high_bound);
274   if (!validator.IsValidFP(fp)) return false;
275   return Isolate::handler(top) != NULL;
276 }
277 
278 
Advance()279 void SafeStackFrameIterator::Advance() {
280   ASSERT(is_working_iterator_);
281   ASSERT(!done());
282   StackFrame* last_frame = iterator_.frame();
283   Address last_sp = last_frame->sp(), last_fp = last_frame->fp();
284   // Before advancing to the next stack frame, perform pointer validity tests
285   iteration_done_ = !IsValidFrame(last_frame) ||
286       !CanIterateHandles(last_frame, iterator_.handler()) ||
287       !IsValidCaller(last_frame);
288   if (iteration_done_) return;
289 
290   iterator_.Advance();
291   if (iterator_.done()) return;
292   // Check that we have actually moved to the previous frame in the stack
293   StackFrame* prev_frame = iterator_.frame();
294   iteration_done_ = prev_frame->sp() < last_sp || prev_frame->fp() < last_fp;
295 }
296 
297 
CanIterateHandles(StackFrame * frame,StackHandler * handler)298 bool SafeStackFrameIterator::CanIterateHandles(StackFrame* frame,
299                                                StackHandler* handler) {
300   // If StackIterator iterates over StackHandles, verify that
301   // StackHandlerIterator can be instantiated (see StackHandlerIterator
302   // constructor.)
303   return !is_valid_top_ || (frame->sp() <= handler->address());
304 }
305 
306 
IsValidFrame(StackFrame * frame) const307 bool SafeStackFrameIterator::IsValidFrame(StackFrame* frame) const {
308   return IsValidStackAddress(frame->sp()) && IsValidStackAddress(frame->fp());
309 }
310 
311 
IsValidCaller(StackFrame * frame)312 bool SafeStackFrameIterator::IsValidCaller(StackFrame* frame) {
313   StackFrame::State state;
314   if (frame->is_entry() || frame->is_entry_construct()) {
315     // See EntryFrame::GetCallerState. It computes the caller FP address
316     // and calls ExitFrame::GetStateForFramePointer on it. We need to be
317     // sure that caller FP address is valid.
318     Address caller_fp = Memory::Address_at(
319         frame->fp() + EntryFrameConstants::kCallerFPOffset);
320     ExitFrameValidator validator(stack_validator_);
321     if (!validator.IsValidFP(caller_fp)) return false;
322   } else if (frame->is_arguments_adaptor()) {
323     // See ArgumentsAdaptorFrame::GetCallerStackPointer. It assumes that
324     // the number of arguments is stored on stack as Smi. We need to check
325     // that it really an Smi.
326     Object* number_of_args = reinterpret_cast<ArgumentsAdaptorFrame*>(frame)->
327         GetExpression(0);
328     if (!number_of_args->IsSmi()) {
329       return false;
330     }
331   }
332   frame->ComputeCallerState(&state);
333   return IsValidStackAddress(state.sp) && IsValidStackAddress(state.fp) &&
334       iterator_.SingletonFor(frame->GetCallerState(&state)) != NULL;
335 }
336 
337 
Reset()338 void SafeStackFrameIterator::Reset() {
339   if (is_working_iterator_) {
340     iterator_.Reset();
341     iteration_done_ = false;
342   }
343 }
344 
345 
346 // -------------------------------------------------------------------------
347 
348 
349 #ifdef ENABLE_LOGGING_AND_PROFILING
SafeStackTraceFrameIterator(Isolate * isolate,Address fp,Address sp,Address low_bound,Address high_bound)350 SafeStackTraceFrameIterator::SafeStackTraceFrameIterator(
351     Isolate* isolate,
352     Address fp, Address sp, Address low_bound, Address high_bound) :
353     SafeJavaScriptFrameIterator(isolate, fp, sp, low_bound, high_bound) {
354   if (!done() && !frame()->is_java_script()) Advance();
355 }
356 
357 
Advance()358 void SafeStackTraceFrameIterator::Advance() {
359   while (true) {
360     SafeJavaScriptFrameIterator::Advance();
361     if (done()) return;
362     if (frame()->is_java_script()) return;
363   }
364 }
365 #endif
366 
367 
GetSafepointData(Isolate * isolate,Address pc,SafepointEntry * safepoint_entry,unsigned * stack_slots)368 Code* StackFrame::GetSafepointData(Isolate* isolate,
369                                    Address pc,
370                                    SafepointEntry* safepoint_entry,
371                                    unsigned* stack_slots) {
372   PcToCodeCache::PcToCodeCacheEntry* entry =
373       isolate->pc_to_code_cache()->GetCacheEntry(pc);
374   SafepointEntry cached_safepoint_entry = entry->safepoint_entry;
375   if (!entry->safepoint_entry.is_valid()) {
376     entry->safepoint_entry = entry->code->GetSafepointEntry(pc);
377     ASSERT(entry->safepoint_entry.is_valid());
378   } else {
379     ASSERT(entry->safepoint_entry.Equals(entry->code->GetSafepointEntry(pc)));
380   }
381 
382   // Fill in the results and return the code.
383   Code* code = entry->code;
384   *safepoint_entry = entry->safepoint_entry;
385   *stack_slots = code->stack_slots();
386   return code;
387 }
388 
389 
HasHandler() const390 bool StackFrame::HasHandler() const {
391   StackHandlerIterator it(this, top_handler());
392   return !it.done();
393 }
394 
395 
IteratePc(ObjectVisitor * v,Address * pc_address,Code * holder)396 void StackFrame::IteratePc(ObjectVisitor* v,
397                            Address* pc_address,
398                            Code* holder) {
399   Address pc = *pc_address;
400   ASSERT(holder->contains(pc));
401   unsigned pc_offset = static_cast<unsigned>(pc - holder->instruction_start());
402   Object* code = holder;
403   v->VisitPointer(&code);
404   if (code != holder) {
405     holder = reinterpret_cast<Code*>(code);
406     pc = holder->instruction_start() + pc_offset;
407     *pc_address = pc;
408   }
409 }
410 
411 
ComputeType(Isolate * isolate,State * state)412 StackFrame::Type StackFrame::ComputeType(Isolate* isolate, State* state) {
413   ASSERT(state->fp != NULL);
414   if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
415     return ARGUMENTS_ADAPTOR;
416   }
417   // The marker and function offsets overlap. If the marker isn't a
418   // smi then the frame is a JavaScript frame -- and the marker is
419   // really the function.
420   const int offset = StandardFrameConstants::kMarkerOffset;
421   Object* marker = Memory::Object_at(state->fp + offset);
422   if (!marker->IsSmi()) {
423     // If we're using a "safe" stack iterator, we treat optimized
424     // frames as normal JavaScript frames to avoid having to look
425     // into the heap to determine the state. This is safe as long
426     // as nobody tries to GC...
427     if (SafeStackFrameIterator::is_active(isolate)) return JAVA_SCRIPT;
428     Code::Kind kind = GetContainingCode(isolate, *(state->pc_address))->kind();
429     ASSERT(kind == Code::FUNCTION || kind == Code::OPTIMIZED_FUNCTION);
430     return (kind == Code::OPTIMIZED_FUNCTION) ? OPTIMIZED : JAVA_SCRIPT;
431   }
432   return static_cast<StackFrame::Type>(Smi::cast(marker)->value());
433 }
434 
435 
436 
GetCallerState(State * state) const437 StackFrame::Type StackFrame::GetCallerState(State* state) const {
438   ComputeCallerState(state);
439   return ComputeType(isolate(), state);
440 }
441 
442 
unchecked_code() const443 Code* EntryFrame::unchecked_code() const {
444   return HEAP->raw_unchecked_js_entry_code();
445 }
446 
447 
ComputeCallerState(State * state) const448 void EntryFrame::ComputeCallerState(State* state) const {
449   GetCallerState(state);
450 }
451 
452 
SetCallerFp(Address caller_fp)453 void EntryFrame::SetCallerFp(Address caller_fp) {
454   const int offset = EntryFrameConstants::kCallerFPOffset;
455   Memory::Address_at(this->fp() + offset) = caller_fp;
456 }
457 
458 
GetCallerState(State * state) const459 StackFrame::Type EntryFrame::GetCallerState(State* state) const {
460   const int offset = EntryFrameConstants::kCallerFPOffset;
461   Address fp = Memory::Address_at(this->fp() + offset);
462   return ExitFrame::GetStateForFramePointer(fp, state);
463 }
464 
465 
unchecked_code() const466 Code* EntryConstructFrame::unchecked_code() const {
467   return HEAP->raw_unchecked_js_construct_entry_code();
468 }
469 
470 
code_slot() const471 Object*& ExitFrame::code_slot() const {
472   const int offset = ExitFrameConstants::kCodeOffset;
473   return Memory::Object_at(fp() + offset);
474 }
475 
476 
unchecked_code() const477 Code* ExitFrame::unchecked_code() const {
478   return reinterpret_cast<Code*>(code_slot());
479 }
480 
481 
ComputeCallerState(State * state) const482 void ExitFrame::ComputeCallerState(State* state) const {
483   // Setup the caller state.
484   state->sp = caller_sp();
485   state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset);
486   state->pc_address
487       = reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset);
488 }
489 
490 
SetCallerFp(Address caller_fp)491 void ExitFrame::SetCallerFp(Address caller_fp) {
492   Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset) = caller_fp;
493 }
494 
495 
Iterate(ObjectVisitor * v) const496 void ExitFrame::Iterate(ObjectVisitor* v) const {
497   // The arguments are traversed as part of the expression stack of
498   // the calling frame.
499   IteratePc(v, pc_address(), LookupCode());
500   v->VisitPointer(&code_slot());
501 }
502 
503 
GetCallerStackPointer() const504 Address ExitFrame::GetCallerStackPointer() const {
505   return fp() + ExitFrameConstants::kCallerSPDisplacement;
506 }
507 
508 
GetStateForFramePointer(Address fp,State * state)509 StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
510   if (fp == 0) return NONE;
511   Address sp = ComputeStackPointer(fp);
512   FillState(fp, sp, state);
513   ASSERT(*state->pc_address != NULL);
514   return EXIT;
515 }
516 
517 
FillState(Address fp,Address sp,State * state)518 void ExitFrame::FillState(Address fp, Address sp, State* state) {
519   state->sp = sp;
520   state->fp = fp;
521   state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize);
522 }
523 
524 
GetExpressionAddress(int n) const525 Address StandardFrame::GetExpressionAddress(int n) const {
526   const int offset = StandardFrameConstants::kExpressionsOffset;
527   return fp() + offset - n * kPointerSize;
528 }
529 
530 
ComputeExpressionsCount() const531 int StandardFrame::ComputeExpressionsCount() const {
532   const int offset =
533       StandardFrameConstants::kExpressionsOffset + kPointerSize;
534   Address base = fp() + offset;
535   Address limit = sp();
536   ASSERT(base >= limit);  // stack grows downwards
537   // Include register-allocated locals in number of expressions.
538   return static_cast<int>((base - limit) / kPointerSize);
539 }
540 
541 
ComputeCallerState(State * state) const542 void StandardFrame::ComputeCallerState(State* state) const {
543   state->sp = caller_sp();
544   state->fp = caller_fp();
545   state->pc_address = reinterpret_cast<Address*>(ComputePCAddress(fp()));
546 }
547 
548 
SetCallerFp(Address caller_fp)549 void StandardFrame::SetCallerFp(Address caller_fp) {
550   Memory::Address_at(fp() + StandardFrameConstants::kCallerFPOffset) =
551       caller_fp;
552 }
553 
554 
IsExpressionInsideHandler(int n) const555 bool StandardFrame::IsExpressionInsideHandler(int n) const {
556   Address address = GetExpressionAddress(n);
557   for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
558     if (it.handler()->includes(address)) return true;
559   }
560   return false;
561 }
562 
563 
Iterate(ObjectVisitor * v) const564 void OptimizedFrame::Iterate(ObjectVisitor* v) const {
565 #ifdef DEBUG
566   // Make sure that optimized frames do not contain any stack handlers.
567   StackHandlerIterator it(this, top_handler());
568   ASSERT(it.done());
569 #endif
570 
571   // Make sure that we're not doing "safe" stack frame iteration. We cannot
572   // possibly find pointers in optimized frames in that state.
573   ASSERT(!SafeStackFrameIterator::is_active(isolate()));
574 
575   // Compute the safepoint information.
576   unsigned stack_slots = 0;
577   SafepointEntry safepoint_entry;
578   Code* code = StackFrame::GetSafepointData(
579       isolate(), pc(), &safepoint_entry, &stack_slots);
580   unsigned slot_space = stack_slots * kPointerSize;
581 
582   // Visit the outgoing parameters.
583   Object** parameters_base = &Memory::Object_at(sp());
584   Object** parameters_limit = &Memory::Object_at(
585       fp() + JavaScriptFrameConstants::kFunctionOffset - slot_space);
586 
587   // Visit the parameters that may be on top of the saved registers.
588   if (safepoint_entry.argument_count() > 0) {
589     v->VisitPointers(parameters_base,
590                      parameters_base + safepoint_entry.argument_count());
591     parameters_base += safepoint_entry.argument_count();
592   }
593 
594   // Skip saved double registers.
595   if (safepoint_entry.has_doubles()) {
596     parameters_base += DoubleRegister::kNumAllocatableRegisters *
597         kDoubleSize / kPointerSize;
598   }
599 
600   // Visit the registers that contain pointers if any.
601   if (safepoint_entry.HasRegisters()) {
602     for (int i = kNumSafepointRegisters - 1; i >=0; i--) {
603       if (safepoint_entry.HasRegisterAt(i)) {
604         int reg_stack_index = MacroAssembler::SafepointRegisterStackIndex(i);
605         v->VisitPointer(parameters_base + reg_stack_index);
606       }
607     }
608     // Skip the words containing the register values.
609     parameters_base += kNumSafepointRegisters;
610   }
611 
612   // We're done dealing with the register bits.
613   uint8_t* safepoint_bits = safepoint_entry.bits();
614   safepoint_bits += kNumSafepointRegisters >> kBitsPerByteLog2;
615 
616   // Visit the rest of the parameters.
617   v->VisitPointers(parameters_base, parameters_limit);
618 
619   // Visit pointer spill slots and locals.
620   for (unsigned index = 0; index < stack_slots; index++) {
621     int byte_index = index >> kBitsPerByteLog2;
622     int bit_index = index & (kBitsPerByte - 1);
623     if ((safepoint_bits[byte_index] & (1U << bit_index)) != 0) {
624       v->VisitPointer(parameters_limit + index);
625     }
626   }
627 
628   // Visit the context and the function.
629   Object** fixed_base = &Memory::Object_at(
630       fp() + JavaScriptFrameConstants::kFunctionOffset);
631   Object** fixed_limit = &Memory::Object_at(fp());
632   v->VisitPointers(fixed_base, fixed_limit);
633 
634   // Visit the return address in the callee and incoming arguments.
635   IteratePc(v, pc_address(), code);
636 }
637 
638 
IsConstructor() const639 bool JavaScriptFrame::IsConstructor() const {
640   Address fp = caller_fp();
641   if (has_adapted_arguments()) {
642     // Skip the arguments adaptor frame and look at the real caller.
643     fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
644   }
645   return IsConstructFrame(fp);
646 }
647 
648 
unchecked_code() const649 Code* JavaScriptFrame::unchecked_code() const {
650   JSFunction* function = JSFunction::cast(this->function());
651   return function->unchecked_code();
652 }
653 
654 
GetNumberOfIncomingArguments() const655 int JavaScriptFrame::GetNumberOfIncomingArguments() const {
656   ASSERT(!SafeStackFrameIterator::is_active(isolate()) &&
657          isolate()->heap()->gc_state() == Heap::NOT_IN_GC);
658 
659   JSFunction* function = JSFunction::cast(this->function());
660   return function->shared()->formal_parameter_count();
661 }
662 
663 
GetCallerStackPointer() const664 Address JavaScriptFrame::GetCallerStackPointer() const {
665   return fp() + StandardFrameConstants::kCallerSPOffset;
666 }
667 
668 
GetFunctions(List<JSFunction * > * functions)669 void JavaScriptFrame::GetFunctions(List<JSFunction*>* functions) {
670   ASSERT(functions->length() == 0);
671   functions->Add(JSFunction::cast(function()));
672 }
673 
674 
Summarize(List<FrameSummary> * functions)675 void JavaScriptFrame::Summarize(List<FrameSummary>* functions) {
676   ASSERT(functions->length() == 0);
677   Code* code_pointer = LookupCode();
678   int offset = static_cast<int>(pc() - code_pointer->address());
679   FrameSummary summary(receiver(),
680                        JSFunction::cast(function()),
681                        code_pointer,
682                        offset,
683                        IsConstructor());
684   functions->Add(summary);
685 }
686 
687 
Print()688 void FrameSummary::Print() {
689   PrintF("receiver: ");
690   receiver_->ShortPrint();
691   PrintF("\nfunction: ");
692   function_->shared()->DebugName()->ShortPrint();
693   PrintF("\ncode: ");
694   code_->ShortPrint();
695   if (code_->kind() == Code::FUNCTION) PrintF(" NON-OPT");
696   if (code_->kind() == Code::OPTIMIZED_FUNCTION) PrintF(" OPT");
697   PrintF("\npc: %d\n", offset_);
698 }
699 
700 
Summarize(List<FrameSummary> * frames)701 void OptimizedFrame::Summarize(List<FrameSummary>* frames) {
702   ASSERT(frames->length() == 0);
703   ASSERT(is_optimized());
704 
705   int deopt_index = Safepoint::kNoDeoptimizationIndex;
706   DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
707 
708   // BUG(3243555): Since we don't have a lazy-deopt registered at
709   // throw-statements, we can't use the translation at the call-site of
710   // throw. An entry with no deoptimization index indicates a call-site
711   // without a lazy-deopt. As a consequence we are not allowed to inline
712   // functions containing throw.
713   if (deopt_index == Safepoint::kNoDeoptimizationIndex) {
714     JavaScriptFrame::Summarize(frames);
715     return;
716   }
717 
718   TranslationIterator it(data->TranslationByteArray(),
719                          data->TranslationIndex(deopt_index)->value());
720   Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
721   ASSERT(opcode == Translation::BEGIN);
722   int frame_count = it.Next();
723 
724   // We create the summary in reverse order because the frames
725   // in the deoptimization translation are ordered bottom-to-top.
726   int i = frame_count;
727   while (i > 0) {
728     opcode = static_cast<Translation::Opcode>(it.Next());
729     if (opcode == Translation::FRAME) {
730       // We don't inline constructor calls, so only the first, outermost
731       // frame can be a constructor frame in case of inlining.
732       bool is_constructor = (i == frame_count) && IsConstructor();
733 
734       i--;
735       int ast_id = it.Next();
736       int function_id = it.Next();
737       it.Next();  // Skip height.
738       JSFunction* function =
739           JSFunction::cast(data->LiteralArray()->get(function_id));
740 
741       // The translation commands are ordered and the receiver is always
742       // at the first position. Since we are always at a call when we need
743       // to construct a stack trace, the receiver is always in a stack slot.
744       opcode = static_cast<Translation::Opcode>(it.Next());
745       ASSERT(opcode == Translation::STACK_SLOT);
746       int input_slot_index = it.Next();
747 
748       // Get the correct receiver in the optimized frame.
749       Object* receiver = NULL;
750       // Positive index means the value is spilled to the locals area. Negative
751       // means it is stored in the incoming parameter area.
752       if (input_slot_index >= 0) {
753         receiver = GetExpression(input_slot_index);
754       } else {
755         // Index -1 overlaps with last parameter, -n with the first parameter,
756         // (-n - 1) with the receiver with n being the number of parameters
757         // of the outermost, optimized frame.
758         int parameter_count = ComputeParametersCount();
759         int parameter_index = input_slot_index + parameter_count;
760         receiver = (parameter_index == -1)
761             ? this->receiver()
762             : this->GetParameter(parameter_index);
763       }
764 
765       Code* code = function->shared()->code();
766       DeoptimizationOutputData* output_data =
767           DeoptimizationOutputData::cast(code->deoptimization_data());
768       unsigned entry = Deoptimizer::GetOutputInfo(output_data,
769                                                   ast_id,
770                                                   function->shared());
771       unsigned pc_offset =
772           FullCodeGenerator::PcField::decode(entry) + Code::kHeaderSize;
773       ASSERT(pc_offset > 0);
774 
775       FrameSummary summary(receiver, function, code, pc_offset, is_constructor);
776       frames->Add(summary);
777     } else {
778       // Skip over operands to advance to the next opcode.
779       it.Skip(Translation::NumberOfOperandsFor(opcode));
780     }
781   }
782 }
783 
784 
GetDeoptimizationData(int * deopt_index)785 DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData(
786     int* deopt_index) {
787   ASSERT(is_optimized());
788 
789   JSFunction* opt_function = JSFunction::cast(function());
790   Code* code = opt_function->code();
791 
792   // The code object may have been replaced by lazy deoptimization. Fall
793   // back to a slow search in this case to find the original optimized
794   // code object.
795   if (!code->contains(pc())) {
796     code = isolate()->pc_to_code_cache()->GcSafeFindCodeForPc(pc());
797   }
798   ASSERT(code != NULL);
799   ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
800 
801   SafepointEntry safepoint_entry = code->GetSafepointEntry(pc());
802   *deopt_index = safepoint_entry.deoptimization_index();
803   ASSERT(*deopt_index != Safepoint::kNoDeoptimizationIndex);
804 
805   return DeoptimizationInputData::cast(code->deoptimization_data());
806 }
807 
808 
GetFunctions(List<JSFunction * > * functions)809 void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) {
810   ASSERT(functions->length() == 0);
811   ASSERT(is_optimized());
812 
813   int deopt_index = Safepoint::kNoDeoptimizationIndex;
814   DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index);
815 
816   TranslationIterator it(data->TranslationByteArray(),
817                          data->TranslationIndex(deopt_index)->value());
818   Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
819   ASSERT(opcode == Translation::BEGIN);
820   int frame_count = it.Next();
821 
822   // We insert the frames in reverse order because the frames
823   // in the deoptimization translation are ordered bottom-to-top.
824   while (frame_count > 0) {
825     opcode = static_cast<Translation::Opcode>(it.Next());
826     if (opcode == Translation::FRAME) {
827       frame_count--;
828       it.Next();  // Skip ast id.
829       int function_id = it.Next();
830       it.Next();  // Skip height.
831       JSFunction* function =
832           JSFunction::cast(data->LiteralArray()->get(function_id));
833       functions->Add(function);
834     } else {
835       // Skip over operands to advance to the next opcode.
836       it.Skip(Translation::NumberOfOperandsFor(opcode));
837     }
838   }
839 }
840 
841 
GetCallerStackPointer() const842 Address ArgumentsAdaptorFrame::GetCallerStackPointer() const {
843   return fp() + StandardFrameConstants::kCallerSPOffset;
844 }
845 
846 
GetCallerStackPointer() const847 Address InternalFrame::GetCallerStackPointer() const {
848   // Internal frames have no arguments. The stack pointer of the
849   // caller is at a fixed offset from the frame pointer.
850   return fp() + StandardFrameConstants::kCallerSPOffset;
851 }
852 
853 
unchecked_code() const854 Code* ArgumentsAdaptorFrame::unchecked_code() const {
855   return isolate()->builtins()->builtin(
856       Builtins::kArgumentsAdaptorTrampoline);
857 }
858 
859 
unchecked_code() const860 Code* InternalFrame::unchecked_code() const {
861   const int offset = InternalFrameConstants::kCodeOffset;
862   Object* code = Memory::Object_at(fp() + offset);
863   ASSERT(code != NULL);
864   return reinterpret_cast<Code*>(code);
865 }
866 
867 
PrintIndex(StringStream * accumulator,PrintMode mode,int index)868 void StackFrame::PrintIndex(StringStream* accumulator,
869                             PrintMode mode,
870                             int index) {
871   accumulator->Add((mode == OVERVIEW) ? "%5d: " : "[%d]: ", index);
872 }
873 
874 
Print(StringStream * accumulator,PrintMode mode,int index) const875 void JavaScriptFrame::Print(StringStream* accumulator,
876                             PrintMode mode,
877                             int index) const {
878   HandleScope scope;
879   Object* receiver = this->receiver();
880   Object* function = this->function();
881 
882   accumulator->PrintSecurityTokenIfChanged(function);
883   PrintIndex(accumulator, mode, index);
884   Code* code = NULL;
885   if (IsConstructor()) accumulator->Add("new ");
886   accumulator->PrintFunction(function, receiver, &code);
887 
888   Handle<SerializedScopeInfo> scope_info(SerializedScopeInfo::Empty());
889 
890   if (function->IsJSFunction()) {
891     Handle<SharedFunctionInfo> shared(JSFunction::cast(function)->shared());
892     scope_info = Handle<SerializedScopeInfo>(shared->scope_info());
893     Object* script_obj = shared->script();
894     if (script_obj->IsScript()) {
895       Handle<Script> script(Script::cast(script_obj));
896       accumulator->Add(" [");
897       accumulator->PrintName(script->name());
898 
899       Address pc = this->pc();
900       if (code != NULL && code->kind() == Code::FUNCTION &&
901           pc >= code->instruction_start() && pc < code->instruction_end()) {
902         int source_pos = code->SourcePosition(pc);
903         int line = GetScriptLineNumberSafe(script, source_pos) + 1;
904         accumulator->Add(":%d", line);
905       } else {
906         int function_start_pos = shared->start_position();
907         int line = GetScriptLineNumberSafe(script, function_start_pos) + 1;
908         accumulator->Add(":~%d", line);
909       }
910 
911       accumulator->Add("] ");
912     }
913   }
914 
915   accumulator->Add("(this=%o", receiver);
916 
917   // Get scope information for nicer output, if possible. If code is
918   // NULL, or doesn't contain scope info, info will return 0 for the
919   // number of parameters, stack slots, or context slots.
920   ScopeInfo<PreallocatedStorage> info(*scope_info);
921 
922   // Print the parameters.
923   int parameters_count = ComputeParametersCount();
924   for (int i = 0; i < parameters_count; i++) {
925     accumulator->Add(",");
926     // If we have a name for the parameter we print it. Nameless
927     // parameters are either because we have more actual parameters
928     // than formal parameters or because we have no scope information.
929     if (i < info.number_of_parameters()) {
930       accumulator->PrintName(*info.parameter_name(i));
931       accumulator->Add("=");
932     }
933     accumulator->Add("%o", GetParameter(i));
934   }
935 
936   accumulator->Add(")");
937   if (mode == OVERVIEW) {
938     accumulator->Add("\n");
939     return;
940   }
941   accumulator->Add(" {\n");
942 
943   // Compute the number of locals and expression stack elements.
944   int stack_locals_count = info.number_of_stack_slots();
945   int heap_locals_count = info.number_of_context_slots();
946   int expressions_count = ComputeExpressionsCount();
947 
948   // Print stack-allocated local variables.
949   if (stack_locals_count > 0) {
950     accumulator->Add("  // stack-allocated locals\n");
951   }
952   for (int i = 0; i < stack_locals_count; i++) {
953     accumulator->Add("  var ");
954     accumulator->PrintName(*info.stack_slot_name(i));
955     accumulator->Add(" = ");
956     if (i < expressions_count) {
957       accumulator->Add("%o", GetExpression(i));
958     } else {
959       accumulator->Add("// no expression found - inconsistent frame?");
960     }
961     accumulator->Add("\n");
962   }
963 
964   // Try to get hold of the context of this frame.
965   Context* context = NULL;
966   if (this->context() != NULL && this->context()->IsContext()) {
967     context = Context::cast(this->context());
968   }
969 
970   // Print heap-allocated local variables.
971   if (heap_locals_count > Context::MIN_CONTEXT_SLOTS) {
972     accumulator->Add("  // heap-allocated locals\n");
973   }
974   for (int i = Context::MIN_CONTEXT_SLOTS; i < heap_locals_count; i++) {
975     accumulator->Add("  var ");
976     accumulator->PrintName(*info.context_slot_name(i));
977     accumulator->Add(" = ");
978     if (context != NULL) {
979       if (i < context->length()) {
980         accumulator->Add("%o", context->get(i));
981       } else {
982         accumulator->Add(
983             "// warning: missing context slot - inconsistent frame?");
984       }
985     } else {
986       accumulator->Add("// warning: no context found - inconsistent frame?");
987     }
988     accumulator->Add("\n");
989   }
990 
991   // Print the expression stack.
992   int expressions_start = stack_locals_count;
993   if (expressions_start < expressions_count) {
994     accumulator->Add("  // expression stack (top to bottom)\n");
995   }
996   for (int i = expressions_count - 1; i >= expressions_start; i--) {
997     if (IsExpressionInsideHandler(i)) continue;
998     accumulator->Add("  [%02d] : %o\n", i, GetExpression(i));
999   }
1000 
1001   // Print details about the function.
1002   if (FLAG_max_stack_trace_source_length != 0 && code != NULL) {
1003     SharedFunctionInfo* shared = JSFunction::cast(function)->shared();
1004     accumulator->Add("--------- s o u r c e   c o d e ---------\n");
1005     shared->SourceCodePrint(accumulator, FLAG_max_stack_trace_source_length);
1006     accumulator->Add("\n-----------------------------------------\n");
1007   }
1008 
1009   accumulator->Add("}\n\n");
1010 }
1011 
1012 
Print(StringStream * accumulator,PrintMode mode,int index) const1013 void ArgumentsAdaptorFrame::Print(StringStream* accumulator,
1014                                   PrintMode mode,
1015                                   int index) const {
1016   int actual = ComputeParametersCount();
1017   int expected = -1;
1018   Object* function = this->function();
1019   if (function->IsJSFunction()) {
1020     expected = JSFunction::cast(function)->shared()->formal_parameter_count();
1021   }
1022 
1023   PrintIndex(accumulator, mode, index);
1024   accumulator->Add("arguments adaptor frame: %d->%d", actual, expected);
1025   if (mode == OVERVIEW) {
1026     accumulator->Add("\n");
1027     return;
1028   }
1029   accumulator->Add(" {\n");
1030 
1031   // Print actual arguments.
1032   if (actual > 0) accumulator->Add("  // actual arguments\n");
1033   for (int i = 0; i < actual; i++) {
1034     accumulator->Add("  [%02d] : %o", i, GetParameter(i));
1035     if (expected != -1 && i >= expected) {
1036       accumulator->Add("  // not passed to callee");
1037     }
1038     accumulator->Add("\n");
1039   }
1040 
1041   accumulator->Add("}\n\n");
1042 }
1043 
1044 
Iterate(ObjectVisitor * v) const1045 void EntryFrame::Iterate(ObjectVisitor* v) const {
1046   StackHandlerIterator it(this, top_handler());
1047   ASSERT(!it.done());
1048   StackHandler* handler = it.handler();
1049   ASSERT(handler->is_entry());
1050   handler->Iterate(v, LookupCode());
1051 #ifdef DEBUG
1052   // Make sure that the entry frame does not contain more than one
1053   // stack handler.
1054   it.Advance();
1055   ASSERT(it.done());
1056 #endif
1057   IteratePc(v, pc_address(), LookupCode());
1058 }
1059 
1060 
IterateExpressions(ObjectVisitor * v) const1061 void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
1062   const int offset = StandardFrameConstants::kContextOffset;
1063   Object** base = &Memory::Object_at(sp());
1064   Object** limit = &Memory::Object_at(fp() + offset) + 1;
1065   for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
1066     StackHandler* handler = it.handler();
1067     // Traverse pointers down to - but not including - the next
1068     // handler in the handler chain. Update the base to skip the
1069     // handler and allow the handler to traverse its own pointers.
1070     const Address address = handler->address();
1071     v->VisitPointers(base, reinterpret_cast<Object**>(address));
1072     base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize);
1073     // Traverse the pointers in the handler itself.
1074     handler->Iterate(v, LookupCode());
1075   }
1076   v->VisitPointers(base, limit);
1077 }
1078 
1079 
Iterate(ObjectVisitor * v) const1080 void JavaScriptFrame::Iterate(ObjectVisitor* v) const {
1081   IterateExpressions(v);
1082   IteratePc(v, pc_address(), LookupCode());
1083 }
1084 
1085 
Iterate(ObjectVisitor * v) const1086 void InternalFrame::Iterate(ObjectVisitor* v) const {
1087   // Internal frames only have object pointers on the expression stack
1088   // as they never have any arguments.
1089   IterateExpressions(v);
1090   IteratePc(v, pc_address(), LookupCode());
1091 }
1092 
1093 
1094 // -------------------------------------------------------------------------
1095 
1096 
FindJavaScriptFrame(int n)1097 JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) {
1098   ASSERT(n >= 0);
1099   for (int i = 0; i <= n; i++) {
1100     while (!iterator_.frame()->is_java_script()) iterator_.Advance();
1101     if (i == n) return JavaScriptFrame::cast(iterator_.frame());
1102     iterator_.Advance();
1103   }
1104   UNREACHABLE();
1105   return NULL;
1106 }
1107 
1108 
1109 // -------------------------------------------------------------------------
1110 
1111 
GcSafeCastToCode(HeapObject * object,Address pc)1112 Code* PcToCodeCache::GcSafeCastToCode(HeapObject* object, Address pc) {
1113   Code* code = reinterpret_cast<Code*>(object);
1114   ASSERT(code != NULL && code->contains(pc));
1115   return code;
1116 }
1117 
1118 
GcSafeFindCodeForPc(Address pc)1119 Code* PcToCodeCache::GcSafeFindCodeForPc(Address pc) {
1120   Heap* heap = isolate_->heap();
1121   // Check if the pc points into a large object chunk.
1122   LargeObjectChunk* chunk = heap->lo_space()->FindChunkContainingPc(pc);
1123   if (chunk != NULL) return GcSafeCastToCode(chunk->GetObject(), pc);
1124 
1125   // Iterate through the 8K page until we reach the end or find an
1126   // object starting after the pc.
1127   Page* page = Page::FromAddress(pc);
1128   HeapObjectIterator iterator(page, heap->GcSafeSizeOfOldObjectFunction());
1129   HeapObject* previous = NULL;
1130   while (true) {
1131     HeapObject* next = iterator.next();
1132     if (next == NULL || next->address() >= pc) {
1133       return GcSafeCastToCode(previous, pc);
1134     }
1135     previous = next;
1136   }
1137 }
1138 
1139 
GetCacheEntry(Address pc)1140 PcToCodeCache::PcToCodeCacheEntry* PcToCodeCache::GetCacheEntry(Address pc) {
1141   isolate_->counters()->pc_to_code()->Increment();
1142   ASSERT(IsPowerOf2(kPcToCodeCacheSize));
1143   uint32_t hash = ComputeIntegerHash(
1144       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(pc)));
1145   uint32_t index = hash & (kPcToCodeCacheSize - 1);
1146   PcToCodeCacheEntry* entry = cache(index);
1147   if (entry->pc == pc) {
1148     isolate_->counters()->pc_to_code_cached()->Increment();
1149     ASSERT(entry->code == GcSafeFindCodeForPc(pc));
1150   } else {
1151     // Because this code may be interrupted by a profiling signal that
1152     // also queries the cache, we cannot update pc before the code has
1153     // been set. Otherwise, we risk trying to use a cache entry before
1154     // the code has been computed.
1155     entry->code = GcSafeFindCodeForPc(pc);
1156     entry->safepoint_entry.Reset();
1157     entry->pc = pc;
1158   }
1159   return entry;
1160 }
1161 
1162 
1163 // -------------------------------------------------------------------------
1164 
NumRegs(RegList reglist)1165 int NumRegs(RegList reglist) {
1166   int n = 0;
1167   while (reglist != 0) {
1168     n++;
1169     reglist &= reglist - 1;  // clear one bit
1170   }
1171   return n;
1172 }
1173 
1174 
1175 struct JSCallerSavedCodeData {
JSCallerSavedCodeDatav8::internal::JSCallerSavedCodeData1176   JSCallerSavedCodeData() {
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   int reg_code[kNumJSCallerSaved];
1185 };
1186 
1187 
1188 static const JSCallerSavedCodeData kCallerSavedCodeData;
1189 
1190 
JSCallerSavedCode(int n)1191 int JSCallerSavedCode(int n) {
1192   ASSERT(0 <= n && n < kNumJSCallerSaved);
1193   return kCallerSavedCodeData.reg_code[n];
1194 }
1195 
1196 
1197 #define DEFINE_WRAPPER(type, field)                              \
1198 class field##_Wrapper : public ZoneObject {                      \
1199  public:  /* NOLINT */                                           \
1200   field##_Wrapper(const field& original) : frame_(original) {    \
1201   }                                                              \
1202   field frame_;                                                  \
1203 };
STACK_FRAME_TYPE_LIST(DEFINE_WRAPPER)1204 STACK_FRAME_TYPE_LIST(DEFINE_WRAPPER)
1205 #undef DEFINE_WRAPPER
1206 
1207 static StackFrame* AllocateFrameCopy(StackFrame* frame) {
1208 #define FRAME_TYPE_CASE(type, field) \
1209   case StackFrame::type: { \
1210     field##_Wrapper* wrapper = \
1211         new field##_Wrapper(*(reinterpret_cast<field*>(frame))); \
1212     return &wrapper->frame_; \
1213   }
1214 
1215   switch (frame->type()) {
1216     STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
1217     default: UNREACHABLE();
1218   }
1219 #undef FRAME_TYPE_CASE
1220   return NULL;
1221 }
1222 
CreateStackMap()1223 Vector<StackFrame*> CreateStackMap() {
1224   ZoneList<StackFrame*> list(10);
1225   for (StackFrameIterator it; !it.done(); it.Advance()) {
1226     StackFrame* frame = AllocateFrameCopy(it.frame());
1227     list.Add(frame);
1228   }
1229   return list.ToVector();
1230 }
1231 
1232 
1233 } }  // namespace v8::internal
1234