1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/frames.h"
6
7 #include <memory>
8 #include <sstream>
9
10 #include "src/base/bits.h"
11 #include "src/deoptimizer.h"
12 #include "src/frames-inl.h"
13 #include "src/full-codegen/full-codegen.h"
14 #include "src/ic/ic-stats.h"
15 #include "src/register-configuration.h"
16 #include "src/safepoint-table.h"
17 #include "src/string-stream.h"
18 #include "src/vm-state-inl.h"
19 #include "src/wasm/wasm-module.h"
20 #include "src/wasm/wasm-objects.h"
21
22 namespace v8 {
23 namespace internal {
24
25 ReturnAddressLocationResolver
26 StackFrame::return_address_location_resolver_ = NULL;
27
28
29 // Iterator that supports traversing the stack handlers of a
30 // particular frame. Needs to know the top of the handler chain.
31 class StackHandlerIterator BASE_EMBEDDED {
32 public:
StackHandlerIterator(const StackFrame * frame,StackHandler * handler)33 StackHandlerIterator(const StackFrame* frame, StackHandler* handler)
34 : limit_(frame->fp()), handler_(handler) {
35 // Make sure the handler has already been unwound to this frame.
36 DCHECK(frame->sp() <= handler->address());
37 }
38
handler() const39 StackHandler* handler() const { return handler_; }
40
done()41 bool done() {
42 return handler_ == NULL || handler_->address() > limit_;
43 }
Advance()44 void Advance() {
45 DCHECK(!done());
46 handler_ = handler_->next();
47 }
48
49 private:
50 const Address limit_;
51 StackHandler* handler_;
52 };
53
54
55 // -------------------------------------------------------------------------
56
57
58 #define INITIALIZE_SINGLETON(type, field) field##_(this),
StackFrameIteratorBase(Isolate * isolate,bool can_access_heap_objects)59 StackFrameIteratorBase::StackFrameIteratorBase(Isolate* isolate,
60 bool can_access_heap_objects)
61 : isolate_(isolate),
62 STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON)
63 frame_(NULL), handler_(NULL),
64 can_access_heap_objects_(can_access_heap_objects) {
65 }
66 #undef INITIALIZE_SINGLETON
67
StackFrameIterator(Isolate * isolate)68 StackFrameIterator::StackFrameIterator(Isolate* isolate)
69 : StackFrameIterator(isolate, isolate->thread_local_top()) {}
70
StackFrameIterator(Isolate * isolate,ThreadLocalTop * t)71 StackFrameIterator::StackFrameIterator(Isolate* isolate, ThreadLocalTop* t)
72 : StackFrameIteratorBase(isolate, true) {
73 Reset(t);
74 }
75
Advance()76 void StackFrameIterator::Advance() {
77 DCHECK(!done());
78 // Compute the state of the calling frame before restoring
79 // callee-saved registers and unwinding handlers. This allows the
80 // frame code that computes the caller state to access the top
81 // handler and the value of any callee-saved register if needed.
82 StackFrame::State state;
83 StackFrame::Type type = frame_->GetCallerState(&state);
84
85 // Unwind handlers corresponding to the current frame.
86 StackHandlerIterator it(frame_, handler_);
87 while (!it.done()) it.Advance();
88 handler_ = it.handler();
89
90 // Advance to the calling frame.
91 frame_ = SingletonFor(type, &state);
92
93 // When we're done iterating over the stack frames, the handler
94 // chain must have been completely unwound.
95 DCHECK(!done() || handler_ == NULL);
96 }
97
98
Reset(ThreadLocalTop * top)99 void StackFrameIterator::Reset(ThreadLocalTop* top) {
100 StackFrame::State state;
101 StackFrame::Type type = ExitFrame::GetStateForFramePointer(
102 Isolate::c_entry_fp(top), &state);
103 handler_ = StackHandler::FromAddress(Isolate::handler(top));
104 frame_ = SingletonFor(type, &state);
105 }
106
107
SingletonFor(StackFrame::Type type,StackFrame::State * state)108 StackFrame* StackFrameIteratorBase::SingletonFor(StackFrame::Type type,
109 StackFrame::State* state) {
110 StackFrame* result = SingletonFor(type);
111 DCHECK((!result) == (type == StackFrame::NONE));
112 if (result) result->state_ = *state;
113 return result;
114 }
115
116
SingletonFor(StackFrame::Type type)117 StackFrame* StackFrameIteratorBase::SingletonFor(StackFrame::Type type) {
118 #define FRAME_TYPE_CASE(type, field) \
119 case StackFrame::type: \
120 return &field##_;
121
122 switch (type) {
123 case StackFrame::NONE: return NULL;
124 STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
125 default: break;
126 }
127 return NULL;
128
129 #undef FRAME_TYPE_CASE
130 }
131
132 // -------------------------------------------------------------------------
133
Advance()134 void JavaScriptFrameIterator::Advance() {
135 do {
136 iterator_.Advance();
137 } while (!iterator_.done() && !iterator_.frame()->is_java_script());
138 }
139
140
AdvanceToArgumentsFrame()141 void JavaScriptFrameIterator::AdvanceToArgumentsFrame() {
142 if (!frame()->has_adapted_arguments()) return;
143 iterator_.Advance();
144 DCHECK(iterator_.frame()->is_arguments_adaptor());
145 }
146
147
148 // -------------------------------------------------------------------------
149
StackTraceFrameIterator(Isolate * isolate)150 StackTraceFrameIterator::StackTraceFrameIterator(Isolate* isolate)
151 : iterator_(isolate) {
152 if (!done() && !IsValidFrame(iterator_.frame())) Advance();
153 }
154
StackTraceFrameIterator(Isolate * isolate,StackFrame::Id id)155 StackTraceFrameIterator::StackTraceFrameIterator(Isolate* isolate,
156 StackFrame::Id id)
157 : StackTraceFrameIterator(isolate) {
158 while (!done() && frame()->id() != id) Advance();
159 }
160
Advance()161 void StackTraceFrameIterator::Advance() {
162 do {
163 iterator_.Advance();
164 } while (!done() && !IsValidFrame(iterator_.frame()));
165 }
166
IsValidFrame(StackFrame * frame) const167 bool StackTraceFrameIterator::IsValidFrame(StackFrame* frame) const {
168 if (frame->is_java_script()) {
169 JavaScriptFrame* jsFrame = static_cast<JavaScriptFrame*>(frame);
170 if (!jsFrame->function()->IsJSFunction()) return false;
171 return jsFrame->function()->shared()->IsSubjectToDebugging();
172 }
173 // apart from javascript, only wasm is valid
174 return frame->is_wasm();
175 }
176
AdvanceToArgumentsFrame()177 void StackTraceFrameIterator::AdvanceToArgumentsFrame() {
178 if (!is_javascript() || !javascript_frame()->has_adapted_arguments()) return;
179 iterator_.Advance();
180 DCHECK(iterator_.frame()->is_arguments_adaptor());
181 }
182
183 // -------------------------------------------------------------------------
184
185 namespace {
186
IsInterpreterFramePc(Isolate * isolate,Address pc)187 bool IsInterpreterFramePc(Isolate* isolate, Address pc) {
188 Code* interpreter_entry_trampoline =
189 isolate->builtins()->builtin(Builtins::kInterpreterEntryTrampoline);
190 Code* interpreter_bytecode_advance =
191 isolate->builtins()->builtin(Builtins::kInterpreterEnterBytecodeAdvance);
192 Code* interpreter_bytecode_dispatch =
193 isolate->builtins()->builtin(Builtins::kInterpreterEnterBytecodeDispatch);
194
195 return (pc >= interpreter_entry_trampoline->instruction_start() &&
196 pc < interpreter_entry_trampoline->instruction_end()) ||
197 (pc >= interpreter_bytecode_advance->instruction_start() &&
198 pc < interpreter_bytecode_advance->instruction_end()) ||
199 (pc >= interpreter_bytecode_dispatch->instruction_start() &&
200 pc < interpreter_bytecode_dispatch->instruction_end());
201 }
202
ReadMemoryAt(Address address)203 DISABLE_ASAN Address ReadMemoryAt(Address address) {
204 return Memory::Address_at(address);
205 }
206
207 } // namespace
208
SafeStackFrameIterator(Isolate * isolate,Address fp,Address sp,Address js_entry_sp)209 SafeStackFrameIterator::SafeStackFrameIterator(
210 Isolate* isolate,
211 Address fp, Address sp, Address js_entry_sp)
212 : StackFrameIteratorBase(isolate, false),
213 low_bound_(sp),
214 high_bound_(js_entry_sp),
215 top_frame_type_(StackFrame::NONE),
216 external_callback_scope_(isolate->external_callback_scope()) {
217 StackFrame::State state;
218 StackFrame::Type type;
219 ThreadLocalTop* top = isolate->thread_local_top();
220 bool advance_frame = true;
221 if (IsValidTop(top)) {
222 type = ExitFrame::GetStateForFramePointer(Isolate::c_entry_fp(top), &state);
223 top_frame_type_ = type;
224 } else if (IsValidStackAddress(fp)) {
225 DCHECK(fp != NULL);
226 state.fp = fp;
227 state.sp = sp;
228 state.pc_address = StackFrame::ResolveReturnAddressLocation(
229 reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp)));
230
231 // If the top of stack is a return address to the interpreter trampoline,
232 // then we are likely in a bytecode handler with elided frame. In that
233 // case, set the PC properly and make sure we do not drop the frame.
234 if (IsValidStackAddress(sp)) {
235 MSAN_MEMORY_IS_INITIALIZED(sp, kPointerSize);
236 Address tos = ReadMemoryAt(reinterpret_cast<Address>(sp));
237 if (IsInterpreterFramePc(isolate, tos)) {
238 state.pc_address = reinterpret_cast<Address*>(sp);
239 advance_frame = false;
240 }
241 }
242
243 // StackFrame::ComputeType will read both kContextOffset and kMarkerOffset,
244 // we check only that kMarkerOffset is within the stack bounds and do
245 // compile time check that kContextOffset slot is pushed on the stack before
246 // kMarkerOffset.
247 STATIC_ASSERT(StandardFrameConstants::kFunctionOffset <
248 StandardFrameConstants::kContextOffset);
249 Address frame_marker = fp + StandardFrameConstants::kFunctionOffset;
250 if (IsValidStackAddress(frame_marker)) {
251 type = StackFrame::ComputeType(this, &state);
252 top_frame_type_ = type;
253 // We only keep the top frame if we believe it to be interpreted frame.
254 if (type != StackFrame::INTERPRETED) {
255 advance_frame = true;
256 }
257 } else {
258 // Mark the frame as JAVA_SCRIPT if we cannot determine its type.
259 // The frame anyways will be skipped.
260 type = StackFrame::JAVA_SCRIPT;
261 // Top frame is incomplete so we cannot reliably determine its type.
262 top_frame_type_ = StackFrame::NONE;
263 }
264 } else {
265 return;
266 }
267 frame_ = SingletonFor(type, &state);
268 if (advance_frame && frame_) Advance();
269 }
270
271
IsValidTop(ThreadLocalTop * top) const272 bool SafeStackFrameIterator::IsValidTop(ThreadLocalTop* top) const {
273 Address c_entry_fp = Isolate::c_entry_fp(top);
274 if (!IsValidExitFrame(c_entry_fp)) return false;
275 // There should be at least one JS_ENTRY stack handler.
276 Address handler = Isolate::handler(top);
277 if (handler == NULL) return false;
278 // Check that there are no js frames on top of the native frames.
279 return c_entry_fp < handler;
280 }
281
282
AdvanceOneFrame()283 void SafeStackFrameIterator::AdvanceOneFrame() {
284 DCHECK(!done());
285 StackFrame* last_frame = frame_;
286 Address last_sp = last_frame->sp(), last_fp = last_frame->fp();
287 // Before advancing to the next stack frame, perform pointer validity tests.
288 if (!IsValidFrame(last_frame) || !IsValidCaller(last_frame)) {
289 frame_ = NULL;
290 return;
291 }
292
293 // Advance to the previous frame.
294 StackFrame::State state;
295 StackFrame::Type type = frame_->GetCallerState(&state);
296 frame_ = SingletonFor(type, &state);
297 if (!frame_) return;
298
299 // Check that we have actually moved to the previous frame in the stack.
300 if (frame_->sp() < last_sp || frame_->fp() < last_fp) {
301 frame_ = NULL;
302 }
303 }
304
305
IsValidFrame(StackFrame * frame) const306 bool SafeStackFrameIterator::IsValidFrame(StackFrame* frame) const {
307 return IsValidStackAddress(frame->sp()) && IsValidStackAddress(frame->fp());
308 }
309
310
IsValidCaller(StackFrame * frame)311 bool SafeStackFrameIterator::IsValidCaller(StackFrame* frame) {
312 StackFrame::State state;
313 if (frame->is_entry() || frame->is_entry_construct()) {
314 // See EntryFrame::GetCallerState. It computes the caller FP address
315 // and calls ExitFrame::GetStateForFramePointer on it. We need to be
316 // sure that caller FP address is valid.
317 Address caller_fp = Memory::Address_at(
318 frame->fp() + EntryFrameConstants::kCallerFPOffset);
319 if (!IsValidExitFrame(caller_fp)) return false;
320 } else if (frame->is_arguments_adaptor()) {
321 // See ArgumentsAdaptorFrame::GetCallerStackPointer. It assumes that
322 // the number of arguments is stored on stack as Smi. We need to check
323 // that it really an Smi.
324 Object* number_of_args = reinterpret_cast<ArgumentsAdaptorFrame*>(frame)->
325 GetExpression(0);
326 if (!number_of_args->IsSmi()) {
327 return false;
328 }
329 }
330 frame->ComputeCallerState(&state);
331 return IsValidStackAddress(state.sp) && IsValidStackAddress(state.fp) &&
332 SingletonFor(frame->GetCallerState(&state)) != NULL;
333 }
334
335
IsValidExitFrame(Address fp) const336 bool SafeStackFrameIterator::IsValidExitFrame(Address fp) const {
337 if (!IsValidStackAddress(fp)) return false;
338 Address sp = ExitFrame::ComputeStackPointer(fp);
339 if (!IsValidStackAddress(sp)) return false;
340 StackFrame::State state;
341 ExitFrame::FillState(fp, sp, &state);
342 MSAN_MEMORY_IS_INITIALIZED(state.pc_address, sizeof(state.pc_address));
343 return *state.pc_address != nullptr;
344 }
345
346
Advance()347 void SafeStackFrameIterator::Advance() {
348 while (true) {
349 AdvanceOneFrame();
350 if (done()) break;
351 ExternalCallbackScope* last_callback_scope = NULL;
352 while (external_callback_scope_ != NULL &&
353 external_callback_scope_->scope_address() < frame_->fp()) {
354 // As long as the setup of a frame is not atomic, we may happen to be
355 // in an interval where an ExternalCallbackScope is already created,
356 // but the frame is not yet entered. So we are actually observing
357 // the previous frame.
358 // Skip all the ExternalCallbackScope's that are below the current fp.
359 last_callback_scope = external_callback_scope_;
360 external_callback_scope_ = external_callback_scope_->previous();
361 }
362 if (frame_->is_java_script()) break;
363 if (frame_->is_exit() || frame_->is_builtin_exit()) {
364 // Some of the EXIT frames may have ExternalCallbackScope allocated on
365 // top of them. In that case the scope corresponds to the first EXIT
366 // frame beneath it. There may be other EXIT frames on top of the
367 // ExternalCallbackScope, just skip them as we cannot collect any useful
368 // information about them.
369 if (last_callback_scope) {
370 frame_->state_.pc_address =
371 last_callback_scope->callback_entrypoint_address();
372 }
373 break;
374 }
375 }
376 }
377
378
379 // -------------------------------------------------------------------------
380
381
GetSafepointData(Isolate * isolate,Address inner_pointer,SafepointEntry * safepoint_entry,unsigned * stack_slots)382 Code* StackFrame::GetSafepointData(Isolate* isolate,
383 Address inner_pointer,
384 SafepointEntry* safepoint_entry,
385 unsigned* stack_slots) {
386 InnerPointerToCodeCache::InnerPointerToCodeCacheEntry* entry =
387 isolate->inner_pointer_to_code_cache()->GetCacheEntry(inner_pointer);
388 if (!entry->safepoint_entry.is_valid()) {
389 entry->safepoint_entry = entry->code->GetSafepointEntry(inner_pointer);
390 DCHECK(entry->safepoint_entry.is_valid());
391 } else {
392 DCHECK(entry->safepoint_entry.Equals(
393 entry->code->GetSafepointEntry(inner_pointer)));
394 }
395
396 // Fill in the results and return the code.
397 Code* code = entry->code;
398 *safepoint_entry = entry->safepoint_entry;
399 *stack_slots = code->stack_slots();
400 return code;
401 }
402
403
404 #ifdef DEBUG
405 static bool GcSafeCodeContains(HeapObject* object, Address addr);
406 #endif
407
408
IteratePc(ObjectVisitor * v,Address * pc_address,Address * constant_pool_address,Code * holder)409 void StackFrame::IteratePc(ObjectVisitor* v, Address* pc_address,
410 Address* constant_pool_address, Code* holder) {
411 Address pc = *pc_address;
412 DCHECK(GcSafeCodeContains(holder, pc));
413 unsigned pc_offset = static_cast<unsigned>(pc - holder->instruction_start());
414 Object* code = holder;
415 v->VisitPointer(&code);
416 if (code != holder) {
417 holder = reinterpret_cast<Code*>(code);
418 pc = holder->instruction_start() + pc_offset;
419 *pc_address = pc;
420 if (FLAG_enable_embedded_constant_pool && constant_pool_address) {
421 *constant_pool_address = holder->constant_pool();
422 }
423 }
424 }
425
426
SetReturnAddressLocationResolver(ReturnAddressLocationResolver resolver)427 void StackFrame::SetReturnAddressLocationResolver(
428 ReturnAddressLocationResolver resolver) {
429 DCHECK(return_address_location_resolver_ == NULL);
430 return_address_location_resolver_ = resolver;
431 }
432
ComputeType(const StackFrameIteratorBase * iterator,State * state)433 StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator,
434 State* state) {
435 DCHECK(state->fp != NULL);
436
437 MSAN_MEMORY_IS_INITIALIZED(
438 state->fp + CommonFrameConstants::kContextOrFrameTypeOffset,
439 kPointerSize);
440 intptr_t marker = Memory::intptr_at(
441 state->fp + CommonFrameConstants::kContextOrFrameTypeOffset);
442 if (!iterator->can_access_heap_objects_) {
443 // TODO(titzer): "can_access_heap_objects" is kind of bogus. It really
444 // means that we are being called from the profiler, which can interrupt
445 // the VM with a signal at any arbitrary instruction, with essentially
446 // anything on the stack. So basically none of these checks are 100%
447 // reliable.
448 MSAN_MEMORY_IS_INITIALIZED(
449 state->fp + StandardFrameConstants::kFunctionOffset, kPointerSize);
450 Object* maybe_function =
451 Memory::Object_at(state->fp + StandardFrameConstants::kFunctionOffset);
452 if (!StackFrame::IsTypeMarker(marker)) {
453 if (maybe_function->IsSmi()) {
454 return NONE;
455 } else if (IsInterpreterFramePc(iterator->isolate(),
456 *(state->pc_address))) {
457 return INTERPRETED;
458 } else {
459 return JAVA_SCRIPT;
460 }
461 }
462 } else {
463 // Look up the code object to figure out the type of the stack frame.
464 Code* code_obj =
465 GetContainingCode(iterator->isolate(), *(state->pc_address));
466 if (code_obj != nullptr) {
467 switch (code_obj->kind()) {
468 case Code::BUILTIN:
469 if (StackFrame::IsTypeMarker(marker)) break;
470 if (code_obj->is_interpreter_trampoline_builtin()) {
471 return INTERPRETED;
472 }
473 if (code_obj->is_turbofanned()) {
474 // TODO(bmeurer): We treat frames for BUILTIN Code objects as
475 // OptimizedFrame for now (all the builtins with JavaScript
476 // linkage are actually generated with TurboFan currently, so
477 // this is sound).
478 return OPTIMIZED;
479 }
480 return BUILTIN;
481 case Code::FUNCTION:
482 return JAVA_SCRIPT;
483 case Code::OPTIMIZED_FUNCTION:
484 return OPTIMIZED;
485 case Code::WASM_FUNCTION:
486 return WASM_COMPILED;
487 case Code::WASM_TO_JS_FUNCTION:
488 return WASM_TO_JS;
489 case Code::JS_TO_WASM_FUNCTION:
490 return JS_TO_WASM;
491 case Code::WASM_INTERPRETER_ENTRY:
492 return WASM_INTERPRETER_ENTRY;
493 default:
494 // All other types should have an explicit marker
495 break;
496 }
497 } else {
498 return NONE;
499 }
500 }
501
502 DCHECK(StackFrame::IsTypeMarker(marker));
503 StackFrame::Type candidate = StackFrame::MarkerToType(marker);
504 switch (candidate) {
505 case ENTRY:
506 case ENTRY_CONSTRUCT:
507 case EXIT:
508 case BUILTIN_EXIT:
509 case STUB:
510 case STUB_FAILURE_TRAMPOLINE:
511 case INTERNAL:
512 case CONSTRUCT:
513 case ARGUMENTS_ADAPTOR:
514 case WASM_TO_JS:
515 case WASM_COMPILED:
516 return candidate;
517 case JS_TO_WASM:
518 case JAVA_SCRIPT:
519 case OPTIMIZED:
520 case INTERPRETED:
521 default:
522 // Unoptimized and optimized JavaScript frames, including
523 // interpreted frames, should never have a StackFrame::Type
524 // marker. If we find one, we're likely being called from the
525 // profiler in a bogus stack frame.
526 return NONE;
527 }
528 }
529
530
531 #ifdef DEBUG
can_access_heap_objects() const532 bool StackFrame::can_access_heap_objects() const {
533 return iterator_->can_access_heap_objects_;
534 }
535 #endif
536
537
GetCallerState(State * state) const538 StackFrame::Type StackFrame::GetCallerState(State* state) const {
539 ComputeCallerState(state);
540 return ComputeType(iterator_, state);
541 }
542
543
UnpaddedFP() const544 Address StackFrame::UnpaddedFP() const {
545 return fp();
546 }
547
548
unchecked_code() const549 Code* EntryFrame::unchecked_code() const {
550 return isolate()->heap()->js_entry_code();
551 }
552
553
ComputeCallerState(State * state) const554 void EntryFrame::ComputeCallerState(State* state) const {
555 GetCallerState(state);
556 }
557
558
SetCallerFp(Address caller_fp)559 void EntryFrame::SetCallerFp(Address caller_fp) {
560 const int offset = EntryFrameConstants::kCallerFPOffset;
561 Memory::Address_at(this->fp() + offset) = caller_fp;
562 }
563
564
GetCallerState(State * state) const565 StackFrame::Type EntryFrame::GetCallerState(State* state) const {
566 const int offset = EntryFrameConstants::kCallerFPOffset;
567 Address fp = Memory::Address_at(this->fp() + offset);
568 return ExitFrame::GetStateForFramePointer(fp, state);
569 }
570
571
unchecked_code() const572 Code* EntryConstructFrame::unchecked_code() const {
573 return isolate()->heap()->js_construct_entry_code();
574 }
575
576
code_slot() const577 Object*& ExitFrame::code_slot() const {
578 const int offset = ExitFrameConstants::kCodeOffset;
579 return Memory::Object_at(fp() + offset);
580 }
581
unchecked_code() const582 Code* ExitFrame::unchecked_code() const {
583 return reinterpret_cast<Code*>(code_slot());
584 }
585
586
ComputeCallerState(State * state) const587 void ExitFrame::ComputeCallerState(State* state) const {
588 // Set up the caller state.
589 state->sp = caller_sp();
590 state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset);
591 state->pc_address = ResolveReturnAddressLocation(
592 reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset));
593 state->callee_pc_address = nullptr;
594 if (FLAG_enable_embedded_constant_pool) {
595 state->constant_pool_address = reinterpret_cast<Address*>(
596 fp() + ExitFrameConstants::kConstantPoolOffset);
597 }
598 }
599
600
SetCallerFp(Address caller_fp)601 void ExitFrame::SetCallerFp(Address caller_fp) {
602 Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset) = caller_fp;
603 }
604
605
Iterate(ObjectVisitor * v) const606 void ExitFrame::Iterate(ObjectVisitor* v) const {
607 // The arguments are traversed as part of the expression stack of
608 // the calling frame.
609 IteratePc(v, pc_address(), constant_pool_address(), LookupCode());
610 v->VisitPointer(&code_slot());
611 }
612
613
GetCallerStackPointer() const614 Address ExitFrame::GetCallerStackPointer() const {
615 return fp() + ExitFrameConstants::kCallerSPOffset;
616 }
617
618
GetStateForFramePointer(Address fp,State * state)619 StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
620 if (fp == 0) return NONE;
621 Address sp = ComputeStackPointer(fp);
622 FillState(fp, sp, state);
623 DCHECK_NOT_NULL(*state->pc_address);
624
625 return ComputeFrameType(fp);
626 }
627
ComputeFrameType(Address fp)628 StackFrame::Type ExitFrame::ComputeFrameType(Address fp) {
629 // Distinguish between between regular and builtin exit frames.
630 // Default to EXIT in all hairy cases (e.g., when called from profiler).
631 const int offset = ExitFrameConstants::kFrameTypeOffset;
632 Object* marker = Memory::Object_at(fp + offset);
633
634 if (!marker->IsSmi()) {
635 return EXIT;
636 }
637
638 intptr_t marker_int = bit_cast<intptr_t>(marker);
639
640 StackFrame::Type frame_type = static_cast<StackFrame::Type>(marker_int >> 1);
641 if (frame_type == EXIT || frame_type == BUILTIN_EXIT) {
642 return frame_type;
643 }
644
645 return EXIT;
646 }
647
ComputeStackPointer(Address fp)648 Address ExitFrame::ComputeStackPointer(Address fp) {
649 MSAN_MEMORY_IS_INITIALIZED(fp + ExitFrameConstants::kSPOffset, kPointerSize);
650 return Memory::Address_at(fp + ExitFrameConstants::kSPOffset);
651 }
652
FillState(Address fp,Address sp,State * state)653 void ExitFrame::FillState(Address fp, Address sp, State* state) {
654 state->sp = sp;
655 state->fp = fp;
656 state->pc_address = ResolveReturnAddressLocation(
657 reinterpret_cast<Address*>(sp - 1 * kPCOnStackSize));
658 state->callee_pc_address = nullptr;
659 // The constant pool recorded in the exit frame is not associated
660 // with the pc in this state (the return address into a C entry
661 // stub). ComputeCallerState will retrieve the constant pool
662 // together with the associated caller pc.
663 state->constant_pool_address = nullptr;
664 }
665
function() const666 JSFunction* BuiltinExitFrame::function() const {
667 return JSFunction::cast(target_slot_object());
668 }
669
receiver() const670 Object* BuiltinExitFrame::receiver() const { return receiver_slot_object(); }
671
IsConstructor() const672 bool BuiltinExitFrame::IsConstructor() const {
673 return !new_target_slot_object()->IsUndefined(isolate());
674 }
675
GetParameter(int i) const676 Object* BuiltinExitFrame::GetParameter(int i) const {
677 DCHECK(i >= 0 && i < ComputeParametersCount());
678 int offset = BuiltinExitFrameConstants::kArgcOffset + (i + 1) * kPointerSize;
679 return Memory::Object_at(fp() + offset);
680 }
681
ComputeParametersCount() const682 int BuiltinExitFrame::ComputeParametersCount() const {
683 Object* argc_slot = argc_slot_object();
684 DCHECK(argc_slot->IsSmi());
685 // Argc also counts the receiver, target, new target, and argc itself as args,
686 // therefore the real argument count is argc - 4.
687 int argc = Smi::cast(argc_slot)->value() - 4;
688 DCHECK(argc >= 0);
689 return argc;
690 }
691
Print(StringStream * accumulator,PrintMode mode,int index) const692 void BuiltinExitFrame::Print(StringStream* accumulator, PrintMode mode,
693 int index) const {
694 DisallowHeapAllocation no_gc;
695 Object* receiver = this->receiver();
696 JSFunction* function = this->function();
697
698 accumulator->PrintSecurityTokenIfChanged(function);
699 PrintIndex(accumulator, mode, index);
700 accumulator->Add("builtin exit frame: ");
701 Code* code = NULL;
702 if (IsConstructor()) accumulator->Add("new ");
703 accumulator->PrintFunction(function, receiver, &code);
704
705 accumulator->Add("(this=%o", receiver);
706
707 // Print the parameters.
708 int parameters_count = ComputeParametersCount();
709 for (int i = 0; i < parameters_count; i++) {
710 accumulator->Add(",%o", GetParameter(i));
711 }
712
713 accumulator->Add(")\n\n");
714 }
715
GetExpressionAddress(int n) const716 Address StandardFrame::GetExpressionAddress(int n) const {
717 const int offset = StandardFrameConstants::kExpressionsOffset;
718 return fp() + offset - n * kPointerSize;
719 }
720
GetExpressionAddress(int n) const721 Address InterpretedFrame::GetExpressionAddress(int n) const {
722 const int offset = InterpreterFrameConstants::kExpressionsOffset;
723 return fp() + offset - n * kPointerSize;
724 }
725
script() const726 Script* StandardFrame::script() const {
727 // This should only be called on frames which override this method.
728 DCHECK(false);
729 return nullptr;
730 }
731
receiver() const732 Object* StandardFrame::receiver() const {
733 return isolate()->heap()->undefined_value();
734 }
735
context() const736 Object* StandardFrame::context() const {
737 return isolate()->heap()->undefined_value();
738 }
739
position() const740 int StandardFrame::position() const {
741 AbstractCode* code = AbstractCode::cast(LookupCode());
742 int code_offset = static_cast<int>(pc() - code->instruction_start());
743 return code->SourcePosition(code_offset);
744 }
745
ComputeExpressionsCount() const746 int StandardFrame::ComputeExpressionsCount() const {
747 Address base = GetExpressionAddress(0);
748 Address limit = sp() - kPointerSize;
749 DCHECK(base >= limit); // stack grows downwards
750 // Include register-allocated locals in number of expressions.
751 return static_cast<int>((base - limit) / kPointerSize);
752 }
753
GetParameter(int index) const754 Object* StandardFrame::GetParameter(int index) const {
755 // StandardFrame does not define any parameters.
756 UNREACHABLE();
757 return nullptr;
758 }
759
ComputeParametersCount() const760 int StandardFrame::ComputeParametersCount() const { return 0; }
761
ComputeCallerState(State * state) const762 void StandardFrame::ComputeCallerState(State* state) const {
763 state->sp = caller_sp();
764 state->fp = caller_fp();
765 state->pc_address = ResolveReturnAddressLocation(
766 reinterpret_cast<Address*>(ComputePCAddress(fp())));
767 state->callee_pc_address = pc_address();
768 state->constant_pool_address =
769 reinterpret_cast<Address*>(ComputeConstantPoolAddress(fp()));
770 }
771
772
SetCallerFp(Address caller_fp)773 void StandardFrame::SetCallerFp(Address caller_fp) {
774 Memory::Address_at(fp() + StandardFrameConstants::kCallerFPOffset) =
775 caller_fp;
776 }
777
IsConstructor() const778 bool StandardFrame::IsConstructor() const { return false; }
779
Summarize(List<FrameSummary> * functions,FrameSummary::Mode mode) const780 void StandardFrame::Summarize(List<FrameSummary>* functions,
781 FrameSummary::Mode mode) const {
782 // This should only be called on frames which override this method.
783 UNREACHABLE();
784 }
785
IterateCompiledFrame(ObjectVisitor * v) const786 void StandardFrame::IterateCompiledFrame(ObjectVisitor* v) const {
787 // Make sure that we're not doing "safe" stack frame iteration. We cannot
788 // possibly find pointers in optimized frames in that state.
789 DCHECK(can_access_heap_objects());
790
791 // Compute the safepoint information.
792 unsigned stack_slots = 0;
793 SafepointEntry safepoint_entry;
794 Code* code = StackFrame::GetSafepointData(
795 isolate(), pc(), &safepoint_entry, &stack_slots);
796 unsigned slot_space = stack_slots * kPointerSize;
797
798 // Determine the fixed header and spill slot area size.
799 int frame_header_size = StandardFrameConstants::kFixedFrameSizeFromFp;
800 intptr_t marker =
801 Memory::intptr_at(fp() + CommonFrameConstants::kContextOrFrameTypeOffset);
802 if (StackFrame::IsTypeMarker(marker)) {
803 StackFrame::Type candidate = StackFrame::MarkerToType(marker);
804 switch (candidate) {
805 case ENTRY:
806 case ENTRY_CONSTRUCT:
807 case EXIT:
808 case BUILTIN_EXIT:
809 case STUB_FAILURE_TRAMPOLINE:
810 case ARGUMENTS_ADAPTOR:
811 case STUB:
812 case INTERNAL:
813 case CONSTRUCT:
814 case JS_TO_WASM:
815 case WASM_TO_JS:
816 case WASM_COMPILED:
817 case WASM_INTERPRETER_ENTRY:
818 frame_header_size = TypedFrameConstants::kFixedFrameSizeFromFp;
819 break;
820 case JAVA_SCRIPT:
821 case OPTIMIZED:
822 case INTERPRETED:
823 case BUILTIN:
824 // These frame types have a context, but they are actually stored
825 // in the place on the stack that one finds the frame type.
826 UNREACHABLE();
827 break;
828 case NONE:
829 case NUMBER_OF_TYPES:
830 case MANUAL:
831 UNREACHABLE();
832 break;
833 }
834 }
835 slot_space -=
836 (frame_header_size + StandardFrameConstants::kFixedFrameSizeAboveFp);
837
838 Object** frame_header_base = &Memory::Object_at(fp() - frame_header_size);
839 Object** frame_header_limit =
840 &Memory::Object_at(fp() - StandardFrameConstants::kCPSlotSize);
841 Object** parameters_base = &Memory::Object_at(sp());
842 Object** parameters_limit = frame_header_base - slot_space / kPointerSize;
843
844 // Visit the parameters that may be on top of the saved registers.
845 if (safepoint_entry.argument_count() > 0) {
846 v->VisitPointers(parameters_base,
847 parameters_base + safepoint_entry.argument_count());
848 parameters_base += safepoint_entry.argument_count();
849 }
850
851 // Skip saved double registers.
852 if (safepoint_entry.has_doubles()) {
853 // Number of doubles not known at snapshot time.
854 DCHECK(!isolate()->serializer_enabled());
855 parameters_base += RegisterConfiguration::Crankshaft()
856 ->num_allocatable_double_registers() *
857 kDoubleSize / kPointerSize;
858 }
859
860 // Visit the registers that contain pointers if any.
861 if (safepoint_entry.HasRegisters()) {
862 for (int i = kNumSafepointRegisters - 1; i >=0; i--) {
863 if (safepoint_entry.HasRegisterAt(i)) {
864 int reg_stack_index = MacroAssembler::SafepointRegisterStackIndex(i);
865 v->VisitPointer(parameters_base + reg_stack_index);
866 }
867 }
868 // Skip the words containing the register values.
869 parameters_base += kNumSafepointRegisters;
870 }
871
872 // We're done dealing with the register bits.
873 uint8_t* safepoint_bits = safepoint_entry.bits();
874 safepoint_bits += kNumSafepointRegisters >> kBitsPerByteLog2;
875
876 // Visit the rest of the parameters.
877 if (!is_js_to_wasm() && !is_wasm()) {
878 // Non-WASM frames have tagged values as parameters.
879 v->VisitPointers(parameters_base, parameters_limit);
880 }
881
882 // Visit pointer spill slots and locals.
883 for (unsigned index = 0; index < stack_slots; index++) {
884 int byte_index = index >> kBitsPerByteLog2;
885 int bit_index = index & (kBitsPerByte - 1);
886 if ((safepoint_bits[byte_index] & (1U << bit_index)) != 0) {
887 v->VisitPointer(parameters_limit + index);
888 }
889 }
890
891 // Visit the return address in the callee and incoming arguments.
892 IteratePc(v, pc_address(), constant_pool_address(), code);
893
894 if (!is_wasm() && !is_wasm_to_js()) {
895 // Visit the context in stub frame and JavaScript frame.
896 // Visit the function in JavaScript frame.
897 v->VisitPointers(frame_header_base, frame_header_limit);
898 }
899 }
900
901
Iterate(ObjectVisitor * v) const902 void StubFrame::Iterate(ObjectVisitor* v) const {
903 IterateCompiledFrame(v);
904 }
905
906
unchecked_code() const907 Code* StubFrame::unchecked_code() const {
908 return isolate()->FindCodeObject(pc());
909 }
910
911
GetCallerStackPointer() const912 Address StubFrame::GetCallerStackPointer() const {
913 return fp() + ExitFrameConstants::kCallerSPOffset;
914 }
915
916
GetNumberOfIncomingArguments() const917 int StubFrame::GetNumberOfIncomingArguments() const {
918 return 0;
919 }
920
921
Iterate(ObjectVisitor * v) const922 void OptimizedFrame::Iterate(ObjectVisitor* v) const {
923 IterateCompiledFrame(v);
924 }
925
926
SetParameterValue(int index,Object * value) const927 void JavaScriptFrame::SetParameterValue(int index, Object* value) const {
928 Memory::Object_at(GetParameterSlot(index)) = value;
929 }
930
931
IsConstructor() const932 bool JavaScriptFrame::IsConstructor() const {
933 Address fp = caller_fp();
934 if (has_adapted_arguments()) {
935 // Skip the arguments adaptor frame and look at the real caller.
936 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
937 }
938 return IsConstructFrame(fp);
939 }
940
941
HasInlinedFrames() const942 bool JavaScriptFrame::HasInlinedFrames() const {
943 List<SharedFunctionInfo*> functions(1);
944 GetFunctions(&functions);
945 return functions.length() > 1;
946 }
947
948
GetArgumentsLength() const949 int JavaScriptFrame::GetArgumentsLength() const {
950 // If there is an arguments adaptor frame get the arguments length from it.
951 if (has_adapted_arguments()) {
952 return ArgumentsAdaptorFrame::GetLength(caller_fp());
953 } else {
954 return GetNumberOfIncomingArguments();
955 }
956 }
957
958
unchecked_code() const959 Code* JavaScriptFrame::unchecked_code() const {
960 return function()->code();
961 }
962
963
GetNumberOfIncomingArguments() const964 int JavaScriptFrame::GetNumberOfIncomingArguments() const {
965 DCHECK(can_access_heap_objects() &&
966 isolate()->heap()->gc_state() == Heap::NOT_IN_GC);
967
968 return function()->shared()->internal_formal_parameter_count();
969 }
970
971
GetCallerStackPointer() const972 Address JavaScriptFrame::GetCallerStackPointer() const {
973 return fp() + StandardFrameConstants::kCallerSPOffset;
974 }
975
GetFunctions(List<SharedFunctionInfo * > * functions) const976 void JavaScriptFrame::GetFunctions(List<SharedFunctionInfo*>* functions) const {
977 DCHECK(functions->length() == 0);
978 functions->Add(function()->shared());
979 }
980
GetFunctions(List<Handle<SharedFunctionInfo>> * functions) const981 void JavaScriptFrame::GetFunctions(
982 List<Handle<SharedFunctionInfo>>* functions) const {
983 DCHECK(functions->length() == 0);
984 List<SharedFunctionInfo*> raw_functions;
985 GetFunctions(&raw_functions);
986 for (const auto& raw_function : raw_functions) {
987 functions->Add(Handle<SharedFunctionInfo>(raw_function));
988 }
989 }
990
Summarize(List<FrameSummary> * functions,FrameSummary::Mode mode) const991 void JavaScriptFrame::Summarize(List<FrameSummary>* functions,
992 FrameSummary::Mode mode) const {
993 DCHECK(functions->length() == 0);
994 Code* code = LookupCode();
995 int offset = static_cast<int>(pc() - code->instruction_start());
996 AbstractCode* abstract_code = AbstractCode::cast(code);
997 FrameSummary::JavaScriptFrameSummary summary(isolate(), receiver(),
998 function(), abstract_code,
999 offset, IsConstructor(), mode);
1000 functions->Add(summary);
1001 }
1002
function() const1003 JSFunction* JavaScriptFrame::function() const {
1004 return JSFunction::cast(function_slot_object());
1005 }
1006
receiver() const1007 Object* JavaScriptFrame::receiver() const { return GetParameter(-1); }
1008
context() const1009 Object* JavaScriptFrame::context() const {
1010 const int offset = StandardFrameConstants::kContextOffset;
1011 Object* maybe_result = Memory::Object_at(fp() + offset);
1012 DCHECK(!maybe_result->IsSmi());
1013 return maybe_result;
1014 }
1015
script() const1016 Script* JavaScriptFrame::script() const {
1017 return Script::cast(function()->shared()->script());
1018 }
1019
LookupExceptionHandlerInTable(int * stack_depth,HandlerTable::CatchPrediction * prediction)1020 int JavaScriptFrame::LookupExceptionHandlerInTable(
1021 int* stack_depth, HandlerTable::CatchPrediction* prediction) {
1022 DCHECK_EQ(0, LookupCode()->handler_table()->length());
1023 DCHECK(!LookupCode()->is_optimized_code());
1024 return -1;
1025 }
1026
PrintFunctionAndOffset(JSFunction * function,AbstractCode * code,int code_offset,FILE * file,bool print_line_number)1027 void JavaScriptFrame::PrintFunctionAndOffset(JSFunction* function,
1028 AbstractCode* code,
1029 int code_offset, FILE* file,
1030 bool print_line_number) {
1031 PrintF(file, "%s", function->IsOptimized() ? "*" : "~");
1032 function->PrintName(file);
1033 PrintF(file, "+%d", code_offset);
1034 if (print_line_number) {
1035 SharedFunctionInfo* shared = function->shared();
1036 int source_pos = code->SourcePosition(code_offset);
1037 Object* maybe_script = shared->script();
1038 if (maybe_script->IsScript()) {
1039 Script* script = Script::cast(maybe_script);
1040 int line = script->GetLineNumber(source_pos) + 1;
1041 Object* script_name_raw = script->name();
1042 if (script_name_raw->IsString()) {
1043 String* script_name = String::cast(script->name());
1044 std::unique_ptr<char[]> c_script_name =
1045 script_name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1046 PrintF(file, " at %s:%d", c_script_name.get(), line);
1047 } else {
1048 PrintF(file, " at <unknown>:%d", line);
1049 }
1050 } else {
1051 PrintF(file, " at <unknown>:<unknown>");
1052 }
1053 }
1054 }
1055
PrintTop(Isolate * isolate,FILE * file,bool print_args,bool print_line_number)1056 void JavaScriptFrame::PrintTop(Isolate* isolate, FILE* file, bool print_args,
1057 bool print_line_number) {
1058 // constructor calls
1059 DisallowHeapAllocation no_allocation;
1060 JavaScriptFrameIterator it(isolate);
1061 while (!it.done()) {
1062 if (it.frame()->is_java_script()) {
1063 JavaScriptFrame* frame = it.frame();
1064 if (frame->IsConstructor()) PrintF(file, "new ");
1065 JSFunction* function = frame->function();
1066 int code_offset = 0;
1067 if (frame->is_interpreted()) {
1068 InterpretedFrame* iframe = reinterpret_cast<InterpretedFrame*>(frame);
1069 code_offset = iframe->GetBytecodeOffset();
1070 } else {
1071 Code* code = frame->unchecked_code();
1072 code_offset = static_cast<int>(frame->pc() - code->instruction_start());
1073 }
1074 PrintFunctionAndOffset(function, function->abstract_code(), code_offset,
1075 file, print_line_number);
1076 if (print_args) {
1077 // function arguments
1078 // (we are intentionally only printing the actually
1079 // supplied parameters, not all parameters required)
1080 PrintF(file, "(this=");
1081 frame->receiver()->ShortPrint(file);
1082 const int length = frame->ComputeParametersCount();
1083 for (int i = 0; i < length; i++) {
1084 PrintF(file, ", ");
1085 frame->GetParameter(i)->ShortPrint(file);
1086 }
1087 PrintF(file, ")");
1088 }
1089 break;
1090 }
1091 it.Advance();
1092 }
1093 }
1094
CollectFunctionAndOffsetForICStats(JSFunction * function,AbstractCode * code,int code_offset)1095 void JavaScriptFrame::CollectFunctionAndOffsetForICStats(JSFunction* function,
1096 AbstractCode* code,
1097 int code_offset) {
1098 auto ic_stats = ICStats::instance();
1099 ICInfo& ic_info = ic_stats->Current();
1100 SharedFunctionInfo* shared = function->shared();
1101
1102 ic_info.function_name = ic_stats->GetOrCacheFunctionName(function);
1103 ic_info.script_offset = code_offset;
1104
1105 int source_pos = code->SourcePosition(code_offset);
1106 Object* maybe_script = shared->script();
1107 if (maybe_script->IsScript()) {
1108 Script* script = Script::cast(maybe_script);
1109 ic_info.line_num = script->GetLineNumber(source_pos) + 1;
1110 ic_info.script_name = ic_stats->GetOrCacheScriptName(script);
1111 }
1112 }
1113
CollectTopFrameForICStats(Isolate * isolate)1114 void JavaScriptFrame::CollectTopFrameForICStats(Isolate* isolate) {
1115 // constructor calls
1116 DisallowHeapAllocation no_allocation;
1117 JavaScriptFrameIterator it(isolate);
1118 ICInfo& ic_info = ICStats::instance()->Current();
1119 while (!it.done()) {
1120 if (it.frame()->is_java_script()) {
1121 JavaScriptFrame* frame = it.frame();
1122 if (frame->IsConstructor()) ic_info.is_constructor = true;
1123 JSFunction* function = frame->function();
1124 int code_offset = 0;
1125 if (frame->is_interpreted()) {
1126 InterpretedFrame* iframe = reinterpret_cast<InterpretedFrame*>(frame);
1127 code_offset = iframe->GetBytecodeOffset();
1128 } else {
1129 Code* code = frame->unchecked_code();
1130 code_offset = static_cast<int>(frame->pc() - code->instruction_start());
1131 }
1132 CollectFunctionAndOffsetForICStats(function, function->abstract_code(),
1133 code_offset);
1134 return;
1135 }
1136 it.Advance();
1137 }
1138 }
1139
GetParameter(int index) const1140 Object* JavaScriptFrame::GetParameter(int index) const {
1141 return Memory::Object_at(GetParameterSlot(index));
1142 }
1143
ComputeParametersCount() const1144 int JavaScriptFrame::ComputeParametersCount() const {
1145 return GetNumberOfIncomingArguments();
1146 }
1147
1148 namespace {
1149
CannotDeoptFromAsmCode(Code * code,JSFunction * function)1150 bool CannotDeoptFromAsmCode(Code* code, JSFunction* function) {
1151 return code->is_turbofanned() && function->shared()->asm_function();
1152 }
1153
1154 } // namespace
1155
JavaScriptFrameSummary(Isolate * isolate,Object * receiver,JSFunction * function,AbstractCode * abstract_code,int code_offset,bool is_constructor,Mode mode)1156 FrameSummary::JavaScriptFrameSummary::JavaScriptFrameSummary(
1157 Isolate* isolate, Object* receiver, JSFunction* function,
1158 AbstractCode* abstract_code, int code_offset, bool is_constructor,
1159 Mode mode)
1160 : FrameSummaryBase(isolate, JAVA_SCRIPT),
1161 receiver_(receiver, isolate),
1162 function_(function, isolate),
1163 abstract_code_(abstract_code, isolate),
1164 code_offset_(code_offset),
1165 is_constructor_(is_constructor) {
1166 DCHECK(abstract_code->IsBytecodeArray() ||
1167 Code::cast(abstract_code)->kind() != Code::OPTIMIZED_FUNCTION ||
1168 CannotDeoptFromAsmCode(Code::cast(abstract_code), function) ||
1169 mode == kApproximateSummary);
1170 }
1171
is_subject_to_debugging() const1172 bool FrameSummary::JavaScriptFrameSummary::is_subject_to_debugging() const {
1173 return function()->shared()->IsSubjectToDebugging();
1174 }
1175
SourcePosition() const1176 int FrameSummary::JavaScriptFrameSummary::SourcePosition() const {
1177 return abstract_code()->SourcePosition(code_offset());
1178 }
1179
SourceStatementPosition() const1180 int FrameSummary::JavaScriptFrameSummary::SourceStatementPosition() const {
1181 return abstract_code()->SourceStatementPosition(code_offset());
1182 }
1183
script() const1184 Handle<Object> FrameSummary::JavaScriptFrameSummary::script() const {
1185 return handle(function_->shared()->script(), isolate());
1186 }
1187
FunctionName() const1188 Handle<String> FrameSummary::JavaScriptFrameSummary::FunctionName() const {
1189 return JSFunction::GetDebugName(function_);
1190 }
1191
native_context() const1192 Handle<Context> FrameSummary::JavaScriptFrameSummary::native_context() const {
1193 return handle(function_->context()->native_context(), isolate());
1194 }
1195
WasmFrameSummary(Isolate * isolate,FrameSummary::Kind kind,Handle<WasmInstanceObject> instance,bool at_to_number_conversion)1196 FrameSummary::WasmFrameSummary::WasmFrameSummary(
1197 Isolate* isolate, FrameSummary::Kind kind,
1198 Handle<WasmInstanceObject> instance, bool at_to_number_conversion)
1199 : FrameSummaryBase(isolate, kind),
1200 wasm_instance_(instance),
1201 at_to_number_conversion_(at_to_number_conversion) {}
1202
receiver() const1203 Handle<Object> FrameSummary::WasmFrameSummary::receiver() const {
1204 return wasm_instance_->GetIsolate()->global_proxy();
1205 }
1206
1207 #define WASM_SUMMARY_DISPATCH(type, name) \
1208 type FrameSummary::WasmFrameSummary::name() const { \
1209 DCHECK(kind() == Kind::WASM_COMPILED || kind() == Kind::WASM_INTERPRETED); \
1210 return kind() == Kind::WASM_COMPILED \
1211 ? static_cast<const WasmCompiledFrameSummary*>(this)->name() \
1212 : static_cast<const WasmInterpretedFrameSummary*>(this) \
1213 ->name(); \
1214 }
1215
WASM_SUMMARY_DISPATCH(uint32_t,function_index)1216 WASM_SUMMARY_DISPATCH(uint32_t, function_index)
1217 WASM_SUMMARY_DISPATCH(int, byte_offset)
1218
1219 #undef WASM_SUMMARY_DISPATCH
1220
1221 int FrameSummary::WasmFrameSummary::SourcePosition() const {
1222 int offset = byte_offset();
1223 Handle<WasmCompiledModule> compiled_module(wasm_instance()->compiled_module(),
1224 isolate());
1225 if (compiled_module->is_asm_js()) {
1226 offset = WasmCompiledModule::GetAsmJsSourcePosition(
1227 compiled_module, function_index(), offset, at_to_number_conversion());
1228 } else {
1229 offset += compiled_module->GetFunctionOffset(function_index());
1230 }
1231 return offset;
1232 }
1233
script() const1234 Handle<Script> FrameSummary::WasmFrameSummary::script() const {
1235 return handle(wasm_instance()->compiled_module()->script());
1236 }
1237
FunctionName() const1238 Handle<String> FrameSummary::WasmFrameSummary::FunctionName() const {
1239 Handle<WasmCompiledModule> compiled_module(
1240 wasm_instance()->compiled_module());
1241 return WasmCompiledModule::GetFunctionName(compiled_module->GetIsolate(),
1242 compiled_module, function_index());
1243 }
1244
native_context() const1245 Handle<Context> FrameSummary::WasmFrameSummary::native_context() const {
1246 return wasm_instance()->compiled_module()->native_context();
1247 }
1248
WasmCompiledFrameSummary(Isolate * isolate,Handle<WasmInstanceObject> instance,Handle<Code> code,int code_offset,bool at_to_number_conversion)1249 FrameSummary::WasmCompiledFrameSummary::WasmCompiledFrameSummary(
1250 Isolate* isolate, Handle<WasmInstanceObject> instance, Handle<Code> code,
1251 int code_offset, bool at_to_number_conversion)
1252 : WasmFrameSummary(isolate, WASM_COMPILED, instance,
1253 at_to_number_conversion),
1254 code_(code),
1255 code_offset_(code_offset) {}
1256
function_index() const1257 uint32_t FrameSummary::WasmCompiledFrameSummary::function_index() const {
1258 FixedArray* deopt_data = code()->deoptimization_data();
1259 DCHECK_EQ(2, deopt_data->length());
1260 DCHECK(deopt_data->get(1)->IsSmi());
1261 int val = Smi::cast(deopt_data->get(1))->value();
1262 DCHECK_LE(0, val);
1263 return static_cast<uint32_t>(val);
1264 }
1265
byte_offset() const1266 int FrameSummary::WasmCompiledFrameSummary::byte_offset() const {
1267 return AbstractCode::cast(*code())->SourcePosition(code_offset());
1268 }
1269
WasmInterpretedFrameSummary(Isolate * isolate,Handle<WasmInstanceObject> instance,uint32_t function_index,int byte_offset)1270 FrameSummary::WasmInterpretedFrameSummary::WasmInterpretedFrameSummary(
1271 Isolate* isolate, Handle<WasmInstanceObject> instance,
1272 uint32_t function_index, int byte_offset)
1273 : WasmFrameSummary(isolate, WASM_INTERPRETED, instance, false),
1274 function_index_(function_index),
1275 byte_offset_(byte_offset) {}
1276
~FrameSummary()1277 FrameSummary::~FrameSummary() {
1278 #define FRAME_SUMMARY_DESTR(kind, type, field, desc) \
1279 case kind: \
1280 field.~type(); \
1281 break;
1282 switch (base_.kind()) {
1283 FRAME_SUMMARY_VARIANTS(FRAME_SUMMARY_DESTR)
1284 default:
1285 UNREACHABLE();
1286 }
1287 #undef FRAME_SUMMARY_DESTR
1288 }
1289
GetTop(const StandardFrame * frame)1290 FrameSummary FrameSummary::GetTop(const StandardFrame* frame) {
1291 List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
1292 frame->Summarize(&frames);
1293 DCHECK_LT(0, frames.length());
1294 return frames.last();
1295 }
1296
GetBottom(const StandardFrame * frame)1297 FrameSummary FrameSummary::GetBottom(const StandardFrame* frame) {
1298 return Get(frame, 0);
1299 }
1300
GetSingle(const StandardFrame * frame)1301 FrameSummary FrameSummary::GetSingle(const StandardFrame* frame) {
1302 List<FrameSummary> frames(1);
1303 frame->Summarize(&frames);
1304 DCHECK_EQ(1, frames.length());
1305 return frames.first();
1306 }
1307
Get(const StandardFrame * frame,int index)1308 FrameSummary FrameSummary::Get(const StandardFrame* frame, int index) {
1309 DCHECK_LE(0, index);
1310 List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
1311 frame->Summarize(&frames);
1312 DCHECK_GT(frames.length(), index);
1313 return frames[index];
1314 }
1315
1316 #define FRAME_SUMMARY_DISPATCH(ret, name) \
1317 ret FrameSummary::name() const { \
1318 switch (base_.kind()) { \
1319 case JAVA_SCRIPT: \
1320 return java_script_summary_.name(); \
1321 case WASM_COMPILED: \
1322 return wasm_compiled_summary_.name(); \
1323 case WASM_INTERPRETED: \
1324 return wasm_interpreted_summary_.name(); \
1325 default: \
1326 UNREACHABLE(); \
1327 return ret{}; \
1328 } \
1329 }
1330
FRAME_SUMMARY_DISPATCH(Handle<Object>,receiver)1331 FRAME_SUMMARY_DISPATCH(Handle<Object>, receiver)
1332 FRAME_SUMMARY_DISPATCH(int, code_offset)
1333 FRAME_SUMMARY_DISPATCH(bool, is_constructor)
1334 FRAME_SUMMARY_DISPATCH(bool, is_subject_to_debugging)
1335 FRAME_SUMMARY_DISPATCH(Handle<Object>, script)
1336 FRAME_SUMMARY_DISPATCH(int, SourcePosition)
1337 FRAME_SUMMARY_DISPATCH(int, SourceStatementPosition)
1338 FRAME_SUMMARY_DISPATCH(Handle<String>, FunctionName)
1339 FRAME_SUMMARY_DISPATCH(Handle<Context>, native_context)
1340
1341 #undef FRAME_SUMMARY_DISPATCH
1342
1343 void OptimizedFrame::Summarize(List<FrameSummary>* frames,
1344 FrameSummary::Mode mode) const {
1345 DCHECK(frames->length() == 0);
1346 DCHECK(is_optimized());
1347
1348 // Delegate to JS frame in absence of turbofan deoptimization.
1349 // TODO(turbofan): Revisit once we support deoptimization across the board.
1350 Code* code = LookupCode();
1351 if (code->kind() == Code::BUILTIN ||
1352 CannotDeoptFromAsmCode(code, function())) {
1353 return JavaScriptFrame::Summarize(frames);
1354 }
1355
1356 DisallowHeapAllocation no_gc;
1357 int deopt_index = Safepoint::kNoDeoptimizationIndex;
1358 DeoptimizationInputData* const data = GetDeoptimizationData(&deopt_index);
1359 if (deopt_index == Safepoint::kNoDeoptimizationIndex) {
1360 DCHECK(data == nullptr);
1361 if (mode == FrameSummary::kApproximateSummary) {
1362 return JavaScriptFrame::Summarize(frames, mode);
1363 }
1364 FATAL("Missing deoptimization information for OptimizedFrame::Summarize.");
1365 }
1366 FixedArray* const literal_array = data->LiteralArray();
1367
1368 TranslationIterator it(data->TranslationByteArray(),
1369 data->TranslationIndex(deopt_index)->value());
1370 Translation::Opcode frame_opcode =
1371 static_cast<Translation::Opcode>(it.Next());
1372 DCHECK_EQ(Translation::BEGIN, frame_opcode);
1373 it.Next(); // Drop frame count.
1374 int jsframe_count = it.Next();
1375
1376 // We create the summary in reverse order because the frames
1377 // in the deoptimization translation are ordered bottom-to-top.
1378 bool is_constructor = IsConstructor();
1379 while (jsframe_count != 0) {
1380 frame_opcode = static_cast<Translation::Opcode>(it.Next());
1381 if (frame_opcode == Translation::JS_FRAME ||
1382 frame_opcode == Translation::INTERPRETED_FRAME) {
1383 jsframe_count--;
1384 BailoutId const bailout_id = BailoutId(it.Next());
1385 SharedFunctionInfo* const shared_info =
1386 SharedFunctionInfo::cast(literal_array->get(it.Next()));
1387 it.Next(); // Skip height.
1388
1389 // The translation commands are ordered and the function is always
1390 // at the first position, and the receiver is next.
1391 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
1392
1393 // Get the correct function in the optimized frame.
1394 JSFunction* function;
1395 if (opcode == Translation::LITERAL) {
1396 function = JSFunction::cast(literal_array->get(it.Next()));
1397 } else {
1398 CHECK_EQ(opcode, Translation::STACK_SLOT);
1399 function = JSFunction::cast(StackSlotAt(it.Next()));
1400 }
1401 DCHECK_EQ(shared_info, function->shared());
1402
1403 // If we are at a call, the receiver is always in a stack slot.
1404 // Otherwise we are not guaranteed to get the receiver value.
1405 opcode = static_cast<Translation::Opcode>(it.Next());
1406
1407 // Get the correct receiver in the optimized frame.
1408 Object* receiver;
1409 if (opcode == Translation::LITERAL) {
1410 receiver = literal_array->get(it.Next());
1411 } else if (opcode == Translation::STACK_SLOT) {
1412 receiver = StackSlotAt(it.Next());
1413 } else {
1414 // The receiver is not in a stack slot nor in a literal. We give up.
1415 it.Skip(Translation::NumberOfOperandsFor(opcode));
1416 // TODO(3029): Materializing a captured object (or duplicated
1417 // object) is hard, we return undefined for now. This breaks the
1418 // produced stack trace, as constructor frames aren't marked as
1419 // such anymore.
1420 receiver = isolate()->heap()->undefined_value();
1421 }
1422
1423 AbstractCode* abstract_code;
1424
1425 unsigned code_offset;
1426 if (frame_opcode == Translation::JS_FRAME) {
1427 Code* code = shared_info->code();
1428 DeoptimizationOutputData* const output_data =
1429 DeoptimizationOutputData::cast(code->deoptimization_data());
1430 unsigned const entry =
1431 Deoptimizer::GetOutputInfo(output_data, bailout_id, shared_info);
1432 code_offset = FullCodeGenerator::PcField::decode(entry);
1433 abstract_code = AbstractCode::cast(code);
1434 } else {
1435 DCHECK_EQ(frame_opcode, Translation::INTERPRETED_FRAME);
1436 code_offset = bailout_id.ToInt(); // Points to current bytecode.
1437 abstract_code = AbstractCode::cast(shared_info->bytecode_array());
1438 }
1439 FrameSummary::JavaScriptFrameSummary summary(isolate(), receiver,
1440 function, abstract_code,
1441 code_offset, is_constructor);
1442 frames->Add(summary);
1443 is_constructor = false;
1444 } else if (frame_opcode == Translation::CONSTRUCT_STUB_FRAME) {
1445 // The next encountered JS_FRAME will be marked as a constructor call.
1446 it.Skip(Translation::NumberOfOperandsFor(frame_opcode));
1447 DCHECK(!is_constructor);
1448 is_constructor = true;
1449 } else {
1450 // Skip over operands to advance to the next opcode.
1451 it.Skip(Translation::NumberOfOperandsFor(frame_opcode));
1452 }
1453 }
1454 DCHECK(!is_constructor);
1455 }
1456
1457
LookupExceptionHandlerInTable(int * stack_slots,HandlerTable::CatchPrediction * prediction)1458 int OptimizedFrame::LookupExceptionHandlerInTable(
1459 int* stack_slots, HandlerTable::CatchPrediction* prediction) {
1460 // We cannot perform exception prediction on optimized code. Instead, we need
1461 // to use FrameSummary to find the corresponding code offset in unoptimized
1462 // code to perform prediction there.
1463 DCHECK_NULL(prediction);
1464 Code* code = LookupCode();
1465 HandlerTable* table = HandlerTable::cast(code->handler_table());
1466 int pc_offset = static_cast<int>(pc() - code->entry());
1467 if (stack_slots) *stack_slots = code->stack_slots();
1468 return table->LookupReturn(pc_offset);
1469 }
1470
1471
GetDeoptimizationData(int * deopt_index) const1472 DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData(
1473 int* deopt_index) const {
1474 DCHECK(is_optimized());
1475
1476 JSFunction* opt_function = function();
1477 Code* code = opt_function->code();
1478
1479 // The code object may have been replaced by lazy deoptimization. Fall
1480 // back to a slow search in this case to find the original optimized
1481 // code object.
1482 if (!code->contains(pc())) {
1483 code = isolate()->inner_pointer_to_code_cache()->
1484 GcSafeFindCodeForInnerPointer(pc());
1485 }
1486 DCHECK(code != NULL);
1487 DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
1488
1489 SafepointEntry safepoint_entry = code->GetSafepointEntry(pc());
1490 *deopt_index = safepoint_entry.deoptimization_index();
1491 if (*deopt_index != Safepoint::kNoDeoptimizationIndex) {
1492 return DeoptimizationInputData::cast(code->deoptimization_data());
1493 }
1494 return nullptr;
1495 }
1496
receiver() const1497 Object* OptimizedFrame::receiver() const {
1498 Code* code = LookupCode();
1499 if (code->kind() == Code::BUILTIN) {
1500 Address argc_ptr = fp() + OptimizedBuiltinFrameConstants::kArgCOffset;
1501 intptr_t argc = *reinterpret_cast<intptr_t*>(argc_ptr);
1502 intptr_t args_size =
1503 (StandardFrameConstants::kFixedSlotCountAboveFp + argc) * kPointerSize;
1504 Address receiver_ptr = fp() + args_size;
1505 return *reinterpret_cast<Object**>(receiver_ptr);
1506 } else {
1507 return JavaScriptFrame::receiver();
1508 }
1509 }
1510
GetFunctions(List<SharedFunctionInfo * > * functions) const1511 void OptimizedFrame::GetFunctions(List<SharedFunctionInfo*>* functions) const {
1512 DCHECK(functions->length() == 0);
1513 DCHECK(is_optimized());
1514
1515 // Delegate to JS frame in absence of turbofan deoptimization.
1516 // TODO(turbofan): Revisit once we support deoptimization across the board.
1517 Code* code = LookupCode();
1518 if (code->kind() == Code::BUILTIN ||
1519 CannotDeoptFromAsmCode(code, function())) {
1520 return JavaScriptFrame::GetFunctions(functions);
1521 }
1522
1523 DisallowHeapAllocation no_gc;
1524 int deopt_index = Safepoint::kNoDeoptimizationIndex;
1525 DeoptimizationInputData* const data = GetDeoptimizationData(&deopt_index);
1526 DCHECK_NOT_NULL(data);
1527 DCHECK_NE(Safepoint::kNoDeoptimizationIndex, deopt_index);
1528 FixedArray* const literal_array = data->LiteralArray();
1529
1530 TranslationIterator it(data->TranslationByteArray(),
1531 data->TranslationIndex(deopt_index)->value());
1532 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
1533 DCHECK_EQ(Translation::BEGIN, opcode);
1534 it.Next(); // Skip frame count.
1535 int jsframe_count = it.Next();
1536
1537 // We insert the frames in reverse order because the frames
1538 // in the deoptimization translation are ordered bottom-to-top.
1539 while (jsframe_count != 0) {
1540 opcode = static_cast<Translation::Opcode>(it.Next());
1541 if (opcode == Translation::JS_FRAME ||
1542 opcode == Translation::INTERPRETED_FRAME) {
1543 it.Next(); // Skip bailout id.
1544 jsframe_count--;
1545
1546 // The second operand of the frame points to the function.
1547 Object* shared = literal_array->get(it.Next());
1548 functions->Add(SharedFunctionInfo::cast(shared));
1549
1550 // Skip over remaining operands to advance to the next opcode.
1551 it.Skip(Translation::NumberOfOperandsFor(opcode) - 2);
1552 } else {
1553 // Skip over operands to advance to the next opcode.
1554 it.Skip(Translation::NumberOfOperandsFor(opcode));
1555 }
1556 }
1557 }
1558
1559
StackSlotOffsetRelativeToFp(int slot_index)1560 int OptimizedFrame::StackSlotOffsetRelativeToFp(int slot_index) {
1561 return StandardFrameConstants::kCallerSPOffset -
1562 ((slot_index + 1) * kPointerSize);
1563 }
1564
1565
StackSlotAt(int index) const1566 Object* OptimizedFrame::StackSlotAt(int index) const {
1567 return Memory::Object_at(fp() + StackSlotOffsetRelativeToFp(index));
1568 }
1569
position() const1570 int InterpretedFrame::position() const {
1571 AbstractCode* code = AbstractCode::cast(GetBytecodeArray());
1572 int code_offset = GetBytecodeOffset();
1573 return code->SourcePosition(code_offset);
1574 }
1575
LookupExceptionHandlerInTable(int * context_register,HandlerTable::CatchPrediction * prediction)1576 int InterpretedFrame::LookupExceptionHandlerInTable(
1577 int* context_register, HandlerTable::CatchPrediction* prediction) {
1578 BytecodeArray* bytecode = function()->shared()->bytecode_array();
1579 HandlerTable* table = HandlerTable::cast(bytecode->handler_table());
1580 return table->LookupRange(GetBytecodeOffset(), context_register, prediction);
1581 }
1582
GetBytecodeOffset() const1583 int InterpretedFrame::GetBytecodeOffset() const {
1584 const int index = InterpreterFrameConstants::kBytecodeOffsetExpressionIndex;
1585 DCHECK_EQ(
1586 InterpreterFrameConstants::kBytecodeOffsetFromFp,
1587 InterpreterFrameConstants::kExpressionsOffset - index * kPointerSize);
1588 int raw_offset = Smi::cast(GetExpression(index))->value();
1589 return raw_offset - BytecodeArray::kHeaderSize + kHeapObjectTag;
1590 }
1591
GetBytecodeOffset(Address fp)1592 int InterpretedFrame::GetBytecodeOffset(Address fp) {
1593 const int offset = InterpreterFrameConstants::kExpressionsOffset;
1594 const int index = InterpreterFrameConstants::kBytecodeOffsetExpressionIndex;
1595 DCHECK_EQ(
1596 InterpreterFrameConstants::kBytecodeOffsetFromFp,
1597 InterpreterFrameConstants::kExpressionsOffset - index * kPointerSize);
1598 Address expression_offset = fp + offset - index * kPointerSize;
1599 int raw_offset = Smi::cast(Memory::Object_at(expression_offset))->value();
1600 return raw_offset - BytecodeArray::kHeaderSize + kHeapObjectTag;
1601 }
1602
PatchBytecodeOffset(int new_offset)1603 void InterpretedFrame::PatchBytecodeOffset(int new_offset) {
1604 const int index = InterpreterFrameConstants::kBytecodeOffsetExpressionIndex;
1605 DCHECK_EQ(
1606 InterpreterFrameConstants::kBytecodeOffsetFromFp,
1607 InterpreterFrameConstants::kExpressionsOffset - index * kPointerSize);
1608 int raw_offset = new_offset + BytecodeArray::kHeaderSize - kHeapObjectTag;
1609 SetExpression(index, Smi::FromInt(raw_offset));
1610 }
1611
GetBytecodeArray() const1612 BytecodeArray* InterpretedFrame::GetBytecodeArray() const {
1613 const int index = InterpreterFrameConstants::kBytecodeArrayExpressionIndex;
1614 DCHECK_EQ(
1615 InterpreterFrameConstants::kBytecodeArrayFromFp,
1616 InterpreterFrameConstants::kExpressionsOffset - index * kPointerSize);
1617 return BytecodeArray::cast(GetExpression(index));
1618 }
1619
PatchBytecodeArray(BytecodeArray * bytecode_array)1620 void InterpretedFrame::PatchBytecodeArray(BytecodeArray* bytecode_array) {
1621 const int index = InterpreterFrameConstants::kBytecodeArrayExpressionIndex;
1622 DCHECK_EQ(
1623 InterpreterFrameConstants::kBytecodeArrayFromFp,
1624 InterpreterFrameConstants::kExpressionsOffset - index * kPointerSize);
1625 SetExpression(index, bytecode_array);
1626 }
1627
ReadInterpreterRegister(int register_index) const1628 Object* InterpretedFrame::ReadInterpreterRegister(int register_index) const {
1629 const int index = InterpreterFrameConstants::kRegisterFileExpressionIndex;
1630 DCHECK_EQ(
1631 InterpreterFrameConstants::kRegisterFileFromFp,
1632 InterpreterFrameConstants::kExpressionsOffset - index * kPointerSize);
1633 return GetExpression(index + register_index);
1634 }
1635
WriteInterpreterRegister(int register_index,Object * value)1636 void InterpretedFrame::WriteInterpreterRegister(int register_index,
1637 Object* value) {
1638 const int index = InterpreterFrameConstants::kRegisterFileExpressionIndex;
1639 DCHECK_EQ(
1640 InterpreterFrameConstants::kRegisterFileFromFp,
1641 InterpreterFrameConstants::kExpressionsOffset - index * kPointerSize);
1642 return SetExpression(index + register_index, value);
1643 }
1644
Summarize(List<FrameSummary> * functions,FrameSummary::Mode mode) const1645 void InterpretedFrame::Summarize(List<FrameSummary>* functions,
1646 FrameSummary::Mode mode) const {
1647 DCHECK(functions->length() == 0);
1648 AbstractCode* abstract_code =
1649 AbstractCode::cast(function()->shared()->bytecode_array());
1650 FrameSummary::JavaScriptFrameSummary summary(
1651 isolate(), receiver(), function(), abstract_code, GetBytecodeOffset(),
1652 IsConstructor());
1653 functions->Add(summary);
1654 }
1655
GetNumberOfIncomingArguments() const1656 int ArgumentsAdaptorFrame::GetNumberOfIncomingArguments() const {
1657 return Smi::cast(GetExpression(0))->value();
1658 }
1659
GetLength(Address fp)1660 int ArgumentsAdaptorFrame::GetLength(Address fp) {
1661 const int offset = ArgumentsAdaptorFrameConstants::kLengthOffset;
1662 return Smi::cast(Memory::Object_at(fp + offset))->value();
1663 }
1664
unchecked_code() const1665 Code* ArgumentsAdaptorFrame::unchecked_code() const {
1666 return isolate()->builtins()->builtin(
1667 Builtins::kArgumentsAdaptorTrampoline);
1668 }
1669
GetNumberOfIncomingArguments() const1670 int BuiltinFrame::GetNumberOfIncomingArguments() const {
1671 return Smi::cast(GetExpression(0))->value();
1672 }
1673
PrintFrameKind(StringStream * accumulator) const1674 void BuiltinFrame::PrintFrameKind(StringStream* accumulator) const {
1675 accumulator->Add("builtin frame: ");
1676 }
1677
GetCallerStackPointer() const1678 Address InternalFrame::GetCallerStackPointer() const {
1679 // Internal frames have no arguments. The stack pointer of the
1680 // caller is at a fixed offset from the frame pointer.
1681 return fp() + StandardFrameConstants::kCallerSPOffset;
1682 }
1683
unchecked_code() const1684 Code* InternalFrame::unchecked_code() const {
1685 const int offset = InternalFrameConstants::kCodeOffset;
1686 Object* code = Memory::Object_at(fp() + offset);
1687 DCHECK(code != NULL);
1688 return reinterpret_cast<Code*>(code);
1689 }
1690
1691
PrintIndex(StringStream * accumulator,PrintMode mode,int index)1692 void StackFrame::PrintIndex(StringStream* accumulator,
1693 PrintMode mode,
1694 int index) {
1695 accumulator->Add((mode == OVERVIEW) ? "%5d: " : "[%d]: ", index);
1696 }
1697
Print(StringStream * accumulator,PrintMode mode,int index) const1698 void WasmCompiledFrame::Print(StringStream* accumulator, PrintMode mode,
1699 int index) const {
1700 PrintIndex(accumulator, mode, index);
1701 accumulator->Add("WASM [");
1702 Script* script = this->script();
1703 accumulator->PrintName(script->name());
1704 int pc = static_cast<int>(this->pc() - LookupCode()->instruction_start());
1705 Object* instance = this->wasm_instance();
1706 Vector<const uint8_t> raw_func_name =
1707 WasmInstanceObject::cast(instance)->compiled_module()->GetRawFunctionName(
1708 this->function_index());
1709 const int kMaxPrintedFunctionName = 64;
1710 char func_name[kMaxPrintedFunctionName + 1];
1711 int func_name_len = std::min(kMaxPrintedFunctionName, raw_func_name.length());
1712 memcpy(func_name, raw_func_name.start(), func_name_len);
1713 func_name[func_name_len] = '\0';
1714 accumulator->Add("], function #%u ('%s'), pc=%p, pos=%d\n",
1715 this->function_index(), func_name, pc, this->position());
1716 if (mode != OVERVIEW) accumulator->Add("\n");
1717 }
1718
unchecked_code() const1719 Code* WasmCompiledFrame::unchecked_code() const {
1720 return isolate()->FindCodeObject(pc());
1721 }
1722
Iterate(ObjectVisitor * v) const1723 void WasmCompiledFrame::Iterate(ObjectVisitor* v) const {
1724 IterateCompiledFrame(v);
1725 }
1726
GetCallerStackPointer() const1727 Address WasmCompiledFrame::GetCallerStackPointer() const {
1728 return fp() + ExitFrameConstants::kCallerSPOffset;
1729 }
1730
wasm_instance() const1731 WasmInstanceObject* WasmCompiledFrame::wasm_instance() const {
1732 WasmInstanceObject* obj = wasm::GetOwningWasmInstance(LookupCode());
1733 // This is a live stack frame; it must have a live instance.
1734 DCHECK_NOT_NULL(obj);
1735 return obj;
1736 }
1737
function_index() const1738 uint32_t WasmCompiledFrame::function_index() const {
1739 return FrameSummary::GetSingle(this).AsWasmCompiled().function_index();
1740 }
1741
script() const1742 Script* WasmCompiledFrame::script() const {
1743 return wasm_instance()->compiled_module()->script();
1744 }
1745
position() const1746 int WasmCompiledFrame::position() const {
1747 return FrameSummary::GetSingle(this).SourcePosition();
1748 }
1749
Summarize(List<FrameSummary> * functions,FrameSummary::Mode mode) const1750 void WasmCompiledFrame::Summarize(List<FrameSummary>* functions,
1751 FrameSummary::Mode mode) const {
1752 DCHECK_EQ(0, functions->length());
1753 Handle<Code> code(LookupCode(), isolate());
1754 int offset = static_cast<int>(pc() - code->instruction_start());
1755 Handle<WasmInstanceObject> instance(wasm_instance(), isolate());
1756 FrameSummary::WasmCompiledFrameSummary summary(
1757 isolate(), instance, code, offset, at_to_number_conversion());
1758 functions->Add(summary);
1759 }
1760
at_to_number_conversion() const1761 bool WasmCompiledFrame::at_to_number_conversion() const {
1762 // Check whether our callee is a WASM_TO_JS frame, and this frame is at the
1763 // ToNumber conversion call.
1764 Address callee_pc = reinterpret_cast<Address>(this->callee_pc());
1765 Code* code = callee_pc ? isolate()->FindCodeObject(callee_pc) : nullptr;
1766 if (!code || code->kind() != Code::WASM_TO_JS_FUNCTION) return false;
1767 int offset = static_cast<int>(callee_pc - code->instruction_start());
1768 int pos = AbstractCode::cast(code)->SourcePosition(offset);
1769 DCHECK(pos == 0 || pos == 1);
1770 // The imported call has position 0, ToNumber has position 1.
1771 return !!pos;
1772 }
1773
LookupExceptionHandlerInTable(int * stack_slots)1774 int WasmCompiledFrame::LookupExceptionHandlerInTable(int* stack_slots) {
1775 DCHECK_NOT_NULL(stack_slots);
1776 Code* code = LookupCode();
1777 HandlerTable* table = HandlerTable::cast(code->handler_table());
1778 int pc_offset = static_cast<int>(pc() - code->entry());
1779 *stack_slots = code->stack_slots();
1780 return table->LookupReturn(pc_offset);
1781 }
1782
Iterate(ObjectVisitor * v) const1783 void WasmInterpreterEntryFrame::Iterate(ObjectVisitor* v) const {
1784 IterateCompiledFrame(v);
1785 }
1786
Print(StringStream * accumulator,PrintMode mode,int index) const1787 void WasmInterpreterEntryFrame::Print(StringStream* accumulator, PrintMode mode,
1788 int index) const {
1789 PrintIndex(accumulator, mode, index);
1790 accumulator->Add("WASM INTERPRETER ENTRY [");
1791 Script* script = this->script();
1792 accumulator->PrintName(script->name());
1793 accumulator->Add("]");
1794 if (mode != OVERVIEW) accumulator->Add("\n");
1795 }
1796
Summarize(List<FrameSummary> * functions,FrameSummary::Mode mode) const1797 void WasmInterpreterEntryFrame::Summarize(List<FrameSummary>* functions,
1798 FrameSummary::Mode mode) const {
1799 Handle<WasmInstanceObject> instance(wasm_instance(), isolate());
1800 std::vector<std::pair<uint32_t, int>> interpreted_stack =
1801 instance->debug_info()->GetInterpretedStack(fp());
1802
1803 for (auto& e : interpreted_stack) {
1804 FrameSummary::WasmInterpretedFrameSummary summary(isolate(), instance,
1805 e.first, e.second);
1806 functions->Add(summary);
1807 }
1808 }
1809
unchecked_code() const1810 Code* WasmInterpreterEntryFrame::unchecked_code() const {
1811 return isolate()->FindCodeObject(pc());
1812 }
1813
wasm_instance() const1814 WasmInstanceObject* WasmInterpreterEntryFrame::wasm_instance() const {
1815 WasmInstanceObject* ret = wasm::GetOwningWasmInstance(LookupCode());
1816 // This is a live stack frame, there must be a live wasm instance available.
1817 DCHECK_NOT_NULL(ret);
1818 return ret;
1819 }
1820
script() const1821 Script* WasmInterpreterEntryFrame::script() const {
1822 return wasm_instance()->compiled_module()->script();
1823 }
1824
position() const1825 int WasmInterpreterEntryFrame::position() const {
1826 return FrameSummary::GetBottom(this).AsWasmInterpreted().SourcePosition();
1827 }
1828
GetCallerStackPointer() const1829 Address WasmInterpreterEntryFrame::GetCallerStackPointer() const {
1830 return fp() + ExitFrameConstants::kCallerSPOffset;
1831 }
1832
1833 namespace {
1834
1835
PrintFunctionSource(StringStream * accumulator,SharedFunctionInfo * shared,Code * code)1836 void PrintFunctionSource(StringStream* accumulator, SharedFunctionInfo* shared,
1837 Code* code) {
1838 if (FLAG_max_stack_trace_source_length != 0 && code != NULL) {
1839 std::ostringstream os;
1840 os << "--------- s o u r c e c o d e ---------\n"
1841 << SourceCodeOf(shared, FLAG_max_stack_trace_source_length)
1842 << "\n-----------------------------------------\n";
1843 accumulator->Add(os.str().c_str());
1844 }
1845 }
1846
1847
1848 } // namespace
1849
1850
Print(StringStream * accumulator,PrintMode mode,int index) const1851 void JavaScriptFrame::Print(StringStream* accumulator,
1852 PrintMode mode,
1853 int index) const {
1854 DisallowHeapAllocation no_gc;
1855 Object* receiver = this->receiver();
1856 JSFunction* function = this->function();
1857
1858 accumulator->PrintSecurityTokenIfChanged(function);
1859 PrintIndex(accumulator, mode, index);
1860 PrintFrameKind(accumulator);
1861 Code* code = NULL;
1862 if (IsConstructor()) accumulator->Add("new ");
1863 accumulator->PrintFunction(function, receiver, &code);
1864
1865 // Get scope information for nicer output, if possible. If code is NULL, or
1866 // doesn't contain scope info, scope_info will return 0 for the number of
1867 // parameters, stack local variables, context local variables, stack slots,
1868 // or context slots.
1869 SharedFunctionInfo* shared = function->shared();
1870 ScopeInfo* scope_info = shared->scope_info();
1871 Object* script_obj = shared->script();
1872 if (script_obj->IsScript()) {
1873 Script* script = Script::cast(script_obj);
1874 accumulator->Add(" [");
1875 accumulator->PrintName(script->name());
1876
1877 Address pc = this->pc();
1878 if (code != NULL && code->kind() == Code::FUNCTION &&
1879 pc >= code->instruction_start() && pc < code->instruction_end()) {
1880 int offset = static_cast<int>(pc - code->instruction_start());
1881 int source_pos = AbstractCode::cast(code)->SourcePosition(offset);
1882 int line = script->GetLineNumber(source_pos) + 1;
1883 accumulator->Add(":%d] [pc=%p]", line, pc);
1884 } else if (is_interpreted()) {
1885 const InterpretedFrame* iframe =
1886 reinterpret_cast<const InterpretedFrame*>(this);
1887 BytecodeArray* bytecodes = iframe->GetBytecodeArray();
1888 int offset = iframe->GetBytecodeOffset();
1889 int source_pos = AbstractCode::cast(bytecodes)->SourcePosition(offset);
1890 int line = script->GetLineNumber(source_pos) + 1;
1891 accumulator->Add(":%d] [bytecode=%p offset=%d]", line, bytecodes, offset);
1892 } else {
1893 int function_start_pos = shared->start_position();
1894 int line = script->GetLineNumber(function_start_pos) + 1;
1895 accumulator->Add(":~%d] [pc=%p]", line, pc);
1896 }
1897 }
1898
1899 accumulator->Add("(this=%o", receiver);
1900
1901 // Print the parameters.
1902 int parameters_count = ComputeParametersCount();
1903 for (int i = 0; i < parameters_count; i++) {
1904 accumulator->Add(",");
1905 // If we have a name for the parameter we print it. Nameless
1906 // parameters are either because we have more actual parameters
1907 // than formal parameters or because we have no scope information.
1908 if (i < scope_info->ParameterCount()) {
1909 accumulator->PrintName(scope_info->ParameterName(i));
1910 accumulator->Add("=");
1911 }
1912 accumulator->Add("%o", GetParameter(i));
1913 }
1914
1915 accumulator->Add(")");
1916 if (mode == OVERVIEW) {
1917 accumulator->Add("\n");
1918 return;
1919 }
1920 if (is_optimized()) {
1921 accumulator->Add(" {\n// optimized frame\n");
1922 PrintFunctionSource(accumulator, shared, code);
1923 accumulator->Add("}\n");
1924 return;
1925 }
1926 accumulator->Add(" {\n");
1927
1928 // Compute the number of locals and expression stack elements.
1929 int stack_locals_count = scope_info->StackLocalCount();
1930 int heap_locals_count = scope_info->ContextLocalCount();
1931 int expressions_count = ComputeExpressionsCount();
1932
1933 // Print stack-allocated local variables.
1934 if (stack_locals_count > 0) {
1935 accumulator->Add(" // stack-allocated locals\n");
1936 }
1937 for (int i = 0; i < stack_locals_count; i++) {
1938 accumulator->Add(" var ");
1939 accumulator->PrintName(scope_info->StackLocalName(i));
1940 accumulator->Add(" = ");
1941 if (i < expressions_count) {
1942 accumulator->Add("%o", GetExpression(i));
1943 } else {
1944 accumulator->Add("// no expression found - inconsistent frame?");
1945 }
1946 accumulator->Add("\n");
1947 }
1948
1949 // Try to get hold of the context of this frame.
1950 Context* context = NULL;
1951 if (this->context() != NULL && this->context()->IsContext()) {
1952 context = Context::cast(this->context());
1953 }
1954 while (context->IsWithContext()) {
1955 context = context->previous();
1956 DCHECK(context != NULL);
1957 }
1958
1959 // Print heap-allocated local variables.
1960 if (heap_locals_count > 0) {
1961 accumulator->Add(" // heap-allocated locals\n");
1962 }
1963 for (int i = 0; i < heap_locals_count; i++) {
1964 accumulator->Add(" var ");
1965 accumulator->PrintName(scope_info->ContextLocalName(i));
1966 accumulator->Add(" = ");
1967 if (context != NULL) {
1968 int index = Context::MIN_CONTEXT_SLOTS + i;
1969 if (index < context->length()) {
1970 accumulator->Add("%o", context->get(index));
1971 } else {
1972 accumulator->Add(
1973 "// warning: missing context slot - inconsistent frame?");
1974 }
1975 } else {
1976 accumulator->Add("// warning: no context found - inconsistent frame?");
1977 }
1978 accumulator->Add("\n");
1979 }
1980
1981 // Print the expression stack.
1982 int expressions_start = stack_locals_count;
1983 if (expressions_start < expressions_count) {
1984 accumulator->Add(" // expression stack (top to bottom)\n");
1985 }
1986 for (int i = expressions_count - 1; i >= expressions_start; i--) {
1987 accumulator->Add(" [%02d] : %o\n", i, GetExpression(i));
1988 }
1989
1990 PrintFunctionSource(accumulator, shared, code);
1991
1992 accumulator->Add("}\n\n");
1993 }
1994
1995
Print(StringStream * accumulator,PrintMode mode,int index) const1996 void ArgumentsAdaptorFrame::Print(StringStream* accumulator,
1997 PrintMode mode,
1998 int index) const {
1999 int actual = ComputeParametersCount();
2000 int expected = -1;
2001 JSFunction* function = this->function();
2002 expected = function->shared()->internal_formal_parameter_count();
2003
2004 PrintIndex(accumulator, mode, index);
2005 accumulator->Add("arguments adaptor frame: %d->%d", actual, expected);
2006 if (mode == OVERVIEW) {
2007 accumulator->Add("\n");
2008 return;
2009 }
2010 accumulator->Add(" {\n");
2011
2012 // Print actual arguments.
2013 if (actual > 0) accumulator->Add(" // actual arguments\n");
2014 for (int i = 0; i < actual; i++) {
2015 accumulator->Add(" [%02d] : %o", i, GetParameter(i));
2016 if (expected != -1 && i >= expected) {
2017 accumulator->Add(" // not passed to callee");
2018 }
2019 accumulator->Add("\n");
2020 }
2021
2022 accumulator->Add("}\n\n");
2023 }
2024
2025
Iterate(ObjectVisitor * v) const2026 void EntryFrame::Iterate(ObjectVisitor* v) const {
2027 IteratePc(v, pc_address(), constant_pool_address(), LookupCode());
2028 }
2029
2030
IterateExpressions(ObjectVisitor * v) const2031 void StandardFrame::IterateExpressions(ObjectVisitor* v) const {
2032 const int offset = StandardFrameConstants::kLastObjectOffset;
2033 Object** base = &Memory::Object_at(sp());
2034 Object** limit = &Memory::Object_at(fp() + offset) + 1;
2035 v->VisitPointers(base, limit);
2036 }
2037
2038
Iterate(ObjectVisitor * v) const2039 void JavaScriptFrame::Iterate(ObjectVisitor* v) const {
2040 IterateExpressions(v);
2041 IteratePc(v, pc_address(), constant_pool_address(), LookupCode());
2042 }
2043
Iterate(ObjectVisitor * v) const2044 void InternalFrame::Iterate(ObjectVisitor* v) const {
2045 // Internal frames only have object pointers on the expression stack
2046 // as they never have any arguments.
2047 IterateExpressions(v);
2048 IteratePc(v, pc_address(), constant_pool_address(), LookupCode());
2049 }
2050
2051
Iterate(ObjectVisitor * v) const2052 void StubFailureTrampolineFrame::Iterate(ObjectVisitor* v) const {
2053 Object** base = &Memory::Object_at(sp());
2054 Object** limit = &Memory::Object_at(
2055 fp() + StubFailureTrampolineFrameConstants::kFixedHeaderBottomOffset);
2056 v->VisitPointers(base, limit);
2057 base = &Memory::Object_at(fp() + StandardFrameConstants::kFunctionOffset);
2058 const int offset = StandardFrameConstants::kLastObjectOffset;
2059 limit = &Memory::Object_at(fp() + offset) + 1;
2060 v->VisitPointers(base, limit);
2061 IteratePc(v, pc_address(), constant_pool_address(), LookupCode());
2062 }
2063
2064
GetCallerStackPointer() const2065 Address StubFailureTrampolineFrame::GetCallerStackPointer() const {
2066 return fp() + StandardFrameConstants::kCallerSPOffset;
2067 }
2068
2069
unchecked_code() const2070 Code* StubFailureTrampolineFrame::unchecked_code() const {
2071 Code* trampoline;
2072 StubFailureTrampolineStub(isolate(), NOT_JS_FUNCTION_STUB_MODE).
2073 FindCodeInCache(&trampoline);
2074 if (trampoline->contains(pc())) {
2075 return trampoline;
2076 }
2077
2078 StubFailureTrampolineStub(isolate(), JS_FUNCTION_STUB_MODE).
2079 FindCodeInCache(&trampoline);
2080 if (trampoline->contains(pc())) {
2081 return trampoline;
2082 }
2083
2084 UNREACHABLE();
2085 return NULL;
2086 }
2087
2088
2089 // -------------------------------------------------------------------------
2090
2091
FindJavaScriptFrame(int n)2092 JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) {
2093 DCHECK(n >= 0);
2094 for (int i = 0; i <= n; i++) {
2095 while (!iterator_.frame()->is_java_script()) iterator_.Advance();
2096 if (i == n) return JavaScriptFrame::cast(iterator_.frame());
2097 iterator_.Advance();
2098 }
2099 UNREACHABLE();
2100 return NULL;
2101 }
2102
2103
2104 // -------------------------------------------------------------------------
2105
2106
GcSafeMapOfCodeSpaceObject(HeapObject * object)2107 static Map* GcSafeMapOfCodeSpaceObject(HeapObject* object) {
2108 MapWord map_word = object->map_word();
2109 return map_word.IsForwardingAddress() ?
2110 map_word.ToForwardingAddress()->map() : map_word.ToMap();
2111 }
2112
2113
GcSafeSizeOfCodeSpaceObject(HeapObject * object)2114 static int GcSafeSizeOfCodeSpaceObject(HeapObject* object) {
2115 return object->SizeFromMap(GcSafeMapOfCodeSpaceObject(object));
2116 }
2117
2118
2119 #ifdef DEBUG
GcSafeCodeContains(HeapObject * code,Address addr)2120 static bool GcSafeCodeContains(HeapObject* code, Address addr) {
2121 Map* map = GcSafeMapOfCodeSpaceObject(code);
2122 DCHECK(map == code->GetHeap()->code_map());
2123 Address start = code->address();
2124 Address end = code->address() + code->SizeFromMap(map);
2125 return start <= addr && addr < end;
2126 }
2127 #endif
2128
2129
GcSafeCastToCode(HeapObject * object,Address inner_pointer)2130 Code* InnerPointerToCodeCache::GcSafeCastToCode(HeapObject* object,
2131 Address inner_pointer) {
2132 Code* code = reinterpret_cast<Code*>(object);
2133 DCHECK(code != NULL && GcSafeCodeContains(code, inner_pointer));
2134 return code;
2135 }
2136
2137
GcSafeFindCodeForInnerPointer(Address inner_pointer)2138 Code* InnerPointerToCodeCache::GcSafeFindCodeForInnerPointer(
2139 Address inner_pointer) {
2140 Heap* heap = isolate_->heap();
2141
2142 // Check if the inner pointer points into a large object chunk.
2143 LargePage* large_page = heap->lo_space()->FindPage(inner_pointer);
2144 if (large_page != NULL) {
2145 return GcSafeCastToCode(large_page->GetObject(), inner_pointer);
2146 }
2147
2148 if (!heap->code_space()->Contains(inner_pointer)) {
2149 return nullptr;
2150 }
2151
2152 // Iterate through the page until we reach the end or find an object starting
2153 // after the inner pointer.
2154 Page* page = Page::FromAddress(inner_pointer);
2155
2156 DCHECK_EQ(page->owner(), heap->code_space());
2157 heap->mark_compact_collector()->sweeper().SweepOrWaitUntilSweepingCompleted(
2158 page);
2159
2160 Address addr = page->skip_list()->StartFor(inner_pointer);
2161
2162 Address top = heap->code_space()->top();
2163 Address limit = heap->code_space()->limit();
2164
2165 while (true) {
2166 if (addr == top && addr != limit) {
2167 addr = limit;
2168 continue;
2169 }
2170
2171 HeapObject* obj = HeapObject::FromAddress(addr);
2172 int obj_size = GcSafeSizeOfCodeSpaceObject(obj);
2173 Address next_addr = addr + obj_size;
2174 if (next_addr > inner_pointer) return GcSafeCastToCode(obj, inner_pointer);
2175 addr = next_addr;
2176 }
2177 }
2178
2179
2180 InnerPointerToCodeCache::InnerPointerToCodeCacheEntry*
GetCacheEntry(Address inner_pointer)2181 InnerPointerToCodeCache::GetCacheEntry(Address inner_pointer) {
2182 isolate_->counters()->pc_to_code()->Increment();
2183 DCHECK(base::bits::IsPowerOfTwo32(kInnerPointerToCodeCacheSize));
2184 uint32_t hash = ComputeIntegerHash(ObjectAddressForHashing(inner_pointer),
2185 v8::internal::kZeroHashSeed);
2186 uint32_t index = hash & (kInnerPointerToCodeCacheSize - 1);
2187 InnerPointerToCodeCacheEntry* entry = cache(index);
2188 if (entry->inner_pointer == inner_pointer) {
2189 isolate_->counters()->pc_to_code_cached()->Increment();
2190 DCHECK(entry->code == GcSafeFindCodeForInnerPointer(inner_pointer));
2191 } else {
2192 // Because this code may be interrupted by a profiling signal that
2193 // also queries the cache, we cannot update inner_pointer before the code
2194 // has been set. Otherwise, we risk trying to use a cache entry before
2195 // the code has been computed.
2196 entry->code = GcSafeFindCodeForInnerPointer(inner_pointer);
2197 entry->safepoint_entry.Reset();
2198 entry->inner_pointer = inner_pointer;
2199 }
2200 return entry;
2201 }
2202
2203
2204 // -------------------------------------------------------------------------
2205
2206
NumRegs(RegList reglist)2207 int NumRegs(RegList reglist) { return base::bits::CountPopulation(reglist); }
2208
2209
2210 struct JSCallerSavedCodeData {
2211 int reg_code[kNumJSCallerSaved];
2212 };
2213
2214 JSCallerSavedCodeData caller_saved_code_data;
2215
SetUpJSCallerSavedCodeData()2216 void SetUpJSCallerSavedCodeData() {
2217 int i = 0;
2218 for (int r = 0; r < kNumRegs; r++)
2219 if ((kJSCallerSaved & (1 << r)) != 0)
2220 caller_saved_code_data.reg_code[i++] = r;
2221
2222 DCHECK(i == kNumJSCallerSaved);
2223 }
2224
2225
JSCallerSavedCode(int n)2226 int JSCallerSavedCode(int n) {
2227 DCHECK(0 <= n && n < kNumJSCallerSaved);
2228 return caller_saved_code_data.reg_code[n];
2229 }
2230
2231
2232 #define DEFINE_WRAPPER(type, field) \
2233 class field##_Wrapper : public ZoneObject { \
2234 public: /* NOLINT */ \
2235 field##_Wrapper(const field& original) : frame_(original) { \
2236 } \
2237 field frame_; \
2238 };
STACK_FRAME_TYPE_LIST(DEFINE_WRAPPER)2239 STACK_FRAME_TYPE_LIST(DEFINE_WRAPPER)
2240 #undef DEFINE_WRAPPER
2241
2242 static StackFrame* AllocateFrameCopy(StackFrame* frame, Zone* zone) {
2243 #define FRAME_TYPE_CASE(type, field) \
2244 case StackFrame::type: { \
2245 field##_Wrapper* wrapper = \
2246 new(zone) field##_Wrapper(*(reinterpret_cast<field*>(frame))); \
2247 return &wrapper->frame_; \
2248 }
2249
2250 switch (frame->type()) {
2251 STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
2252 default: UNREACHABLE();
2253 }
2254 #undef FRAME_TYPE_CASE
2255 return NULL;
2256 }
2257
2258
CreateStackMap(Isolate * isolate,Zone * zone)2259 Vector<StackFrame*> CreateStackMap(Isolate* isolate, Zone* zone) {
2260 ZoneList<StackFrame*> list(10, zone);
2261 for (StackFrameIterator it(isolate); !it.done(); it.Advance()) {
2262 StackFrame* frame = AllocateFrameCopy(it.frame(), zone);
2263 list.Add(frame, zone);
2264 }
2265 return list.ToVector();
2266 }
2267
2268
2269 } // namespace internal
2270 } // namespace v8
2271