• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/execution/frames.h"
6 
7 #include <memory>
8 #include <sstream>
9 
10 #include "src/base/bits.h"
11 #include "src/base/platform/wrappers.h"
12 #include "src/codegen/interface-descriptors.h"
13 #include "src/codegen/macro-assembler.h"
14 #include "src/codegen/register-configuration.h"
15 #include "src/codegen/safepoint-table.h"
16 #include "src/common/globals.h"
17 #include "src/deoptimizer/deoptimizer.h"
18 #include "src/execution/frames-inl.h"
19 #include "src/execution/vm-state-inl.h"
20 #include "src/ic/ic-stats.h"
21 #include "src/logging/counters.h"
22 #include "src/objects/code.h"
23 #include "src/objects/slots.h"
24 #include "src/objects/smi.h"
25 #include "src/objects/visitors.h"
26 #include "src/snapshot/embedded/embedded-data-inl.h"
27 #include "src/strings/string-stream.h"
28 #include "src/zone/zone-containers.h"
29 
30 #if V8_ENABLE_WEBASSEMBLY
31 #include "src/debug/debug-wasm-objects.h"
32 #include "src/wasm/wasm-code-manager.h"
33 #include "src/wasm/wasm-engine.h"
34 #include "src/wasm/wasm-objects-inl.h"
35 #endif  // V8_ENABLE_WEBASSEMBLY
36 
37 namespace v8 {
38 namespace internal {
39 
40 ReturnAddressLocationResolver StackFrame::return_address_location_resolver_ =
41     nullptr;
42 
43 namespace {
44 
AddressOf(const StackHandler * handler)45 Address AddressOf(const StackHandler* handler) {
46   Address raw = handler->address();
47 #ifdef V8_USE_ADDRESS_SANITIZER
48   // ASan puts C++-allocated StackHandler markers onto its fake stack.
49   // We work around that by storing the real stack address in the "padding"
50   // field. StackHandlers allocated from generated code have 0 as padding.
51   Address padding =
52       base::Memory<Address>(raw + StackHandlerConstants::kPaddingOffset);
53   if (padding != 0) return padding;
54 #endif
55   return raw;
56 }
57 
58 }  // namespace
59 
60 // Iterator that supports traversing the stack handlers of a
61 // particular frame. Needs to know the top of the handler chain.
62 class StackHandlerIterator {
63  public:
StackHandlerIterator(const StackFrame * frame,StackHandler * handler)64   StackHandlerIterator(const StackFrame* frame, StackHandler* handler)
65       : limit_(frame->fp()), handler_(handler) {
66 #if V8_ENABLE_WEBASSEMBLY
67     // Make sure the handler has already been unwound to this frame. With stack
68     // switching this is not equivalent to the inequality below, because the
69     // frame and the handler could be in different stacks.
70     DCHECK_IMPLIES(!FLAG_experimental_wasm_stack_switching,
71                    frame->sp() <= AddressOf(handler));
72     // For CWasmEntry frames, the handler was registered by the last C++
73     // frame (Execution::CallWasm), so even though its address is already
74     // beyond the limit, we know we always want to unwind one handler.
75     if (frame->is_c_wasm_entry()) handler_ = handler_->next();
76 #else
77     // Make sure the handler has already been unwound to this frame.
78     DCHECK_LE(frame->sp(), AddressOf(handler));
79 #endif  // V8_ENABLE_WEBASSEMBLY
80   }
81 
handler() const82   StackHandler* handler() const { return handler_; }
83 
done()84   bool done() { return handler_ == nullptr || AddressOf(handler_) > limit_; }
Advance()85   void Advance() {
86     DCHECK(!done());
87     handler_ = handler_->next();
88   }
89 
90  private:
91   const Address limit_;
92   StackHandler* handler_;
93 };
94 
95 // -------------------------------------------------------------------------
96 
97 #define INITIALIZE_SINGLETON(type, field) field##_(this),
StackFrameIteratorBase(Isolate * isolate,bool can_access_heap_objects)98 StackFrameIteratorBase::StackFrameIteratorBase(Isolate* isolate,
99                                                bool can_access_heap_objects)
100     : isolate_(isolate),
101       STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON) frame_(nullptr),
102       handler_(nullptr),
103       can_access_heap_objects_(can_access_heap_objects) {}
104 #undef INITIALIZE_SINGLETON
105 
StackFrameIterator(Isolate * isolate)106 StackFrameIterator::StackFrameIterator(Isolate* isolate)
107     : StackFrameIterator(isolate, isolate->thread_local_top()) {}
108 
StackFrameIterator(Isolate * isolate,ThreadLocalTop * t)109 StackFrameIterator::StackFrameIterator(Isolate* isolate, ThreadLocalTop* t)
110     : StackFrameIteratorBase(isolate, true) {
111   Reset(t);
112 }
113 #if V8_ENABLE_WEBASSEMBLY
StackFrameIterator(Isolate * isolate,wasm::StackMemory * stack)114 StackFrameIterator::StackFrameIterator(Isolate* isolate,
115                                        wasm::StackMemory* stack)
116     : StackFrameIteratorBase(isolate, true) {
117   Reset(isolate->thread_local_top(), stack);
118 }
119 #endif
120 
Advance()121 void StackFrameIterator::Advance() {
122   DCHECK(!done());
123   // Compute the state of the calling frame before restoring
124   // callee-saved registers and unwinding handlers. This allows the
125   // frame code that computes the caller state to access the top
126   // handler and the value of any callee-saved register if needed.
127   StackFrame::State state;
128   StackFrame::Type type = frame_->GetCallerState(&state);
129 
130   // Unwind handlers corresponding to the current frame.
131   StackHandlerIterator it(frame_, handler_);
132   while (!it.done()) it.Advance();
133   handler_ = it.handler();
134 
135   // Advance to the calling frame.
136   frame_ = SingletonFor(type, &state);
137 
138   // When we're done iterating over the stack frames, the handler
139   // chain must have been completely unwound. Except for wasm stack-switching:
140   // we stop at the end of the current segment.
141 #if V8_ENABLE_WEBASSEMBLY
142   DCHECK_IMPLIES(done() && !FLAG_experimental_wasm_stack_switching,
143                  handler_ == nullptr);
144 #else
145   DCHECK_IMPLIES(done(), handler_ == nullptr);
146 #endif
147 }
148 
Reframe()149 StackFrame* StackFrameIterator::Reframe() {
150   StackFrame::Type type = frame_->ComputeType(this, &frame_->state_);
151   frame_ = SingletonFor(type, &frame_->state_);
152   return frame();
153 }
154 
Reset(ThreadLocalTop * top)155 void StackFrameIterator::Reset(ThreadLocalTop* top) {
156   StackFrame::State state;
157   StackFrame::Type type =
158       ExitFrame::GetStateForFramePointer(Isolate::c_entry_fp(top), &state);
159   handler_ = StackHandler::FromAddress(Isolate::handler(top));
160   frame_ = SingletonFor(type, &state);
161 }
162 
163 #if V8_ENABLE_WEBASSEMBLY
Reset(ThreadLocalTop * top,wasm::StackMemory * stack)164 void StackFrameIterator::Reset(ThreadLocalTop* top, wasm::StackMemory* stack) {
165   if (stack->jmpbuf()->sp == kNullAddress) {
166     // A null SP indicates that the computation associated with this stack has
167     // returned, leaving the stack segment empty.
168     return;
169   }
170   StackFrame::State state;
171   StackSwitchFrame::GetStateForJumpBuffer(stack->jmpbuf(), &state);
172   handler_ = StackHandler::FromAddress(Isolate::handler(top));
173   frame_ = SingletonFor(StackFrame::STACK_SWITCH, &state);
174 }
175 #endif
176 
SingletonFor(StackFrame::Type type,StackFrame::State * state)177 StackFrame* StackFrameIteratorBase::SingletonFor(StackFrame::Type type,
178                                                  StackFrame::State* state) {
179   StackFrame* result = SingletonFor(type);
180   DCHECK((!result) == (type == StackFrame::NO_FRAME_TYPE));
181   if (result) result->state_ = *state;
182   return result;
183 }
184 
SingletonFor(StackFrame::Type type)185 StackFrame* StackFrameIteratorBase::SingletonFor(StackFrame::Type type) {
186 #define FRAME_TYPE_CASE(type, field) \
187   case StackFrame::type:             \
188     return &field##_;
189 
190   switch (type) {
191     case StackFrame::NO_FRAME_TYPE:
192       return nullptr;
193       STACK_FRAME_TYPE_LIST(FRAME_TYPE_CASE)
194     default:
195       break;
196   }
197   return nullptr;
198 
199 #undef FRAME_TYPE_CASE
200 }
201 
202 // -------------------------------------------------------------------------
203 
Iterate(RootVisitor * v) const204 void TypedFrameWithJSLinkage::Iterate(RootVisitor* v) const {
205   IterateExpressions(v);
206   IteratePc(v, pc_address(), constant_pool_address(), LookupCode());
207 }
208 
209 // -------------------------------------------------------------------------
210 
Advance()211 void JavaScriptFrameIterator::Advance() {
212   do {
213     iterator_.Advance();
214   } while (!iterator_.done() && !iterator_.frame()->is_java_script());
215 }
216 
217 // -------------------------------------------------------------------------
218 
StackTraceFrameIterator(Isolate * isolate)219 StackTraceFrameIterator::StackTraceFrameIterator(Isolate* isolate)
220     : iterator_(isolate) {
221   if (!done() && !IsValidFrame(iterator_.frame())) Advance();
222 }
223 
StackTraceFrameIterator(Isolate * isolate,StackFrameId id)224 StackTraceFrameIterator::StackTraceFrameIterator(Isolate* isolate,
225                                                  StackFrameId id)
226     : StackTraceFrameIterator(isolate) {
227   while (!done() && frame()->id() != id) Advance();
228 }
229 
Advance()230 void StackTraceFrameIterator::Advance() {
231   do {
232     iterator_.Advance();
233   } while (!done() && !IsValidFrame(iterator_.frame()));
234 }
235 
FrameFunctionCount() const236 int StackTraceFrameIterator::FrameFunctionCount() const {
237   DCHECK(!done());
238   if (!iterator_.frame()->is_optimized()) return 1;
239   std::vector<SharedFunctionInfo> infos;
240   OptimizedFrame::cast(iterator_.frame())->GetFunctions(&infos);
241   return static_cast<int>(infos.size());
242 }
243 
GetTopValidFrame() const244 FrameSummary StackTraceFrameIterator::GetTopValidFrame() const {
245   DCHECK(!done());
246   // Like FrameSummary::GetTop, but additionally observes
247   // StackTraceFrameIterator filtering semantics.
248   std::vector<FrameSummary> frames;
249   frame()->Summarize(&frames);
250   if (is_javascript()) {
251     for (int i = static_cast<int>(frames.size()) - 1; i >= 0; i--) {
252       if (!IsValidJSFunction(*frames[i].AsJavaScript().function())) continue;
253       return frames[i];
254     }
255     UNREACHABLE();
256   }
257 #if V8_ENABLE_WEBASSEMBLY
258   if (is_wasm()) return frames.back();
259 #endif  // V8_ENABLE_WEBASSEMBLY
260   UNREACHABLE();
261 }
262 
263 // static
IsValidFrame(StackFrame * frame)264 bool StackTraceFrameIterator::IsValidFrame(StackFrame* frame) {
265   if (frame->is_java_script()) {
266     return IsValidJSFunction(static_cast<JavaScriptFrame*>(frame)->function());
267   }
268 #if V8_ENABLE_WEBASSEMBLY
269   if (frame->is_wasm()) return true;
270 #endif  // V8_ENABLE_WEBASSEMBLY
271   return false;
272 }
273 
274 // static
IsValidJSFunction(JSFunction f)275 bool StackTraceFrameIterator::IsValidJSFunction(JSFunction f) {
276   if (!f.IsJSFunction()) return false;
277   return f.shared().IsSubjectToDebugging();
278 }
279 
280 // -------------------------------------------------------------------------
281 
282 namespace {
283 
IsInterpreterFramePc(Isolate * isolate,Address pc,StackFrame::State * state)284 bool IsInterpreterFramePc(Isolate* isolate, Address pc,
285                           StackFrame::State* state) {
286   Builtin builtin = OffHeapInstructionStream::TryLookupCode(isolate, pc);
287   if (builtin != Builtin::kNoBuiltinId &&
288       (builtin == Builtin::kInterpreterEntryTrampoline ||
289        builtin == Builtin::kInterpreterEnterAtBytecode ||
290        builtin == Builtin::kInterpreterEnterAtNextBytecode ||
291        builtin == Builtin::kBaselineOrInterpreterEnterAtBytecode ||
292        builtin == Builtin::kBaselineOrInterpreterEnterAtNextBytecode)) {
293     return true;
294   } else if (FLAG_interpreted_frames_native_stack) {
295     intptr_t marker = Memory<intptr_t>(
296         state->fp + CommonFrameConstants::kContextOrFrameTypeOffset);
297     MSAN_MEMORY_IS_INITIALIZED(
298         state->fp + StandardFrameConstants::kFunctionOffset,
299         kSystemPointerSize);
300     Object maybe_function = Object(
301         Memory<Address>(state->fp + StandardFrameConstants::kFunctionOffset));
302     // There's no need to run a full ContainsSlow if we know the frame can't be
303     // an InterpretedFrame,  so we do these fast checks first
304     if (StackFrame::IsTypeMarker(marker) || maybe_function.IsSmi()) {
305       return false;
306     } else if (!isolate->heap()->InSpaceSlow(pc, CODE_SPACE)) {
307       return false;
308     }
309     Code interpreter_entry_trampoline =
310         isolate->heap()->GcSafeFindCodeForInnerPointer(pc);
311     return interpreter_entry_trampoline.is_interpreter_trampoline_builtin();
312   } else {
313     return false;
314   }
315 }
316 
317 }  // namespace
318 
IsNoFrameBytecodeHandlerPc(Isolate * isolate,Address pc,Address fp) const319 bool SafeStackFrameIterator::IsNoFrameBytecodeHandlerPc(Isolate* isolate,
320                                                         Address pc,
321                                                         Address fp) const {
322   // Return false for builds with non-embedded bytecode handlers.
323   if (Isolate::CurrentEmbeddedBlobCode() == nullptr) return false;
324 
325   EmbeddedData d = EmbeddedData::FromBlob(isolate);
326   if (pc < d.InstructionStartOfBytecodeHandlers() ||
327       pc >= d.InstructionEndOfBytecodeHandlers()) {
328     // Not a bytecode handler pc address.
329     return false;
330   }
331 
332   if (!IsValidStackAddress(fp +
333                            CommonFrameConstants::kContextOrFrameTypeOffset)) {
334     return false;
335   }
336 
337   // Check if top stack frame is a bytecode handler stub frame.
338   MSAN_MEMORY_IS_INITIALIZED(
339       fp + CommonFrameConstants::kContextOrFrameTypeOffset, kSystemPointerSize);
340   intptr_t marker =
341       Memory<intptr_t>(fp + CommonFrameConstants::kContextOrFrameTypeOffset);
342   if (StackFrame::IsTypeMarker(marker) &&
343       StackFrame::MarkerToType(marker) == StackFrame::STUB) {
344     // Bytecode handler built a frame.
345     return false;
346   }
347   return true;
348 }
349 
SafeStackFrameIterator(Isolate * isolate,Address pc,Address fp,Address sp,Address lr,Address js_entry_sp)350 SafeStackFrameIterator::SafeStackFrameIterator(Isolate* isolate, Address pc,
351                                                Address fp, Address sp,
352                                                Address lr, Address js_entry_sp)
353     : StackFrameIteratorBase(isolate, false),
354       low_bound_(sp),
355       high_bound_(js_entry_sp),
356       top_frame_type_(StackFrame::NO_FRAME_TYPE),
357       top_context_address_(kNullAddress),
358       external_callback_scope_(isolate->external_callback_scope()),
359       top_link_register_(lr) {
360   StackFrame::State state;
361   StackFrame::Type type;
362   ThreadLocalTop* top = isolate->thread_local_top();
363   bool advance_frame = true;
364 
365   Address fast_c_fp = isolate->isolate_data()->fast_c_call_caller_fp();
366   uint8_t stack_is_iterable = isolate->isolate_data()->stack_is_iterable();
367   if (!stack_is_iterable) {
368     frame_ = nullptr;
369     return;
370   }
371   // 'Fast C calls' are a special type of C call where we call directly from
372   // JS to C without an exit frame inbetween. The CEntryStub is responsible
373   // for setting Isolate::c_entry_fp, meaning that it won't be set for fast C
374   // calls. To keep the stack iterable, we store the FP and PC of the caller
375   // of the fast C call on the isolate. This is guaranteed to be the topmost
376   // JS frame, because fast C calls cannot call back into JS. We start
377   // iterating the stack from this topmost JS frame.
378   if (fast_c_fp) {
379     DCHECK_NE(kNullAddress, isolate->isolate_data()->fast_c_call_caller_pc());
380     type = StackFrame::Type::OPTIMIZED;
381     top_frame_type_ = type;
382     state.fp = fast_c_fp;
383     state.sp = sp;
384     state.pc_address = reinterpret_cast<Address*>(
385         isolate->isolate_data()->fast_c_call_caller_pc_address());
386     advance_frame = false;
387   } else if (IsValidTop(top)) {
388     type = ExitFrame::GetStateForFramePointer(Isolate::c_entry_fp(top), &state);
389     top_frame_type_ = type;
390   } else if (IsValidStackAddress(fp)) {
391     DCHECK_NE(fp, kNullAddress);
392     state.fp = fp;
393     state.sp = sp;
394     state.pc_address = StackFrame::ResolveReturnAddressLocation(
395         reinterpret_cast<Address*>(CommonFrame::ComputePCAddress(fp)));
396 
397     // If the current PC is in a bytecode handler, the top stack frame isn't
398     // the bytecode handler's frame and the top of stack or link register is a
399     // return address into the interpreter entry trampoline, then we are likely
400     // in a bytecode handler with elided frame. In that case, set the PC
401     // properly and make sure we do not drop the frame.
402     bool is_no_frame_bytecode_handler = false;
403     if (IsNoFrameBytecodeHandlerPc(isolate, pc, fp)) {
404       Address* tos_location = nullptr;
405       if (top_link_register_) {
406         tos_location = &top_link_register_;
407       } else if (IsValidStackAddress(sp)) {
408         MSAN_MEMORY_IS_INITIALIZED(sp, kSystemPointerSize);
409         tos_location = reinterpret_cast<Address*>(sp);
410       }
411 
412       if (IsInterpreterFramePc(isolate, *tos_location, &state)) {
413         state.pc_address = tos_location;
414         is_no_frame_bytecode_handler = true;
415         advance_frame = false;
416       }
417     }
418 
419     // StackFrame::ComputeType will read both kContextOffset and kMarkerOffset,
420     // we check only that kMarkerOffset is within the stack bounds and do
421     // compile time check that kContextOffset slot is pushed on the stack before
422     // kMarkerOffset.
423     STATIC_ASSERT(StandardFrameConstants::kFunctionOffset <
424                   StandardFrameConstants::kContextOffset);
425     Address frame_marker = fp + StandardFrameConstants::kFunctionOffset;
426     if (IsValidStackAddress(frame_marker)) {
427       if (is_no_frame_bytecode_handler) {
428         type = StackFrame::INTERPRETED;
429       } else {
430         type = StackFrame::ComputeType(this, &state);
431       }
432       top_frame_type_ = type;
433       MSAN_MEMORY_IS_INITIALIZED(
434           fp + CommonFrameConstants::kContextOrFrameTypeOffset,
435           kSystemPointerSize);
436       Address type_or_context_address =
437           Memory<Address>(fp + CommonFrameConstants::kContextOrFrameTypeOffset);
438       if (!StackFrame::IsTypeMarker(type_or_context_address))
439         top_context_address_ = type_or_context_address;
440     } else {
441       // Mark the frame as OPTIMIZED if we cannot determine its type.
442       // We chose OPTIMIZED rather than INTERPRETED because it's closer to
443       // the original value of StackFrame::JAVA_SCRIPT here, in that JAVA_SCRIPT
444       // referred to full-codegen frames (now removed from the tree), and
445       // OPTIMIZED refers to turbofan frames, both of which are generated
446       // code. INTERPRETED frames refer to bytecode.
447       // The frame anyways will be skipped.
448       type = StackFrame::OPTIMIZED;
449       // Top frame is incomplete so we cannot reliably determine its type.
450       top_frame_type_ = StackFrame::NO_FRAME_TYPE;
451     }
452   } else {
453     return;
454   }
455   frame_ = SingletonFor(type, &state);
456   if (advance_frame && frame_) Advance();
457 }
458 
IsValidTop(ThreadLocalTop * top) const459 bool SafeStackFrameIterator::IsValidTop(ThreadLocalTop* top) const {
460   Address c_entry_fp = Isolate::c_entry_fp(top);
461   if (!IsValidExitFrame(c_entry_fp)) return false;
462   // There should be at least one JS_ENTRY stack handler.
463   Address handler = Isolate::handler(top);
464   if (handler == kNullAddress) return false;
465   // Check that there are no js frames on top of the native frames.
466   return c_entry_fp < handler;
467 }
468 
AdvanceOneFrame()469 void SafeStackFrameIterator::AdvanceOneFrame() {
470   DCHECK(!done());
471   StackFrame* last_frame = frame_;
472   Address last_sp = last_frame->sp(), last_fp = last_frame->fp();
473 
474   // Before advancing to the next stack frame, perform pointer validity tests.
475   if (!IsValidFrame(last_frame) || !IsValidCaller(last_frame)) {
476     frame_ = nullptr;
477     return;
478   }
479 
480   // Advance to the previous frame.
481   StackFrame::State state;
482   StackFrame::Type type = frame_->GetCallerState(&state);
483   frame_ = SingletonFor(type, &state);
484   if (!frame_) return;
485 
486   // Check that we have actually moved to the previous frame in the stack.
487   if (frame_->sp() <= last_sp || frame_->fp() <= last_fp) {
488     frame_ = nullptr;
489   }
490 }
491 
IsValidFrame(StackFrame * frame) const492 bool SafeStackFrameIterator::IsValidFrame(StackFrame* frame) const {
493   return IsValidStackAddress(frame->sp()) && IsValidStackAddress(frame->fp());
494 }
495 
IsValidCaller(StackFrame * frame)496 bool SafeStackFrameIterator::IsValidCaller(StackFrame* frame) {
497   StackFrame::State state;
498   if (frame->is_entry() || frame->is_construct_entry()) {
499     // See EntryFrame::GetCallerState. It computes the caller FP address
500     // and calls ExitFrame::GetStateForFramePointer on it. We need to be
501     // sure that caller FP address is valid.
502     Address caller_fp =
503         Memory<Address>(frame->fp() + EntryFrameConstants::kCallerFPOffset);
504     if (!IsValidExitFrame(caller_fp)) return false;
505   }
506   frame->ComputeCallerState(&state);
507   return IsValidStackAddress(state.sp) && IsValidStackAddress(state.fp) &&
508          SingletonFor(frame->GetCallerState(&state)) != nullptr;
509 }
510 
IsValidExitFrame(Address fp) const511 bool SafeStackFrameIterator::IsValidExitFrame(Address fp) const {
512   if (!IsValidStackAddress(fp)) return false;
513   Address sp = ExitFrame::ComputeStackPointer(fp);
514   if (!IsValidStackAddress(sp)) return false;
515   StackFrame::State state;
516   ExitFrame::FillState(fp, sp, &state);
517   MSAN_MEMORY_IS_INITIALIZED(state.pc_address, sizeof(state.pc_address));
518   return *state.pc_address != kNullAddress;
519 }
520 
Advance()521 void SafeStackFrameIterator::Advance() {
522   while (true) {
523     AdvanceOneFrame();
524     if (done()) break;
525     ExternalCallbackScope* last_callback_scope = nullptr;
526     while (external_callback_scope_ != nullptr &&
527            external_callback_scope_->scope_address() < frame_->fp()) {
528       // As long as the setup of a frame is not atomic, we may happen to be
529       // in an interval where an ExternalCallbackScope is already created,
530       // but the frame is not yet entered. So we are actually observing
531       // the previous frame.
532       // Skip all the ExternalCallbackScope's that are below the current fp.
533       last_callback_scope = external_callback_scope_;
534       external_callback_scope_ = external_callback_scope_->previous();
535     }
536     if (frame_->is_java_script()) break;
537 #if V8_ENABLE_WEBASSEMBLY
538     if (frame_->is_wasm() || frame_->is_wasm_to_js() ||
539         frame_->is_js_to_wasm()) {
540       break;
541     }
542 #endif  // V8_ENABLE_WEBASSEMBLY
543     if (frame_->is_exit() || frame_->is_builtin_exit()) {
544       // Some of the EXIT frames may have ExternalCallbackScope allocated on
545       // top of them. In that case the scope corresponds to the first EXIT
546       // frame beneath it. There may be other EXIT frames on top of the
547       // ExternalCallbackScope, just skip them as we cannot collect any useful
548       // information about them.
549       if (last_callback_scope) {
550         frame_->state_.pc_address =
551             last_callback_scope->callback_entrypoint_address();
552       }
553       break;
554     }
555   }
556 }
557 
558 // -------------------------------------------------------------------------
559 
560 namespace {
GetContainingCode(Isolate * isolate,Address pc)561 Code GetContainingCode(Isolate* isolate, Address pc) {
562   return isolate->inner_pointer_to_code_cache()->GetCacheEntry(pc)->code;
563 }
564 }  // namespace
565 
LookupCode() const566 Code StackFrame::LookupCode() const {
567   Code result = GetContainingCode(isolate(), pc());
568   DCHECK_GE(pc(), result.InstructionStart(isolate(), pc()));
569   DCHECK_LT(pc(), result.InstructionEnd(isolate(), pc()));
570   return result;
571 }
572 
IteratePc(RootVisitor * v,Address * pc_address,Address * constant_pool_address,Code holder) const573 void StackFrame::IteratePc(RootVisitor* v, Address* pc_address,
574                            Address* constant_pool_address, Code holder) const {
575   Address old_pc = ReadPC(pc_address);
576   DCHECK(ReadOnlyHeap::Contains(holder) ||
577          holder.GetHeap()->GcSafeCodeContains(holder, old_pc));
578   unsigned pc_offset = holder.GetOffsetFromInstructionStart(isolate_, old_pc);
579   Object code = holder;
580   v->VisitRunningCode(FullObjectSlot(&code));
581   if (code == holder) return;
582   holder = Code::unchecked_cast(code);
583   Address pc = holder.InstructionStart(isolate_, old_pc) + pc_offset;
584   // TODO(v8:10026): avoid replacing a signed pointer.
585   PointerAuthentication::ReplacePC(pc_address, pc, kSystemPointerSize);
586   if (FLAG_enable_embedded_constant_pool && constant_pool_address) {
587     *constant_pool_address = holder.constant_pool();
588   }
589 }
590 
SetReturnAddressLocationResolver(ReturnAddressLocationResolver resolver)591 void StackFrame::SetReturnAddressLocationResolver(
592     ReturnAddressLocationResolver resolver) {
593   DCHECK_NULL(return_address_location_resolver_);
594   return_address_location_resolver_ = resolver;
595 }
596 
ComputeType(const StackFrameIteratorBase * iterator,State * state)597 StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator,
598                                          State* state) {
599 #if V8_ENABLE_WEBASSEMBLY
600   if (state->fp == kNullAddress) {
601     DCHECK(FLAG_experimental_wasm_stack_switching);
602     return NO_FRAME_TYPE;
603   }
604 #endif
605 
606   MSAN_MEMORY_IS_INITIALIZED(
607       state->fp + CommonFrameConstants::kContextOrFrameTypeOffset,
608       kSystemPointerSize);
609   intptr_t marker = Memory<intptr_t>(
610       state->fp + CommonFrameConstants::kContextOrFrameTypeOffset);
611   Address pc = StackFrame::ReadPC(state->pc_address);
612   if (!iterator->can_access_heap_objects_) {
613     // TODO(titzer): "can_access_heap_objects" is kind of bogus. It really
614     // means that we are being called from the profiler, which can interrupt
615     // the VM with a signal at any arbitrary instruction, with essentially
616     // anything on the stack. So basically none of these checks are 100%
617     // reliable.
618     MSAN_MEMORY_IS_INITIALIZED(
619         state->fp + StandardFrameConstants::kFunctionOffset,
620         kSystemPointerSize);
621     Object maybe_function = Object(
622         Memory<Address>(state->fp + StandardFrameConstants::kFunctionOffset));
623     if (!StackFrame::IsTypeMarker(marker)) {
624       if (maybe_function.IsSmi()) {
625         return NATIVE;
626       } else if (IsInterpreterFramePc(iterator->isolate(), pc, state)) {
627         return INTERPRETED;
628       } else {
629         return OPTIMIZED;
630       }
631     }
632   } else {
633 #if V8_ENABLE_WEBASSEMBLY
634     // If the {pc} does not point into WebAssembly code we can rely on the
635     // returned {wasm_code} to be null and fall back to {GetContainingCode}.
636     wasm::WasmCodeRefScope code_ref_scope;
637     if (wasm::WasmCode* wasm_code =
638             wasm::GetWasmCodeManager()->LookupCode(pc)) {
639       switch (wasm_code->kind()) {
640         case wasm::WasmCode::kWasmFunction:
641           return WASM;
642         case wasm::WasmCode::kWasmToCapiWrapper:
643           return WASM_EXIT;
644         case wasm::WasmCode::kWasmToJsWrapper:
645           return WASM_TO_JS;
646         default:
647           UNREACHABLE();
648       }
649     }
650 #endif  // V8_ENABLE_WEBASSEMBLY
651 
652     // Look up the code object to figure out the type of the stack frame.
653     Code code_obj = GetContainingCode(iterator->isolate(), pc);
654     if (!code_obj.is_null()) {
655       switch (code_obj.kind()) {
656         case CodeKind::BUILTIN:
657           if (StackFrame::IsTypeMarker(marker)) break;
658           if (code_obj.is_interpreter_trampoline_builtin() ||
659               // Frames for baseline entry trampolines on the stack are still
660               // interpreted frames.
661               code_obj.is_baseline_trampoline_builtin()) {
662             return INTERPRETED;
663           }
664           if (code_obj.is_baseline_leave_frame_builtin()) {
665             return BASELINE;
666           }
667           if (code_obj.is_turbofanned()) {
668             // TODO(bmeurer): We treat frames for BUILTIN Code objects as
669             // OptimizedFrame for now (all the builtins with JavaScript
670             // linkage are actually generated with TurboFan currently, so
671             // this is sound).
672             return OPTIMIZED;
673           }
674           return BUILTIN;
675         case CodeKind::TURBOFAN:
676         case CodeKind::MAGLEV:
677           return OPTIMIZED;
678         case CodeKind::BASELINE:
679           return Type::BASELINE;
680 #if V8_ENABLE_WEBASSEMBLY
681         case CodeKind::JS_TO_WASM_FUNCTION:
682           return JS_TO_WASM;
683         case CodeKind::JS_TO_JS_FUNCTION:
684           return STUB;
685         case CodeKind::C_WASM_ENTRY:
686           return C_WASM_ENTRY;
687         case CodeKind::WASM_TO_JS_FUNCTION:
688           return WASM_TO_JS;
689         case CodeKind::WASM_FUNCTION:
690         case CodeKind::WASM_TO_CAPI_FUNCTION:
691           // Never appear as on-heap {Code} objects.
692           UNREACHABLE();
693 #endif  // V8_ENABLE_WEBASSEMBLY
694         default:
695           // All other types should have an explicit marker
696           break;
697       }
698     } else {
699       return NATIVE;
700     }
701   }
702   DCHECK(StackFrame::IsTypeMarker(marker));
703   StackFrame::Type candidate = StackFrame::MarkerToType(marker);
704   switch (candidate) {
705     case ENTRY:
706     case CONSTRUCT_ENTRY:
707     case EXIT:
708     case BUILTIN_CONTINUATION:
709     case JAVA_SCRIPT_BUILTIN_CONTINUATION:
710     case JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH:
711     case BUILTIN_EXIT:
712     case STUB:
713     case INTERNAL:
714     case CONSTRUCT:
715 #if V8_ENABLE_WEBASSEMBLY
716     case WASM_TO_JS:
717     case WASM:
718     case WASM_COMPILE_LAZY:
719     case WASM_EXIT:
720     case WASM_DEBUG_BREAK:
721     case JS_TO_WASM:
722     case STACK_SWITCH:
723 #endif  // V8_ENABLE_WEBASSEMBLY
724       return candidate;
725     case OPTIMIZED:
726     case INTERPRETED:
727     default:
728       // Unoptimized and optimized JavaScript frames, including
729       // interpreted frames, should never have a StackFrame::Type
730       // marker. If we find one, we're likely being called from the
731       // profiler in a bogus stack frame.
732       return NATIVE;
733   }
734 }
735 
736 #ifdef DEBUG
can_access_heap_objects() const737 bool StackFrame::can_access_heap_objects() const {
738   return iterator_->can_access_heap_objects_;
739 }
740 #endif
741 
GetCallerState(State * state) const742 StackFrame::Type StackFrame::GetCallerState(State* state) const {
743   ComputeCallerState(state);
744   return ComputeType(iterator_, state);
745 }
746 
GetCallerStackPointer() const747 Address CommonFrame::GetCallerStackPointer() const {
748   return fp() + CommonFrameConstants::kCallerSPOffset;
749 }
750 
ComputeCallerState(State * state) const751 void NativeFrame::ComputeCallerState(State* state) const {
752   state->sp = caller_sp();
753   state->fp = Memory<Address>(fp() + CommonFrameConstants::kCallerFPOffset);
754   state->pc_address = ResolveReturnAddressLocation(
755       reinterpret_cast<Address*>(fp() + CommonFrameConstants::kCallerPCOffset));
756   state->callee_pc_address = nullptr;
757   state->constant_pool_address = nullptr;
758 }
759 
unchecked_code() const760 Code EntryFrame::unchecked_code() const {
761   return FromCodeT(isolate()->builtins()->code(Builtin::kJSEntry));
762 }
763 
ComputeCallerState(State * state) const764 void EntryFrame::ComputeCallerState(State* state) const {
765   GetCallerState(state);
766 }
767 
GetCallerState(State * state) const768 StackFrame::Type EntryFrame::GetCallerState(State* state) const {
769   const int offset = EntryFrameConstants::kCallerFPOffset;
770   Address fp = Memory<Address>(this->fp() + offset);
771   return ExitFrame::GetStateForFramePointer(fp, state);
772 }
773 
774 #if V8_ENABLE_WEBASSEMBLY
GetCallerState(State * state) const775 StackFrame::Type CWasmEntryFrame::GetCallerState(State* state) const {
776   const int offset = CWasmEntryFrameConstants::kCEntryFPOffset;
777   Address fp = Memory<Address>(this->fp() + offset);
778   return ExitFrame::GetStateForFramePointer(fp, state);
779 }
780 #endif  // V8_ENABLE_WEBASSEMBLY
781 
unchecked_code() const782 Code ConstructEntryFrame::unchecked_code() const {
783   return FromCodeT(isolate()->builtins()->code(Builtin::kJSConstructEntry));
784 }
785 
ComputeCallerState(State * state) const786 void ExitFrame::ComputeCallerState(State* state) const {
787   // Set up the caller state.
788   state->sp = caller_sp();
789   state->fp = Memory<Address>(fp() + ExitFrameConstants::kCallerFPOffset);
790   state->pc_address = ResolveReturnAddressLocation(
791       reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset));
792   state->callee_pc_address = nullptr;
793   if (FLAG_enable_embedded_constant_pool) {
794     state->constant_pool_address = reinterpret_cast<Address*>(
795         fp() + ExitFrameConstants::kConstantPoolOffset);
796   }
797 }
798 
Iterate(RootVisitor * v) const799 void ExitFrame::Iterate(RootVisitor* v) const {
800   // The arguments are traversed as part of the expression stack of
801   // the calling frame.
802   IteratePc(v, pc_address(), constant_pool_address(), LookupCode());
803 }
804 
GetStateForFramePointer(Address fp,State * state)805 StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
806   if (fp == 0) return NO_FRAME_TYPE;
807   StackFrame::Type type = ComputeFrameType(fp);
808 #if V8_ENABLE_WEBASSEMBLY
809   Address sp = type == WASM_EXIT ? WasmExitFrame::ComputeStackPointer(fp)
810                                  : ExitFrame::ComputeStackPointer(fp);
811 #else
812   Address sp = ExitFrame::ComputeStackPointer(fp);
813 #endif  // V8_ENABLE_WEBASSEMBLY
814   FillState(fp, sp, state);
815   DCHECK_NE(*state->pc_address, kNullAddress);
816   return type;
817 }
818 
ComputeFrameType(Address fp)819 StackFrame::Type ExitFrame::ComputeFrameType(Address fp) {
820   // Distinguish between between regular and builtin exit frames.
821   // Default to EXIT in all hairy cases (e.g., when called from profiler).
822   const int offset = ExitFrameConstants::kFrameTypeOffset;
823   Object marker(Memory<Address>(fp + offset));
824 
825   if (!marker.IsSmi()) {
826     return EXIT;
827   }
828 
829   intptr_t marker_int = bit_cast<intptr_t>(marker);
830 
831   StackFrame::Type frame_type = static_cast<StackFrame::Type>(marker_int >> 1);
832   switch (frame_type) {
833     case BUILTIN_EXIT:
834 #if V8_ENABLE_WEBASSEMBLY
835     case WASM_EXIT:
836     case STACK_SWITCH:
837 #endif  // V8_ENABLE_WEBASSEMBLY
838       return frame_type;
839     default:
840       return EXIT;
841   }
842 }
843 
ComputeStackPointer(Address fp)844 Address ExitFrame::ComputeStackPointer(Address fp) {
845   MSAN_MEMORY_IS_INITIALIZED(fp + ExitFrameConstants::kSPOffset,
846                              kSystemPointerSize);
847   return Memory<Address>(fp + ExitFrameConstants::kSPOffset);
848 }
849 
850 #if V8_ENABLE_WEBASSEMBLY
ComputeStackPointer(Address fp)851 Address WasmExitFrame::ComputeStackPointer(Address fp) {
852   // For WASM_EXIT frames, {sp} is only needed for finding the PC slot,
853   // everything else is handled via safepoint information.
854   Address sp = fp + WasmExitFrameConstants::kWasmInstanceOffset;
855   DCHECK_EQ(sp - 1 * kPCOnStackSize,
856             fp + WasmExitFrameConstants::kCallingPCOffset);
857   return sp;
858 }
859 #endif  // V8_ENABLE_WEBASSEMBLY
860 
FillState(Address fp,Address sp,State * state)861 void ExitFrame::FillState(Address fp, Address sp, State* state) {
862   state->sp = sp;
863   state->fp = fp;
864   state->pc_address = ResolveReturnAddressLocation(
865       reinterpret_cast<Address*>(sp - 1 * kPCOnStackSize));
866   state->callee_pc_address = nullptr;
867   // The constant pool recorded in the exit frame is not associated
868   // with the pc in this state (the return address into a C entry
869   // stub).  ComputeCallerState will retrieve the constant pool
870   // together with the associated caller pc.
871   state->constant_pool_address = nullptr;
872 }
873 
Summarize(std::vector<FrameSummary> * frames) const874 void BuiltinExitFrame::Summarize(std::vector<FrameSummary>* frames) const {
875   DCHECK(frames->empty());
876   Handle<FixedArray> parameters = GetParameters();
877   DisallowGarbageCollection no_gc;
878   Code code = LookupCode();
879   int code_offset = code.GetOffsetFromInstructionStart(isolate(), pc());
880   FrameSummary::JavaScriptFrameSummary summary(
881       isolate(), receiver(), function(), AbstractCode::cast(code), code_offset,
882       IsConstructor(), *parameters);
883   frames->push_back(summary);
884 }
885 
function() const886 JSFunction BuiltinExitFrame::function() const {
887   return JSFunction::cast(target_slot_object());
888 }
889 
receiver() const890 Object BuiltinExitFrame::receiver() const { return receiver_slot_object(); }
891 
GetParameter(int i) const892 Object BuiltinExitFrame::GetParameter(int i) const {
893   DCHECK(i >= 0 && i < ComputeParametersCount());
894   int offset =
895       BuiltinExitFrameConstants::kFirstArgumentOffset + i * kSystemPointerSize;
896   return Object(Memory<Address>(fp() + offset));
897 }
898 
ComputeParametersCount() const899 int BuiltinExitFrame::ComputeParametersCount() const {
900   Object argc_slot = argc_slot_object();
901   DCHECK(argc_slot.IsSmi());
902   // Argc also counts the receiver, target, new target, and argc itself as args,
903   // therefore the real argument count is argc - 4.
904   int argc = Smi::ToInt(argc_slot) - 4;
905   DCHECK_GE(argc, 0);
906   return argc;
907 }
908 
GetParameters() const909 Handle<FixedArray> BuiltinExitFrame::GetParameters() const {
910   if (V8_LIKELY(!FLAG_detailed_error_stack_trace)) {
911     return isolate()->factory()->empty_fixed_array();
912   }
913   int param_count = ComputeParametersCount();
914   auto parameters = isolate()->factory()->NewFixedArray(param_count);
915   for (int i = 0; i < param_count; i++) {
916     parameters->set(i, GetParameter(i));
917   }
918   return parameters;
919 }
920 
IsConstructor() const921 bool BuiltinExitFrame::IsConstructor() const {
922   return !new_target_slot_object().IsUndefined(isolate());
923 }
924 
925 namespace {
PrintIndex(StringStream * accumulator,StackFrame::PrintMode mode,int index)926 void PrintIndex(StringStream* accumulator, StackFrame::PrintMode mode,
927                 int index) {
928   accumulator->Add((mode == StackFrame::OVERVIEW) ? "%5d: " : "[%d]: ", index);
929 }
930 
StringForStackFrameType(StackFrame::Type type)931 const char* StringForStackFrameType(StackFrame::Type type) {
932   switch (type) {
933 #define CASE(value, name) \
934   case StackFrame::value: \
935     return #name;
936     STACK_FRAME_TYPE_LIST(CASE)
937 #undef CASE
938     default:
939       UNREACHABLE();
940   }
941 }
942 }  // namespace
943 
Print(StringStream * accumulator,PrintMode mode,int index) const944 void StackFrame::Print(StringStream* accumulator, PrintMode mode,
945                        int index) const {
946   DisallowGarbageCollection no_gc;
947   PrintIndex(accumulator, mode, index);
948   accumulator->Add(StringForStackFrameType(type()));
949   accumulator->Add(" [pc: %p]\n", reinterpret_cast<void*>(pc()));
950 }
951 
Print(StringStream * accumulator,PrintMode mode,int index) const952 void BuiltinExitFrame::Print(StringStream* accumulator, PrintMode mode,
953                              int index) const {
954   DisallowGarbageCollection no_gc;
955   Object receiver = this->receiver();
956   JSFunction function = this->function();
957 
958   accumulator->PrintSecurityTokenIfChanged(function);
959   PrintIndex(accumulator, mode, index);
960   accumulator->Add("builtin exit frame: ");
961   Code code;
962   if (IsConstructor()) accumulator->Add("new ");
963   accumulator->PrintFunction(function, receiver, &code);
964 
965   accumulator->Add("(this=%o", receiver);
966 
967   // Print the parameters.
968   int parameters_count = ComputeParametersCount();
969   for (int i = 0; i < parameters_count; i++) {
970     accumulator->Add(",%o", GetParameter(i));
971   }
972 
973   accumulator->Add(")\n\n");
974 }
975 
GetExpressionAddress(int n) const976 Address CommonFrame::GetExpressionAddress(int n) const {
977   const int offset = StandardFrameConstants::kExpressionsOffset;
978   return fp() + offset - n * kSystemPointerSize;
979 }
980 
GetExpressionAddress(int n) const981 Address UnoptimizedFrame::GetExpressionAddress(int n) const {
982   const int offset = UnoptimizedFrameConstants::kExpressionsOffset;
983   return fp() + offset - n * kSystemPointerSize;
984 }
985 
context() const986 Object CommonFrame::context() const {
987   return ReadOnlyRoots(isolate()).undefined_value();
988 }
989 
position() const990 int CommonFrame::position() const {
991   Code code = LookupCode();
992   int code_offset = code.GetOffsetFromInstructionStart(isolate(), pc());
993   return AbstractCode::cast(code).SourcePosition(code_offset);
994 }
995 
ComputeExpressionsCount() const996 int CommonFrame::ComputeExpressionsCount() const {
997   Address base = GetExpressionAddress(0);
998   Address limit = sp() - kSystemPointerSize;
999   DCHECK(base >= limit);  // stack grows downwards
1000   // Include register-allocated locals in number of expressions.
1001   return static_cast<int>((base - limit) / kSystemPointerSize);
1002 }
1003 
ComputeCallerState(State * state) const1004 void CommonFrame::ComputeCallerState(State* state) const {
1005   state->fp = caller_fp();
1006 #if V8_ENABLE_WEBASSEMBLY
1007   if (state->fp == kNullAddress) {
1008     // An empty FP signals the first frame of a stack segment. The caller is
1009     // on a different stack, or is unbound (suspended stack).
1010     DCHECK(FLAG_experimental_wasm_stack_switching);
1011     return;
1012   }
1013 #endif
1014   state->sp = caller_sp();
1015   state->pc_address = ResolveReturnAddressLocation(
1016       reinterpret_cast<Address*>(ComputePCAddress(fp())));
1017   state->callee_fp = fp();
1018   state->callee_pc_address = pc_address();
1019   state->constant_pool_address =
1020       reinterpret_cast<Address*>(ComputeConstantPoolAddress(fp()));
1021 }
1022 
Summarize(std::vector<FrameSummary> * functions) const1023 void CommonFrame::Summarize(std::vector<FrameSummary>* functions) const {
1024   // This should only be called on frames which override this method.
1025   UNREACHABLE();
1026 }
1027 
IterateCompiledFrame(RootVisitor * v) const1028 void CommonFrame::IterateCompiledFrame(RootVisitor* v) const {
1029   // Make sure that we're not doing "safe" stack frame iteration. We cannot
1030   // possibly find pointers in optimized frames in that state.
1031   DCHECK(can_access_heap_objects());
1032 
1033   // Find the code and compute the safepoint information.
1034   Address inner_pointer = pc();
1035   SafepointEntry safepoint_entry;
1036   uint32_t stack_slots = 0;
1037   Code code;
1038   bool has_tagged_outgoing_params = false;
1039   uint16_t first_tagged_parameter_slot = 0;
1040   uint16_t num_tagged_parameter_slots = 0;
1041   bool is_wasm = false;
1042 
1043 #if V8_ENABLE_WEBASSEMBLY
1044   bool has_wasm_feedback_slot = false;
1045   if (auto* wasm_code = wasm::GetWasmCodeManager()->LookupCode(inner_pointer)) {
1046     is_wasm = true;
1047     SafepointTable table(wasm_code);
1048     safepoint_entry = table.FindEntry(inner_pointer);
1049     stack_slots = wasm_code->stack_slots();
1050     has_tagged_outgoing_params =
1051         wasm_code->kind() != wasm::WasmCode::kWasmFunction &&
1052         wasm_code->kind() != wasm::WasmCode::kWasmToCapiWrapper;
1053     first_tagged_parameter_slot = wasm_code->first_tagged_parameter_slot();
1054     num_tagged_parameter_slots = wasm_code->num_tagged_parameter_slots();
1055     if (wasm_code->is_liftoff() && FLAG_wasm_speculative_inlining) {
1056       has_wasm_feedback_slot = true;
1057     }
1058   }
1059 #endif  // V8_ENABLE_WEBASSEMBLY
1060 
1061   if (!is_wasm) {
1062     InnerPointerToCodeCache::InnerPointerToCodeCacheEntry* entry =
1063         isolate()->inner_pointer_to_code_cache()->GetCacheEntry(inner_pointer);
1064     if (!entry->safepoint_entry.is_initialized()) {
1065       entry->safepoint_entry =
1066           entry->code.GetSafepointEntry(isolate(), inner_pointer);
1067       DCHECK(entry->safepoint_entry.is_initialized());
1068     } else {
1069       DCHECK_EQ(entry->safepoint_entry,
1070                 entry->code.GetSafepointEntry(isolate(), inner_pointer));
1071     }
1072 
1073     code = entry->code;
1074     safepoint_entry = entry->safepoint_entry;
1075     stack_slots = code.stack_slots();
1076 
1077     has_tagged_outgoing_params = code.has_tagged_outgoing_params();
1078 
1079 #if V8_ENABLE_WEBASSEMBLY
1080     // With inlined JS-to-Wasm calls, we can be in an OptimizedFrame and
1081     // directly call a Wasm function from JavaScript. In this case the
1082     // parameters we pass to the callee are not tagged.
1083     wasm::WasmCode* wasm_callee =
1084         wasm::GetWasmCodeManager()->LookupCode(callee_pc());
1085     bool is_wasm_call = (wasm_callee != nullptr);
1086     if (is_wasm_call) has_tagged_outgoing_params = false;
1087 #endif  // V8_ENABLE_WEBASSEMBLY
1088   }
1089 
1090   // Determine the fixed header and spill slot area size.
1091   int frame_header_size = StandardFrameConstants::kFixedFrameSizeFromFp;
1092   intptr_t marker =
1093       Memory<intptr_t>(fp() + CommonFrameConstants::kContextOrFrameTypeOffset);
1094   bool typed_frame = StackFrame::IsTypeMarker(marker);
1095   if (typed_frame) {
1096     StackFrame::Type candidate = StackFrame::MarkerToType(marker);
1097     switch (candidate) {
1098       case ENTRY:
1099       case CONSTRUCT_ENTRY:
1100       case EXIT:
1101       case BUILTIN_CONTINUATION:
1102       case JAVA_SCRIPT_BUILTIN_CONTINUATION:
1103       case JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH:
1104       case BUILTIN_EXIT:
1105       case STUB:
1106       case INTERNAL:
1107       case CONSTRUCT:
1108 #if V8_ENABLE_WEBASSEMBLY
1109       case JS_TO_WASM:
1110       case STACK_SWITCH:
1111       case C_WASM_ENTRY:
1112       case WASM_DEBUG_BREAK:
1113 #endif  // V8_ENABLE_WEBASSEMBLY
1114         frame_header_size = TypedFrameConstants::kFixedFrameSizeFromFp;
1115         break;
1116 #if V8_ENABLE_WEBASSEMBLY
1117       case WASM_TO_JS:
1118       case WASM:
1119       case WASM_COMPILE_LAZY:
1120         frame_header_size = WasmFrameConstants::kFixedFrameSizeFromFp;
1121         if (has_wasm_feedback_slot) frame_header_size += kSystemPointerSize;
1122         break;
1123       case WASM_EXIT:
1124         // The last value in the frame header is the calling PC, which should
1125         // not be visited.
1126         static_assert(WasmExitFrameConstants::kFixedSlotCountFromFp ==
1127                           WasmFrameConstants::kFixedSlotCountFromFp + 1,
1128                       "WasmExitFrame has one slot more than WasmFrame");
1129         frame_header_size = WasmFrameConstants::kFixedFrameSizeFromFp;
1130         break;
1131 #endif  // V8_ENABLE_WEBASSEMBLY
1132       case OPTIMIZED:
1133       case INTERPRETED:
1134       case BASELINE:
1135       case BUILTIN:
1136         // These frame types have a context, but they are actually stored
1137         // in the place on the stack that one finds the frame type.
1138         UNREACHABLE();
1139       case NATIVE:
1140       case NO_FRAME_TYPE:
1141       case NUMBER_OF_TYPES:
1142       case MANUAL:
1143         UNREACHABLE();
1144     }
1145   }
1146 
1147   // slot_space holds the actual number of spill slots, without fixed frame
1148   // slots.
1149   const uint32_t slot_space =
1150       stack_slots * kSystemPointerSize -
1151       (frame_header_size + StandardFrameConstants::kFixedFrameSizeAboveFp);
1152 
1153   // base <= limit.
1154   // Fixed frame slots.
1155   FullObjectSlot frame_header_base(&Memory<Address>(fp() - frame_header_size));
1156   FullObjectSlot frame_header_limit(
1157       &Memory<Address>(fp() - StandardFrameConstants::kCPSlotSize));
1158   // Parameters passed to the callee.
1159   FullObjectSlot parameters_base(&Memory<Address>(sp()));
1160   FullObjectSlot parameters_limit(frame_header_base.address() - slot_space);
1161   // Spill slots are in the region ]frame_header_base, parameters_limit];
1162 
1163   // Visit the rest of the parameters if they are tagged.
1164   if (has_tagged_outgoing_params) {
1165     v->VisitRootPointers(Root::kStackRoots, nullptr, parameters_base,
1166                          parameters_limit);
1167   }
1168 
1169   // Visit pointer spill slots and locals.
1170   DCHECK_GE((stack_slots + kBitsPerByte) / kBitsPerByte,
1171             safepoint_entry.tagged_slots().size());
1172   int slot_offset = 0;
1173   PtrComprCageBase cage_base(isolate());
1174   for (uint8_t bits : safepoint_entry.tagged_slots()) {
1175     while (bits) {
1176       const int bit = base::bits::CountTrailingZeros(bits);
1177       bits &= ~(1 << bit);
1178       FullObjectSlot spill_slot = parameters_limit + slot_offset + bit;
1179 #ifdef V8_COMPRESS_POINTERS
1180       // Spill slots may contain compressed values in which case the upper
1181       // 32-bits will contain zeros. In order to simplify handling of such
1182       // slots in GC we ensure that the slot always contains full value.
1183 
1184       // The spill slot may actually contain weak references so we load/store
1185       // values using spill_slot.location() in order to avoid dealing with
1186       // FullMaybeObjectSlots here.
1187       if (V8_EXTERNAL_CODE_SPACE_BOOL) {
1188         // When external code space is enabled the spill slot could contain both
1189         // Code and non-Code references, which have different cage bases. So
1190         // unconditional decompression of the value might corrupt Code pointers.
1191         // However, given that
1192         // 1) the Code pointers are never compressed by design (because
1193         //    otherwise we wouldn't know which cage base to apply for
1194         //    decompression, see respective DCHECKs in
1195         //    RelocInfo::target_object()),
1196         // 2) there's no need to update the upper part of the full pointer
1197         //    because if it was there then it'll stay the same,
1198         // we can avoid updating upper part of the spill slot if it already
1199         // contains full value.
1200         // TODO(v8:11880): Remove this special handling by enforcing builtins
1201         // to use CodeTs instead of Code objects.
1202         Address value = *spill_slot.location();
1203         if (!HAS_SMI_TAG(value) && value <= 0xffffffff) {
1204           // We don't need to update smi values or full pointers.
1205           *spill_slot.location() =
1206               DecompressTaggedPointer(cage_base, static_cast<Tagged_t>(value));
1207           if (DEBUG_BOOL) {
1208             // Ensure that the spill slot contains correct heap object.
1209             HeapObject raw = HeapObject::cast(Object(*spill_slot.location()));
1210             MapWord map_word = raw.map_word(cage_base, kRelaxedLoad);
1211             HeapObject forwarded = map_word.IsForwardingAddress()
1212                                        ? map_word.ToForwardingAddress()
1213                                        : raw;
1214             bool is_self_forwarded =
1215                 forwarded.map_word(cage_base, kRelaxedLoad).ptr() ==
1216                 forwarded.address();
1217             if (is_self_forwarded) {
1218               // The object might be in a self-forwarding state if it's located
1219               // in new large object space. GC will fix this at a later stage.
1220               CHECK(BasicMemoryChunk::FromHeapObject(forwarded)
1221                         ->InNewLargeObjectSpace());
1222             } else {
1223               CHECK(forwarded.map(cage_base).IsMap(cage_base));
1224             }
1225           }
1226         }
1227       } else {
1228         Tagged_t compressed_value =
1229             static_cast<Tagged_t>(*spill_slot.location());
1230         if (!HAS_SMI_TAG(compressed_value)) {
1231           // We don't need to update smi values.
1232           *spill_slot.location() =
1233               DecompressTaggedPointer(cage_base, compressed_value);
1234         }
1235       }
1236 #endif
1237       v->VisitRootPointer(Root::kStackRoots, nullptr, spill_slot);
1238     }
1239     slot_offset += kBitsPerByte;
1240   }
1241 
1242   // Visit tagged parameters that have been passed to the function of this
1243   // frame. Conceptionally these parameters belong to the parent frame. However,
1244   // the exact count is only known by this frame (in the presence of tail calls,
1245   // this information cannot be derived from the call site).
1246   if (num_tagged_parameter_slots > 0) {
1247     FullObjectSlot tagged_parameter_base(&Memory<Address>(caller_sp()));
1248     tagged_parameter_base += first_tagged_parameter_slot;
1249     FullObjectSlot tagged_parameter_limit =
1250         tagged_parameter_base + num_tagged_parameter_slots;
1251 
1252     v->VisitRootPointers(Root::kStackRoots, nullptr, tagged_parameter_base,
1253                          tagged_parameter_limit);
1254   }
1255 
1256   // For the off-heap code cases, we can skip this.
1257   if (!code.is_null()) {
1258     // Visit the return address in the callee and incoming arguments.
1259     IteratePc(v, pc_address(), constant_pool_address(), code);
1260   }
1261 
1262   // If this frame has JavaScript ABI, visit the context (in stub and JS
1263   // frames) and the function (in JS frames). If it has WebAssembly ABI, visit
1264   // the instance object.
1265   if (!typed_frame) {
1266     // JavaScript ABI frames also contain arguments count value which is stored
1267     // untagged, we don't need to visit it.
1268     frame_header_base += 1;
1269   }
1270   v->VisitRootPointers(Root::kStackRoots, nullptr, frame_header_base,
1271                        frame_header_limit);
1272 }
1273 
unchecked_code() const1274 Code StubFrame::unchecked_code() const {
1275   return isolate()->FindCodeObject(pc());
1276 }
1277 
LookupExceptionHandlerInTable()1278 int StubFrame::LookupExceptionHandlerInTable() {
1279   Code code = LookupCode();
1280   DCHECK(code.is_turbofanned());
1281   DCHECK_EQ(code.kind(), CodeKind::BUILTIN);
1282   HandlerTable table(code);
1283   int pc_offset = code.GetOffsetFromInstructionStart(isolate(), pc());
1284   return table.LookupReturn(pc_offset);
1285 }
1286 
Iterate(RootVisitor * v) const1287 void OptimizedFrame::Iterate(RootVisitor* v) const { IterateCompiledFrame(v); }
1288 
SetParameterValue(int index,Object value) const1289 void JavaScriptFrame::SetParameterValue(int index, Object value) const {
1290   Memory<Address>(GetParameterSlot(index)) = value.ptr();
1291 }
1292 
IsConstructor() const1293 bool JavaScriptFrame::IsConstructor() const {
1294   return IsConstructFrame(caller_fp());
1295 }
1296 
HasInlinedFrames() const1297 bool JavaScriptFrame::HasInlinedFrames() const {
1298   std::vector<SharedFunctionInfo> functions;
1299   GetFunctions(&functions);
1300   return functions.size() > 1;
1301 }
1302 
unchecked_code() const1303 Code CommonFrameWithJSLinkage::unchecked_code() const {
1304   return FromCodeT(function().code());
1305 }
1306 
ComputeParametersCount() const1307 int OptimizedFrame::ComputeParametersCount() const {
1308   Code code = LookupCode();
1309   if (code.kind() == CodeKind::BUILTIN) {
1310     return static_cast<int>(
1311                Memory<intptr_t>(fp() + StandardFrameConstants::kArgCOffset)) -
1312            kJSArgcReceiverSlots;
1313   } else {
1314     return JavaScriptFrame::ComputeParametersCount();
1315   }
1316 }
1317 
GetCallerStackPointer() const1318 Address JavaScriptFrame::GetCallerStackPointer() const {
1319   return fp() + StandardFrameConstants::kCallerSPOffset;
1320 }
1321 
GetFunctions(std::vector<SharedFunctionInfo> * functions) const1322 void JavaScriptFrame::GetFunctions(
1323     std::vector<SharedFunctionInfo>* functions) const {
1324   DCHECK(functions->empty());
1325   functions->push_back(function().shared());
1326 }
1327 
GetFunctions(std::vector<Handle<SharedFunctionInfo>> * functions) const1328 void JavaScriptFrame::GetFunctions(
1329     std::vector<Handle<SharedFunctionInfo>>* functions) const {
1330   DCHECK(functions->empty());
1331   std::vector<SharedFunctionInfo> raw_functions;
1332   GetFunctions(&raw_functions);
1333   for (const auto& raw_function : raw_functions) {
1334     functions->push_back(
1335         Handle<SharedFunctionInfo>(raw_function, function().GetIsolate()));
1336   }
1337 }
1338 
IsConstructor() const1339 bool CommonFrameWithJSLinkage::IsConstructor() const {
1340   return IsConstructFrame(caller_fp());
1341 }
1342 
Summarize(std::vector<FrameSummary> * functions) const1343 void CommonFrameWithJSLinkage::Summarize(
1344     std::vector<FrameSummary>* functions) const {
1345   DCHECK(functions->empty());
1346   Code code = LookupCode();
1347   int offset = code.GetOffsetFromInstructionStart(isolate(), pc());
1348   Handle<AbstractCode> abstract_code(AbstractCode::cast(code), isolate());
1349   Handle<FixedArray> params = GetParameters();
1350   FrameSummary::JavaScriptFrameSummary summary(
1351       isolate(), receiver(), function(), *abstract_code, offset,
1352       IsConstructor(), *params);
1353   functions->push_back(summary);
1354 }
1355 
function() const1356 JSFunction JavaScriptFrame::function() const {
1357   return JSFunction::cast(function_slot_object());
1358 }
1359 
unchecked_function() const1360 Object JavaScriptFrame::unchecked_function() const {
1361   // During deoptimization of an optimized function, we may have yet to
1362   // materialize some closures on the stack. The arguments marker object
1363   // marks this case.
1364   DCHECK(function_slot_object().IsJSFunction() ||
1365          ReadOnlyRoots(isolate()).arguments_marker() == function_slot_object());
1366   return function_slot_object();
1367 }
1368 
receiver() const1369 Object CommonFrameWithJSLinkage::receiver() const { return GetParameter(-1); }
1370 
context() const1371 Object JavaScriptFrame::context() const {
1372   const int offset = StandardFrameConstants::kContextOffset;
1373   Object maybe_result(Memory<Address>(fp() + offset));
1374   DCHECK(!maybe_result.IsSmi());
1375   return maybe_result;
1376 }
1377 
script() const1378 Script JavaScriptFrame::script() const {
1379   return Script::cast(function().shared().script());
1380 }
1381 
LookupExceptionHandlerInTable(int * stack_depth,HandlerTable::CatchPrediction * prediction)1382 int CommonFrameWithJSLinkage::LookupExceptionHandlerInTable(
1383     int* stack_depth, HandlerTable::CatchPrediction* prediction) {
1384   DCHECK(!LookupCode().has_handler_table());
1385   DCHECK(!LookupCode().is_optimized_code() ||
1386          LookupCode().kind() == CodeKind::BASELINE);
1387   return -1;
1388 }
1389 
PrintFunctionAndOffset(JSFunction function,AbstractCode code,int code_offset,FILE * file,bool print_line_number)1390 void JavaScriptFrame::PrintFunctionAndOffset(JSFunction function,
1391                                              AbstractCode code, int code_offset,
1392                                              FILE* file,
1393                                              bool print_line_number) {
1394   PrintF(file, "%s", CodeKindToMarker(code.kind()));
1395   function.PrintName(file);
1396   PrintF(file, "+%d", code_offset);
1397   if (print_line_number) {
1398     SharedFunctionInfo shared = function.shared();
1399     int source_pos = code.SourcePosition(code_offset);
1400     Object maybe_script = shared.script();
1401     if (maybe_script.IsScript()) {
1402       Script script = Script::cast(maybe_script);
1403       int line = script.GetLineNumber(source_pos) + 1;
1404       Object script_name_raw = script.name();
1405       if (script_name_raw.IsString()) {
1406         String script_name = String::cast(script.name());
1407         std::unique_ptr<char[]> c_script_name =
1408             script_name.ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1409         PrintF(file, " at %s:%d", c_script_name.get(), line);
1410       } else {
1411         PrintF(file, " at <unknown>:%d", line);
1412       }
1413     } else {
1414       PrintF(file, " at <unknown>:<unknown>");
1415     }
1416   }
1417 }
1418 
PrintTop(Isolate * isolate,FILE * file,bool print_args,bool print_line_number)1419 void JavaScriptFrame::PrintTop(Isolate* isolate, FILE* file, bool print_args,
1420                                bool print_line_number) {
1421   // constructor calls
1422   DisallowGarbageCollection no_gc;
1423   JavaScriptFrameIterator it(isolate);
1424   while (!it.done()) {
1425     if (it.frame()->is_java_script()) {
1426       JavaScriptFrame* frame = it.frame();
1427       if (frame->IsConstructor()) PrintF(file, "new ");
1428       JSFunction function = frame->function();
1429       int code_offset = 0;
1430       AbstractCode abstract_code = function.abstract_code(isolate);
1431       if (frame->is_interpreted()) {
1432         InterpretedFrame* iframe = reinterpret_cast<InterpretedFrame*>(frame);
1433         code_offset = iframe->GetBytecodeOffset();
1434       } else if (frame->is_baseline()) {
1435         // TODO(pthier): AbstractCode should fully support Baseline code.
1436         BaselineFrame* baseline_frame = BaselineFrame::cast(frame);
1437         code_offset = baseline_frame->GetBytecodeOffset();
1438         abstract_code = AbstractCode::cast(baseline_frame->GetBytecodeArray());
1439       } else {
1440         Code code = frame->unchecked_code();
1441         code_offset = code.GetOffsetFromInstructionStart(isolate, frame->pc());
1442       }
1443       PrintFunctionAndOffset(function, abstract_code, code_offset, file,
1444                              print_line_number);
1445       if (print_args) {
1446         // function arguments
1447         // (we are intentionally only printing the actually
1448         // supplied parameters, not all parameters required)
1449         PrintF(file, "(this=");
1450         frame->receiver().ShortPrint(file);
1451         const int length = frame->ComputeParametersCount();
1452         for (int i = 0; i < length; i++) {
1453           PrintF(file, ", ");
1454           frame->GetParameter(i).ShortPrint(file);
1455         }
1456         PrintF(file, ")");
1457       }
1458       break;
1459     }
1460     it.Advance();
1461   }
1462 }
1463 
CollectFunctionAndOffsetForICStats(JSFunction function,AbstractCode code,int code_offset)1464 void JavaScriptFrame::CollectFunctionAndOffsetForICStats(JSFunction function,
1465                                                          AbstractCode code,
1466                                                          int code_offset) {
1467   auto ic_stats = ICStats::instance();
1468   ICInfo& ic_info = ic_stats->Current();
1469   SharedFunctionInfo shared = function.shared();
1470 
1471   ic_info.function_name = ic_stats->GetOrCacheFunctionName(function);
1472   ic_info.script_offset = code_offset;
1473 
1474   int source_pos = code.SourcePosition(code_offset);
1475   Object maybe_script = shared.script();
1476   if (maybe_script.IsScript()) {
1477     Script script = Script::cast(maybe_script);
1478     ic_info.line_num = script.GetLineNumber(source_pos) + 1;
1479     ic_info.column_num = script.GetColumnNumber(source_pos);
1480     ic_info.script_name = ic_stats->GetOrCacheScriptName(script);
1481   }
1482 }
1483 
GetParameter(int index) const1484 Object CommonFrameWithJSLinkage::GetParameter(int index) const {
1485   return Object(Memory<Address>(GetParameterSlot(index)));
1486 }
1487 
ComputeParametersCount() const1488 int CommonFrameWithJSLinkage::ComputeParametersCount() const {
1489   DCHECK(can_access_heap_objects() &&
1490          isolate()->heap()->gc_state() == Heap::NOT_IN_GC);
1491   return function().shared().internal_formal_parameter_count_without_receiver();
1492 }
1493 
GetActualArgumentCount() const1494 int JavaScriptFrame::GetActualArgumentCount() const {
1495   return static_cast<int>(
1496              Memory<intptr_t>(fp() + StandardFrameConstants::kArgCOffset)) -
1497          kJSArgcReceiverSlots;
1498 }
1499 
GetParameters() const1500 Handle<FixedArray> CommonFrameWithJSLinkage::GetParameters() const {
1501   if (V8_LIKELY(!FLAG_detailed_error_stack_trace)) {
1502     return isolate()->factory()->empty_fixed_array();
1503   }
1504   int param_count = ComputeParametersCount();
1505   Handle<FixedArray> parameters =
1506       isolate()->factory()->NewFixedArray(param_count);
1507   for (int i = 0; i < param_count; i++) {
1508     parameters->set(i, GetParameter(i));
1509   }
1510 
1511   return parameters;
1512 }
1513 
function() const1514 JSFunction JavaScriptBuiltinContinuationFrame::function() const {
1515   const int offset = BuiltinContinuationFrameConstants::kFunctionOffset;
1516   return JSFunction::cast(Object(base::Memory<Address>(fp() + offset)));
1517 }
1518 
ComputeParametersCount() const1519 int JavaScriptBuiltinContinuationFrame::ComputeParametersCount() const {
1520   // Assert that the first allocatable register is also the argument count
1521   // register.
1522   DCHECK_EQ(RegisterConfiguration::Default()->GetAllocatableGeneralCode(0),
1523             kJavaScriptCallArgCountRegister.code());
1524   Object argc_object(
1525       Memory<Address>(fp() + BuiltinContinuationFrameConstants::kArgCOffset));
1526   return Smi::ToInt(argc_object) - kJSArgcReceiverSlots;
1527 }
1528 
GetSPToFPDelta() const1529 intptr_t JavaScriptBuiltinContinuationFrame::GetSPToFPDelta() const {
1530   Address height_slot =
1531       fp() + BuiltinContinuationFrameConstants::kFrameSPtoFPDeltaAtDeoptimize;
1532   intptr_t height = Smi::ToInt(Smi(Memory<Address>(height_slot)));
1533   return height;
1534 }
1535 
context() const1536 Object JavaScriptBuiltinContinuationFrame::context() const {
1537   return Object(Memory<Address>(
1538       fp() + BuiltinContinuationFrameConstants::kBuiltinContextOffset));
1539 }
1540 
SetException(Object exception)1541 void JavaScriptBuiltinContinuationWithCatchFrame::SetException(
1542     Object exception) {
1543   int argc = ComputeParametersCount();
1544   Address exception_argument_slot =
1545       fp() + BuiltinContinuationFrameConstants::kFixedFrameSizeAboveFp +
1546       (argc - 1) * kSystemPointerSize;
1547 
1548   // Only allow setting exception if previous value was the hole.
1549   CHECK_EQ(ReadOnlyRoots(isolate()).the_hole_value(),
1550            Object(Memory<Address>(exception_argument_slot)));
1551   Memory<Address>(exception_argument_slot) = exception.ptr();
1552 }
1553 
JavaScriptFrameSummary(Isolate * isolate,Object receiver,JSFunction function,AbstractCode abstract_code,int code_offset,bool is_constructor,FixedArray parameters)1554 FrameSummary::JavaScriptFrameSummary::JavaScriptFrameSummary(
1555     Isolate* isolate, Object receiver, JSFunction function,
1556     AbstractCode abstract_code, int code_offset, bool is_constructor,
1557     FixedArray parameters)
1558     : FrameSummaryBase(isolate, FrameSummary::JAVA_SCRIPT),
1559       receiver_(receiver, isolate),
1560       function_(function, isolate),
1561       abstract_code_(abstract_code, isolate),
1562       code_offset_(code_offset),
1563       is_constructor_(is_constructor),
1564       parameters_(parameters, isolate) {
1565   DCHECK(abstract_code.IsBytecodeArray() ||
1566          !CodeKindIsOptimizedJSFunction(Code::cast(abstract_code).kind()));
1567 }
1568 
EnsureSourcePositionsAvailable()1569 void FrameSummary::EnsureSourcePositionsAvailable() {
1570   if (IsJavaScript()) {
1571     java_script_summary_.EnsureSourcePositionsAvailable();
1572   }
1573 }
1574 
AreSourcePositionsAvailable() const1575 bool FrameSummary::AreSourcePositionsAvailable() const {
1576   if (IsJavaScript()) {
1577     return java_script_summary_.AreSourcePositionsAvailable();
1578   }
1579   return true;
1580 }
1581 
EnsureSourcePositionsAvailable()1582 void FrameSummary::JavaScriptFrameSummary::EnsureSourcePositionsAvailable() {
1583   Handle<SharedFunctionInfo> shared(function()->shared(), isolate());
1584   SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate(), shared);
1585 }
1586 
AreSourcePositionsAvailable() const1587 bool FrameSummary::JavaScriptFrameSummary::AreSourcePositionsAvailable() const {
1588   return !FLAG_enable_lazy_source_positions || function()
1589                                                    ->shared()
1590                                                    .GetBytecodeArray(isolate())
1591                                                    .HasSourcePositionTable();
1592 }
1593 
is_subject_to_debugging() const1594 bool FrameSummary::JavaScriptFrameSummary::is_subject_to_debugging() const {
1595   return function()->shared().IsSubjectToDebugging();
1596 }
1597 
SourcePosition() const1598 int FrameSummary::JavaScriptFrameSummary::SourcePosition() const {
1599   return abstract_code()->SourcePosition(code_offset());
1600 }
1601 
SourceStatementPosition() const1602 int FrameSummary::JavaScriptFrameSummary::SourceStatementPosition() const {
1603   return abstract_code()->SourceStatementPosition(code_offset());
1604 }
1605 
script() const1606 Handle<Object> FrameSummary::JavaScriptFrameSummary::script() const {
1607   return handle(function_->shared().script(), isolate());
1608 }
1609 
native_context() const1610 Handle<Context> FrameSummary::JavaScriptFrameSummary::native_context() const {
1611   return handle(function_->native_context(), isolate());
1612 }
1613 
1614 Handle<StackFrameInfo>
CreateStackFrameInfo() const1615 FrameSummary::JavaScriptFrameSummary::CreateStackFrameInfo() const {
1616   Handle<SharedFunctionInfo> shared(function_->shared(), isolate());
1617   Handle<Script> script(Script::cast(shared->script()), isolate());
1618   Handle<String> function_name = JSFunction::GetDebugName(function_);
1619   if (function_name->length() == 0 &&
1620       script->compilation_type() == Script::COMPILATION_TYPE_EVAL) {
1621     function_name = isolate()->factory()->eval_string();
1622   }
1623   int bytecode_offset = code_offset();
1624   if (bytecode_offset == kFunctionEntryBytecodeOffset) {
1625     // For the special function entry bytecode offset (-1), which signals
1626     // that the stack trace was captured while the function entry was
1627     // executing (i.e. during the interrupt check), we cannot store this
1628     // sentinel in the bit field, so we just eagerly lookup the source
1629     // position within the script.
1630     SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate(), shared);
1631     int source_position = abstract_code()->SourcePosition(bytecode_offset);
1632     return isolate()->factory()->NewStackFrameInfo(
1633         script, source_position, function_name, is_constructor());
1634   }
1635   return isolate()->factory()->NewStackFrameInfo(
1636       shared, bytecode_offset, function_name, is_constructor());
1637 }
1638 
1639 #if V8_ENABLE_WEBASSEMBLY
WasmFrameSummary(Isolate * isolate,Handle<WasmInstanceObject> instance,wasm::WasmCode * code,int code_offset,bool at_to_number_conversion)1640 FrameSummary::WasmFrameSummary::WasmFrameSummary(
1641     Isolate* isolate, Handle<WasmInstanceObject> instance, wasm::WasmCode* code,
1642     int code_offset, bool at_to_number_conversion)
1643     : FrameSummaryBase(isolate, WASM),
1644       wasm_instance_(instance),
1645       at_to_number_conversion_(at_to_number_conversion),
1646       code_(code),
1647       code_offset_(code_offset) {}
1648 
receiver() const1649 Handle<Object> FrameSummary::WasmFrameSummary::receiver() const {
1650   return wasm_instance_->GetIsolate()->global_proxy();
1651 }
1652 
function_index() const1653 uint32_t FrameSummary::WasmFrameSummary::function_index() const {
1654   return code()->index();
1655 }
1656 
byte_offset() const1657 int FrameSummary::WasmFrameSummary::byte_offset() const {
1658   return code_->GetSourcePositionBefore(code_offset());
1659 }
1660 
SourcePosition() const1661 int FrameSummary::WasmFrameSummary::SourcePosition() const {
1662   const wasm::WasmModule* module = wasm_instance()->module_object().module();
1663   return GetSourcePosition(module, function_index(), byte_offset(),
1664                            at_to_number_conversion());
1665 }
1666 
script() const1667 Handle<Script> FrameSummary::WasmFrameSummary::script() const {
1668   return handle(wasm_instance()->module_object().script(),
1669                 wasm_instance()->GetIsolate());
1670 }
1671 
native_context() const1672 Handle<Context> FrameSummary::WasmFrameSummary::native_context() const {
1673   return handle(wasm_instance()->native_context(), isolate());
1674 }
1675 
CreateStackFrameInfo() const1676 Handle<StackFrameInfo> FrameSummary::WasmFrameSummary::CreateStackFrameInfo()
1677     const {
1678   Handle<String> function_name =
1679       GetWasmFunctionDebugName(isolate(), wasm_instance(), function_index());
1680   return isolate()->factory()->NewStackFrameInfo(script(), SourcePosition(),
1681                                                  function_name, false);
1682 }
1683 #endif  // V8_ENABLE_WEBASSEMBLY
1684 
~FrameSummary()1685 FrameSummary::~FrameSummary() {
1686 #define FRAME_SUMMARY_DESTR(kind, type, field, desc) \
1687   case kind:                                         \
1688     field.~type();                                   \
1689     break;
1690   switch (base_.kind()) {
1691     FRAME_SUMMARY_VARIANTS(FRAME_SUMMARY_DESTR)
1692     default:
1693       UNREACHABLE();
1694   }
1695 #undef FRAME_SUMMARY_DESTR
1696 }
1697 
GetTop(const CommonFrame * frame)1698 FrameSummary FrameSummary::GetTop(const CommonFrame* frame) {
1699   std::vector<FrameSummary> frames;
1700   frame->Summarize(&frames);
1701   DCHECK_LT(0, frames.size());
1702   return frames.back();
1703 }
1704 
GetBottom(const CommonFrame * frame)1705 FrameSummary FrameSummary::GetBottom(const CommonFrame* frame) {
1706   return Get(frame, 0);
1707 }
1708 
GetSingle(const CommonFrame * frame)1709 FrameSummary FrameSummary::GetSingle(const CommonFrame* frame) {
1710   std::vector<FrameSummary> frames;
1711   frame->Summarize(&frames);
1712   DCHECK_EQ(1, frames.size());
1713   return frames.front();
1714 }
1715 
Get(const CommonFrame * frame,int index)1716 FrameSummary FrameSummary::Get(const CommonFrame* frame, int index) {
1717   DCHECK_LE(0, index);
1718   std::vector<FrameSummary> frames;
1719   frame->Summarize(&frames);
1720   DCHECK_GT(frames.size(), index);
1721   return frames[index];
1722 }
1723 
1724 #if V8_ENABLE_WEBASSEMBLY
1725 #define FRAME_SUMMARY_DISPATCH(ret, name)   \
1726   ret FrameSummary::name() const {          \
1727     switch (base_.kind()) {                 \
1728       case JAVA_SCRIPT:                     \
1729         return java_script_summary_.name(); \
1730       case WASM:                            \
1731         return wasm_summary_.name();        \
1732       default:                              \
1733         UNREACHABLE();                      \
1734     }                                       \
1735   }
1736 #else
1737 #define FRAME_SUMMARY_DISPATCH(ret, name) \
1738   ret FrameSummary::name() const {        \
1739     DCHECK_EQ(JAVA_SCRIPT, base_.kind()); \
1740     return java_script_summary_.name();   \
1741   }
1742 #endif  // V8_ENABLE_WEBASSEMBLY
1743 
FRAME_SUMMARY_DISPATCH(Handle<Object>,receiver)1744 FRAME_SUMMARY_DISPATCH(Handle<Object>, receiver)
1745 FRAME_SUMMARY_DISPATCH(int, code_offset)
1746 FRAME_SUMMARY_DISPATCH(bool, is_constructor)
1747 FRAME_SUMMARY_DISPATCH(bool, is_subject_to_debugging)
1748 FRAME_SUMMARY_DISPATCH(Handle<Object>, script)
1749 FRAME_SUMMARY_DISPATCH(int, SourcePosition)
1750 FRAME_SUMMARY_DISPATCH(int, SourceStatementPosition)
1751 FRAME_SUMMARY_DISPATCH(Handle<Context>, native_context)
1752 FRAME_SUMMARY_DISPATCH(Handle<StackFrameInfo>, CreateStackFrameInfo)
1753 
1754 #undef FRAME_SUMMARY_DISPATCH
1755 
1756 void OptimizedFrame::Summarize(std::vector<FrameSummary>* frames) const {
1757   DCHECK(frames->empty());
1758   DCHECK(is_optimized());
1759 
1760   // Delegate to JS frame in absence of turbofan deoptimization.
1761   // TODO(turbofan): Revisit once we support deoptimization across the board.
1762   Code code = LookupCode();
1763   if (code.kind() == CodeKind::BUILTIN) {
1764     return JavaScriptFrame::Summarize(frames);
1765   }
1766 
1767   int deopt_index = SafepointEntry::kNoDeoptIndex;
1768   DeoptimizationData const data = GetDeoptimizationData(&deopt_index);
1769   if (deopt_index == SafepointEntry::kNoDeoptIndex) {
1770     CHECK(data.is_null());
1771     FATAL("Missing deoptimization information for OptimizedFrame::Summarize.");
1772   }
1773 
1774   // Prepare iteration over translation. Note that the below iteration might
1775   // materialize objects without storing them back to the Isolate, this will
1776   // lead to objects being re-materialized again for each summary.
1777   TranslatedState translated(this);
1778   translated.Prepare(fp());
1779 
1780   // We create the summary in reverse order because the frames
1781   // in the deoptimization translation are ordered bottom-to-top.
1782   bool is_constructor = IsConstructor();
1783   for (auto it = translated.begin(); it != translated.end(); it++) {
1784     if (it->kind() == TranslatedFrame::kUnoptimizedFunction ||
1785         it->kind() == TranslatedFrame::kJavaScriptBuiltinContinuation ||
1786         it->kind() ==
1787             TranslatedFrame::kJavaScriptBuiltinContinuationWithCatch) {
1788       Handle<SharedFunctionInfo> shared_info = it->shared_info();
1789 
1790       // The translation commands are ordered and the function is always
1791       // at the first position, and the receiver is next.
1792       TranslatedFrame::iterator translated_values = it->begin();
1793 
1794       // Get or materialize the correct function in the optimized frame.
1795       Handle<JSFunction> function =
1796           Handle<JSFunction>::cast(translated_values->GetValue());
1797       translated_values++;
1798 
1799       // Get or materialize the correct receiver in the optimized frame.
1800       Handle<Object> receiver = translated_values->GetValue();
1801       translated_values++;
1802 
1803       // Determine the underlying code object and the position within it from
1804       // the translation corresponding to the frame type in question.
1805       Handle<AbstractCode> abstract_code;
1806       unsigned code_offset;
1807       if (it->kind() == TranslatedFrame::kJavaScriptBuiltinContinuation ||
1808           it->kind() ==
1809               TranslatedFrame::kJavaScriptBuiltinContinuationWithCatch) {
1810         code_offset = 0;
1811         abstract_code = ToAbstractCode(
1812             isolate()->builtins()->code_handle(
1813                 Builtins::GetBuiltinFromBytecodeOffset(it->bytecode_offset())),
1814             isolate());
1815       } else {
1816         DCHECK_EQ(it->kind(), TranslatedFrame::kUnoptimizedFunction);
1817         code_offset = it->bytecode_offset().ToInt();
1818         abstract_code =
1819             handle(shared_info->abstract_code(isolate()), isolate());
1820       }
1821 
1822       // Append full summary of the encountered JS frame.
1823       Handle<FixedArray> params = GetParameters();
1824       FrameSummary::JavaScriptFrameSummary summary(
1825           isolate(), *receiver, *function, *abstract_code, code_offset,
1826           is_constructor, *params);
1827       frames->push_back(summary);
1828       is_constructor = false;
1829     } else if (it->kind() == TranslatedFrame::kConstructStub) {
1830       // The next encountered JS frame will be marked as a constructor call.
1831       DCHECK(!is_constructor);
1832       is_constructor = true;
1833     }
1834   }
1835 }
1836 
LookupExceptionHandlerInTable(int * data,HandlerTable::CatchPrediction * prediction)1837 int OptimizedFrame::LookupExceptionHandlerInTable(
1838     int* data, HandlerTable::CatchPrediction* prediction) {
1839   // We cannot perform exception prediction on optimized code. Instead, we need
1840   // to use FrameSummary to find the corresponding code offset in unoptimized
1841   // code to perform prediction there.
1842   DCHECK_NULL(prediction);
1843   Code code = LookupCode();
1844   HandlerTable table(code);
1845   int pc_offset = code.GetOffsetFromInstructionStart(isolate(), pc());
1846   DCHECK_NULL(data);  // Data is not used and will not return a value.
1847 
1848   // When the return pc has been replaced by a trampoline there won't be
1849   // a handler for this trampoline. Thus we need to use the return pc that
1850   // _used to be_ on the stack to get the right ExceptionHandler.
1851   if (CodeKindCanDeoptimize(code.kind()) && code.marked_for_deoptimization()) {
1852     SafepointTable safepoints(isolate(), pc(), code);
1853     pc_offset = safepoints.find_return_pc(pc_offset);
1854   }
1855   return table.LookupReturn(pc_offset);
1856 }
1857 
GetDeoptimizationData(int * deopt_index) const1858 DeoptimizationData OptimizedFrame::GetDeoptimizationData(
1859     int* deopt_index) const {
1860   DCHECK(is_optimized());
1861 
1862   JSFunction opt_function = function();
1863   Code code = FromCodeT(opt_function.code());
1864 
1865   // The code object may have been replaced by lazy deoptimization. Fall
1866   // back to a slow search in this case to find the original optimized
1867   // code object.
1868   if (!code.contains(isolate(), pc())) {
1869     code = isolate()->heap()->GcSafeFindCodeForInnerPointer(pc());
1870   }
1871   DCHECK(!code.is_null());
1872   DCHECK(CodeKindCanDeoptimize(code.kind()));
1873 
1874   SafepointEntry safepoint_entry = code.GetSafepointEntry(isolate(), pc());
1875   if (safepoint_entry.has_deoptimization_index()) {
1876     *deopt_index = safepoint_entry.deoptimization_index();
1877     return DeoptimizationData::cast(code.deoptimization_data());
1878   }
1879   *deopt_index = SafepointEntry::kNoDeoptIndex;
1880   return DeoptimizationData();
1881 }
1882 
GetFunctions(std::vector<SharedFunctionInfo> * functions) const1883 void OptimizedFrame::GetFunctions(
1884     std::vector<SharedFunctionInfo>* functions) const {
1885   DCHECK(functions->empty());
1886   DCHECK(is_optimized());
1887 
1888   // Delegate to JS frame in absence of turbofan deoptimization.
1889   // TODO(turbofan): Revisit once we support deoptimization across the board.
1890   Code code = LookupCode();
1891   if (code.kind() == CodeKind::BUILTIN) {
1892     return JavaScriptFrame::GetFunctions(functions);
1893   }
1894 
1895   DisallowGarbageCollection no_gc;
1896   int deopt_index = SafepointEntry::kNoDeoptIndex;
1897   DeoptimizationData const data = GetDeoptimizationData(&deopt_index);
1898   DCHECK(!data.is_null());
1899   DCHECK_NE(SafepointEntry::kNoDeoptIndex, deopt_index);
1900   DeoptimizationLiteralArray const literal_array = data.LiteralArray();
1901 
1902   TranslationArrayIterator it(data.TranslationByteArray(),
1903                               data.TranslationIndex(deopt_index).value());
1904   TranslationOpcode opcode = TranslationOpcodeFromInt(it.Next());
1905   DCHECK_EQ(TranslationOpcode::BEGIN, opcode);
1906   it.Next();  // Skip frame count.
1907   int jsframe_count = it.Next();
1908   it.Next();  // Skip update feedback count.
1909 
1910   // We insert the frames in reverse order because the frames
1911   // in the deoptimization translation are ordered bottom-to-top.
1912   while (jsframe_count != 0) {
1913     opcode = TranslationOpcodeFromInt(it.Next());
1914     if (opcode == TranslationOpcode::INTERPRETED_FRAME ||
1915         opcode == TranslationOpcode::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME ||
1916         opcode == TranslationOpcode::
1917                       JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME) {
1918       it.Next();  // Skip bailout id.
1919       jsframe_count--;
1920 
1921       // The second operand of the frame points to the function.
1922       Object shared = literal_array.get(it.Next());
1923       functions->push_back(SharedFunctionInfo::cast(shared));
1924 
1925       // Skip over remaining operands to advance to the next opcode.
1926       it.Skip(TranslationOpcodeOperandCount(opcode) - 2);
1927     } else {
1928       // Skip over operands to advance to the next opcode.
1929       it.Skip(TranslationOpcodeOperandCount(opcode));
1930     }
1931   }
1932 }
1933 
StackSlotOffsetRelativeToFp(int slot_index)1934 int OptimizedFrame::StackSlotOffsetRelativeToFp(int slot_index) {
1935   return StandardFrameConstants::kCallerSPOffset -
1936          ((slot_index + 1) * kSystemPointerSize);
1937 }
1938 
StackSlotAt(int index) const1939 Object OptimizedFrame::StackSlotAt(int index) const {
1940   return Object(Memory<Address>(fp() + StackSlotOffsetRelativeToFp(index)));
1941 }
1942 
position() const1943 int UnoptimizedFrame::position() const {
1944   AbstractCode code = AbstractCode::cast(GetBytecodeArray());
1945   int code_offset = GetBytecodeOffset();
1946   return code.SourcePosition(code_offset);
1947 }
1948 
LookupExceptionHandlerInTable(int * context_register,HandlerTable::CatchPrediction * prediction)1949 int UnoptimizedFrame::LookupExceptionHandlerInTable(
1950     int* context_register, HandlerTable::CatchPrediction* prediction) {
1951   HandlerTable table(GetBytecodeArray());
1952   return table.LookupRange(GetBytecodeOffset(), context_register, prediction);
1953 }
1954 
GetBytecodeArray() const1955 BytecodeArray UnoptimizedFrame::GetBytecodeArray() const {
1956   const int index = UnoptimizedFrameConstants::kBytecodeArrayExpressionIndex;
1957   DCHECK_EQ(UnoptimizedFrameConstants::kBytecodeArrayFromFp,
1958             UnoptimizedFrameConstants::kExpressionsOffset -
1959                 index * kSystemPointerSize);
1960   return BytecodeArray::cast(GetExpression(index));
1961 }
1962 
ReadInterpreterRegister(int register_index) const1963 Object UnoptimizedFrame::ReadInterpreterRegister(int register_index) const {
1964   const int index = UnoptimizedFrameConstants::kRegisterFileExpressionIndex;
1965   DCHECK_EQ(UnoptimizedFrameConstants::kRegisterFileFromFp,
1966             UnoptimizedFrameConstants::kExpressionsOffset -
1967                 index * kSystemPointerSize);
1968   return GetExpression(index + register_index);
1969 }
1970 
Summarize(std::vector<FrameSummary> * functions) const1971 void UnoptimizedFrame::Summarize(std::vector<FrameSummary>* functions) const {
1972   DCHECK(functions->empty());
1973   Handle<AbstractCode> abstract_code(AbstractCode::cast(GetBytecodeArray()),
1974                                      isolate());
1975   Handle<FixedArray> params = GetParameters();
1976   FrameSummary::JavaScriptFrameSummary summary(
1977       isolate(), receiver(), function(), *abstract_code, GetBytecodeOffset(),
1978       IsConstructor(), *params);
1979   functions->push_back(summary);
1980 }
1981 
GetBytecodeOffset() const1982 int InterpretedFrame::GetBytecodeOffset() const {
1983   const int index = InterpreterFrameConstants::kBytecodeOffsetExpressionIndex;
1984   DCHECK_EQ(InterpreterFrameConstants::kBytecodeOffsetFromFp,
1985             InterpreterFrameConstants::kExpressionsOffset -
1986                 index * kSystemPointerSize);
1987   int raw_offset = Smi::ToInt(GetExpression(index));
1988   return raw_offset - BytecodeArray::kHeaderSize + kHeapObjectTag;
1989 }
1990 
1991 // static
GetBytecodeOffset(Address fp)1992 int InterpretedFrame::GetBytecodeOffset(Address fp) {
1993   const int offset = InterpreterFrameConstants::kExpressionsOffset;
1994   const int index = InterpreterFrameConstants::kBytecodeOffsetExpressionIndex;
1995   DCHECK_EQ(InterpreterFrameConstants::kBytecodeOffsetFromFp,
1996             InterpreterFrameConstants::kExpressionsOffset -
1997                 index * kSystemPointerSize);
1998   Address expression_offset = fp + offset - index * kSystemPointerSize;
1999   int raw_offset = Smi::ToInt(Object(Memory<Address>(expression_offset)));
2000   return raw_offset - BytecodeArray::kHeaderSize + kHeapObjectTag;
2001 }
2002 
PatchBytecodeOffset(int new_offset)2003 void InterpretedFrame::PatchBytecodeOffset(int new_offset) {
2004   const int index = InterpreterFrameConstants::kBytecodeOffsetExpressionIndex;
2005   DCHECK_EQ(InterpreterFrameConstants::kBytecodeOffsetFromFp,
2006             InterpreterFrameConstants::kExpressionsOffset -
2007                 index * kSystemPointerSize);
2008   int raw_offset = BytecodeArray::kHeaderSize - kHeapObjectTag + new_offset;
2009   SetExpression(index, Smi::FromInt(raw_offset));
2010 }
2011 
PatchBytecodeArray(BytecodeArray bytecode_array)2012 void InterpretedFrame::PatchBytecodeArray(BytecodeArray bytecode_array) {
2013   const int index = InterpreterFrameConstants::kBytecodeArrayExpressionIndex;
2014   DCHECK_EQ(InterpreterFrameConstants::kBytecodeArrayFromFp,
2015             InterpreterFrameConstants::kExpressionsOffset -
2016                 index * kSystemPointerSize);
2017   SetExpression(index, bytecode_array);
2018 }
2019 
GetBytecodeOffset() const2020 int BaselineFrame::GetBytecodeOffset() const {
2021   return LookupCode().GetBytecodeOffsetForBaselinePC(this->pc(),
2022                                                      GetBytecodeArray());
2023 }
2024 
GetPCForBytecodeOffset(int bytecode_offset) const2025 intptr_t BaselineFrame::GetPCForBytecodeOffset(int bytecode_offset) const {
2026   return LookupCode().GetBaselineStartPCForBytecodeOffset(bytecode_offset,
2027                                                           GetBytecodeArray());
2028 }
2029 
PatchContext(Context value)2030 void BaselineFrame::PatchContext(Context value) {
2031   base::Memory<Address>(fp() + BaselineFrameConstants::kContextOffset) =
2032       value.ptr();
2033 }
2034 
function() const2035 JSFunction BuiltinFrame::function() const {
2036   const int offset = BuiltinFrameConstants::kFunctionOffset;
2037   return JSFunction::cast(Object(base::Memory<Address>(fp() + offset)));
2038 }
2039 
ComputeParametersCount() const2040 int BuiltinFrame::ComputeParametersCount() const {
2041   const int offset = BuiltinFrameConstants::kLengthOffset;
2042   return Smi::ToInt(Object(base::Memory<Address>(fp() + offset))) -
2043          kJSArgcReceiverSlots;
2044 }
2045 
2046 #if V8_ENABLE_WEBASSEMBLY
Print(StringStream * accumulator,PrintMode mode,int index) const2047 void WasmFrame::Print(StringStream* accumulator, PrintMode mode,
2048                       int index) const {
2049   PrintIndex(accumulator, mode, index);
2050   if (function_index() == wasm::kAnonymousFuncIndex) {
2051     accumulator->Add("Anonymous wasm wrapper [pc: %p]\n",
2052                      reinterpret_cast<void*>(pc()));
2053     return;
2054   }
2055   wasm::WasmCodeRefScope code_ref_scope;
2056   accumulator->Add("Wasm [");
2057   accumulator->PrintName(script().name());
2058   Address instruction_start = wasm_code()->instruction_start();
2059   base::Vector<const uint8_t> raw_func_name =
2060       module_object().GetRawFunctionName(function_index());
2061   const int kMaxPrintedFunctionName = 64;
2062   char func_name[kMaxPrintedFunctionName + 1];
2063   int func_name_len = std::min(kMaxPrintedFunctionName, raw_func_name.length());
2064   memcpy(func_name, raw_func_name.begin(), func_name_len);
2065   func_name[func_name_len] = '\0';
2066   int pos = position();
2067   const wasm::WasmModule* module = wasm_instance().module_object().module();
2068   int func_index = function_index();
2069   int func_code_offset = module->functions[func_index].code.offset();
2070   accumulator->Add("], function #%u ('%s'), pc=%p (+0x%x), pos=%d (+%d)\n",
2071                    func_index, func_name, reinterpret_cast<void*>(pc()),
2072                    static_cast<int>(pc() - instruction_start), pos,
2073                    pos - func_code_offset);
2074   if (mode != OVERVIEW) accumulator->Add("\n");
2075 }
2076 
wasm_code() const2077 wasm::WasmCode* WasmFrame::wasm_code() const {
2078   return wasm::GetWasmCodeManager()->LookupCode(pc());
2079 }
2080 
wasm_instance() const2081 WasmInstanceObject WasmFrame::wasm_instance() const {
2082   const int offset = WasmFrameConstants::kWasmInstanceOffset;
2083   Object instance(Memory<Address>(fp() + offset));
2084   return WasmInstanceObject::cast(instance);
2085 }
2086 
native_module() const2087 wasm::NativeModule* WasmFrame::native_module() const {
2088   return module_object().native_module();
2089 }
2090 
module_object() const2091 WasmModuleObject WasmFrame::module_object() const {
2092   return wasm_instance().module_object();
2093 }
2094 
function_index() const2095 int WasmFrame::function_index() const {
2096   wasm::WasmCodeRefScope code_ref_scope;
2097   return wasm_code()->index();
2098 }
2099 
script() const2100 Script WasmFrame::script() const { return module_object().script(); }
2101 
position() const2102 int WasmFrame::position() const {
2103   wasm::WasmCodeRefScope code_ref_scope;
2104   const wasm::WasmModule* module = wasm_instance().module_object().module();
2105   return GetSourcePosition(module, function_index(), byte_offset(),
2106                            at_to_number_conversion());
2107 }
2108 
byte_offset() const2109 int WasmFrame::byte_offset() const {
2110   wasm::WasmCode* code = wasm_code();
2111   int offset = static_cast<int>(pc() - code->instruction_start());
2112   return code->GetSourcePositionBefore(offset);
2113 }
2114 
is_inspectable() const2115 bool WasmFrame::is_inspectable() const {
2116   wasm::WasmCodeRefScope code_ref_scope;
2117   return wasm_code()->is_inspectable();
2118 }
2119 
context() const2120 Object WasmFrame::context() const { return wasm_instance().native_context(); }
2121 
Summarize(std::vector<FrameSummary> * functions) const2122 void WasmFrame::Summarize(std::vector<FrameSummary>* functions) const {
2123   DCHECK(functions->empty());
2124   // The {WasmCode*} escapes this scope via the {FrameSummary}, which is fine,
2125   // since this code object is part of our stack.
2126   wasm::WasmCodeRefScope code_ref_scope;
2127   wasm::WasmCode* code = wasm_code();
2128   int offset = static_cast<int>(pc() - code->instruction_start());
2129   Handle<WasmInstanceObject> instance(wasm_instance(), isolate());
2130   FrameSummary::WasmFrameSummary summary(isolate(), instance, code, offset,
2131                                          at_to_number_conversion());
2132   functions->push_back(summary);
2133 }
2134 
at_to_number_conversion() const2135 bool WasmFrame::at_to_number_conversion() const {
2136   // Check whether our callee is a WASM_TO_JS frame, and this frame is at the
2137   // ToNumber conversion call.
2138   wasm::WasmCode* code =
2139       callee_pc() != kNullAddress
2140           ? wasm::GetWasmCodeManager()->LookupCode(callee_pc())
2141           : nullptr;
2142   if (!code || code->kind() != wasm::WasmCode::kWasmToJsWrapper) return false;
2143   int offset = static_cast<int>(callee_pc() - code->instruction_start());
2144   int pos = code->GetSourcePositionBefore(offset);
2145   // The imported call has position 0, ToNumber has position 1.
2146   // If there is no source position available, this is also not a ToNumber call.
2147   DCHECK(pos == wasm::kNoCodePosition || pos == 0 || pos == 1);
2148   return pos == 1;
2149 }
2150 
LookupExceptionHandlerInTable()2151 int WasmFrame::LookupExceptionHandlerInTable() {
2152   wasm::WasmCode* code = wasm::GetWasmCodeManager()->LookupCode(pc());
2153   if (!code->IsAnonymous() && code->handler_table_size() > 0) {
2154     HandlerTable table(code);
2155     int pc_offset = static_cast<int>(pc() - code->instruction_start());
2156     return table.LookupReturn(pc_offset);
2157   }
2158   return -1;
2159 }
2160 
Iterate(RootVisitor * v) const2161 void WasmDebugBreakFrame::Iterate(RootVisitor* v) const {
2162   DCHECK(caller_pc());
2163   wasm::WasmCode* code = wasm::GetWasmCodeManager()->LookupCode(caller_pc());
2164   DCHECK(code);
2165   SafepointTable table(code);
2166   SafepointEntry safepoint_entry = table.FindEntry(caller_pc());
2167   uint32_t tagged_register_indexes = safepoint_entry.tagged_register_indexes();
2168 
2169   while (tagged_register_indexes != 0) {
2170     int reg_code = base::bits::CountTrailingZeros(tagged_register_indexes);
2171     tagged_register_indexes &= ~(1 << reg_code);
2172     FullObjectSlot spill_slot(&Memory<Address>(
2173         fp() +
2174         WasmDebugBreakFrameConstants::GetPushedGpRegisterOffset(reg_code)));
2175 
2176     v->VisitRootPointer(Root::kStackRoots, nullptr, spill_slot);
2177   }
2178 }
2179 
Print(StringStream * accumulator,PrintMode mode,int index) const2180 void WasmDebugBreakFrame::Print(StringStream* accumulator, PrintMode mode,
2181                                 int index) const {
2182   PrintIndex(accumulator, mode, index);
2183   accumulator->Add("WasmDebugBreak");
2184   if (mode != OVERVIEW) accumulator->Add("\n");
2185 }
2186 
Iterate(RootVisitor * v) const2187 void JsToWasmFrame::Iterate(RootVisitor* v) const {
2188   Code code = GetContainingCode(isolate(), pc());
2189   //  GenericJSToWasmWrapper stack layout
2190   //  ------+-----------------+----------------------
2191   //        |  return addr    |
2192   //    fp  |- - - - - - - - -|  -------------------|
2193   //        |       fp        |                     |
2194   //   fp-p |- - - - - - - - -|                     |
2195   //        |  frame marker   |                     | no GC scan
2196   //  fp-2p |- - - - - - - - -|                     |
2197   //        |   scan_count    |                     |
2198   //  fp-3p |- - - - - - - - -|  -------------------|
2199   //        |      ....       | <- spill_slot_limit |
2200   //        |   spill slots   |                     | GC scan scan_count slots
2201   //        |      ....       | <- spill_slot_base--|
2202   //        |- - - - - - - - -|                     |
2203   if (code.is_null() || !code.is_builtin() ||
2204       code.builtin_id() != Builtin::kGenericJSToWasmWrapper) {
2205     // If it's not the  GenericJSToWasmWrapper, then it's the TurboFan compiled
2206     // specific wrapper. So we have to call IterateCompiledFrame.
2207     IterateCompiledFrame(v);
2208     return;
2209   }
2210   // The [fp + BuiltinFrameConstants::kGCScanSlotCount] on the stack is a value
2211   // indicating how many values should be scanned from the top.
2212   intptr_t scan_count = *reinterpret_cast<intptr_t*>(
2213       fp() + BuiltinWasmWrapperConstants::kGCScanSlotCountOffset);
2214 
2215   FullObjectSlot spill_slot_base(&Memory<Address>(sp()));
2216   FullObjectSlot spill_slot_limit(
2217       &Memory<Address>(sp() + scan_count * kSystemPointerSize));
2218   v->VisitRootPointers(Root::kStackRoots, nullptr, spill_slot_base,
2219                        spill_slot_limit);
2220 }
2221 
Iterate(RootVisitor * v) const2222 void StackSwitchFrame::Iterate(RootVisitor* v) const {
2223   //  See JsToWasmFrame layout.
2224   //  We cannot DCHECK that the pc matches the expected builtin code here,
2225   //  because the return address is on a different stack.
2226   // The [fp + BuiltinFrameConstants::kGCScanSlotCountOffset] on the stack is a
2227   // value indicating how many values should be scanned from the top.
2228   intptr_t scan_count = *reinterpret_cast<intptr_t*>(
2229       fp() + BuiltinWasmWrapperConstants::kGCScanSlotCountOffset);
2230 
2231   FullObjectSlot spill_slot_base(&Memory<Address>(sp()));
2232   FullObjectSlot spill_slot_limit(
2233       &Memory<Address>(sp() + scan_count * kSystemPointerSize));
2234   v->VisitRootPointers(Root::kStackRoots, nullptr, spill_slot_base,
2235                        spill_slot_limit);
2236 }
2237 
2238 // static
GetStateForJumpBuffer(wasm::JumpBuffer * jmpbuf,State * state)2239 void StackSwitchFrame::GetStateForJumpBuffer(wasm::JumpBuffer* jmpbuf,
2240                                              State* state) {
2241   DCHECK_NE(jmpbuf->fp, kNullAddress);
2242   DCHECK_EQ(ComputeFrameType(jmpbuf->fp), STACK_SWITCH);
2243   FillState(jmpbuf->fp, jmpbuf->sp, state);
2244   DCHECK_NE(*state->pc_address, kNullAddress);
2245 }
2246 
wasm_instance() const2247 WasmInstanceObject WasmCompileLazyFrame::wasm_instance() const {
2248   return WasmInstanceObject::cast(*wasm_instance_slot());
2249 }
2250 
wasm_instance_slot() const2251 FullObjectSlot WasmCompileLazyFrame::wasm_instance_slot() const {
2252   const int offset = WasmCompileLazyFrameConstants::kWasmInstanceOffset;
2253   return FullObjectSlot(&Memory<Address>(fp() + offset));
2254 }
2255 
Iterate(RootVisitor * v) const2256 void WasmCompileLazyFrame::Iterate(RootVisitor* v) const {
2257   const int header_size = WasmCompileLazyFrameConstants::kFixedFrameSizeFromFp;
2258   FullObjectSlot base(&Memory<Address>(sp()));
2259   FullObjectSlot limit(&Memory<Address>(fp() - header_size));
2260   v->VisitRootPointers(Root::kStackRoots, nullptr, base, limit);
2261   v->VisitRootPointer(Root::kStackRoots, nullptr, wasm_instance_slot());
2262 }
2263 #endif  // V8_ENABLE_WEBASSEMBLY
2264 
2265 namespace {
2266 
PrintFunctionSource(StringStream * accumulator,SharedFunctionInfo shared,Code code)2267 void PrintFunctionSource(StringStream* accumulator, SharedFunctionInfo shared,
2268                          Code code) {
2269   if (FLAG_max_stack_trace_source_length != 0 && !code.is_null()) {
2270     std::ostringstream os;
2271     os << "--------- s o u r c e   c o d e ---------\n"
2272        << SourceCodeOf(shared, FLAG_max_stack_trace_source_length)
2273        << "\n-----------------------------------------\n";
2274     accumulator->Add(os.str().c_str());
2275   }
2276 }
2277 
2278 }  // namespace
2279 
Print(StringStream * accumulator,PrintMode mode,int index) const2280 void JavaScriptFrame::Print(StringStream* accumulator, PrintMode mode,
2281                             int index) const {
2282   Handle<SharedFunctionInfo> shared = handle(function().shared(), isolate());
2283   SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate(), shared);
2284 
2285   DisallowGarbageCollection no_gc;
2286   Object receiver = this->receiver();
2287   JSFunction function = this->function();
2288 
2289   accumulator->PrintSecurityTokenIfChanged(function);
2290   PrintIndex(accumulator, mode, index);
2291   PrintFrameKind(accumulator);
2292   Code code;
2293   if (IsConstructor()) accumulator->Add("new ");
2294   accumulator->PrintFunction(function, receiver, &code);
2295   accumulator->Add(" [%p]", function);
2296 
2297   // Get scope information for nicer output, if possible. If code is nullptr, or
2298   // doesn't contain scope info, scope_info will return 0 for the number of
2299   // parameters, stack local variables, context local variables, stack slots,
2300   // or context slots.
2301   ScopeInfo scope_info = shared->scope_info();
2302   Object script_obj = shared->script();
2303   if (script_obj.IsScript()) {
2304     Script script = Script::cast(script_obj);
2305     accumulator->Add(" [");
2306     accumulator->PrintName(script.name());
2307 
2308     if (is_interpreted()) {
2309       const InterpretedFrame* iframe = InterpretedFrame::cast(this);
2310       BytecodeArray bytecodes = iframe->GetBytecodeArray();
2311       int offset = iframe->GetBytecodeOffset();
2312       int source_pos = AbstractCode::cast(bytecodes).SourcePosition(offset);
2313       int line = script.GetLineNumber(source_pos) + 1;
2314       accumulator->Add(":%d] [bytecode=%p offset=%d]", line,
2315                        reinterpret_cast<void*>(bytecodes.ptr()), offset);
2316     } else {
2317       int function_start_pos = shared->StartPosition();
2318       int line = script.GetLineNumber(function_start_pos) + 1;
2319       accumulator->Add(":~%d] [pc=%p]", line, reinterpret_cast<void*>(pc()));
2320     }
2321   }
2322 
2323   accumulator->Add("(this=%o", receiver);
2324 
2325   // Print the parameters.
2326   int parameters_count = ComputeParametersCount();
2327   for (int i = 0; i < parameters_count; i++) {
2328     accumulator->Add(",");
2329     accumulator->Add("%o", GetParameter(i));
2330   }
2331 
2332   accumulator->Add(")");
2333   if (mode == OVERVIEW) {
2334     accumulator->Add("\n");
2335     return;
2336   }
2337   if (is_optimized()) {
2338     accumulator->Add(" {\n// optimized frame\n");
2339     PrintFunctionSource(accumulator, *shared, code);
2340     accumulator->Add("}\n");
2341     return;
2342   }
2343   accumulator->Add(" {\n");
2344 
2345   // Compute the number of locals and expression stack elements.
2346   int heap_locals_count = scope_info.ContextLocalCount();
2347   int expressions_count = ComputeExpressionsCount();
2348 
2349   // Try to get hold of the context of this frame.
2350   Context context;
2351   if (this->context().IsContext()) {
2352     context = Context::cast(this->context());
2353     while (context.IsWithContext()) {
2354       context = context.previous();
2355       DCHECK(!context.is_null());
2356     }
2357   }
2358 
2359   // Print heap-allocated local variables.
2360   if (heap_locals_count > 0) {
2361     accumulator->Add("  // heap-allocated locals\n");
2362   }
2363   for (auto it : ScopeInfo::IterateLocalNames(&scope_info, no_gc)) {
2364     accumulator->Add("  var ");
2365     accumulator->PrintName(it->name());
2366     accumulator->Add(" = ");
2367     if (!context.is_null()) {
2368       int slot_index = Context::MIN_CONTEXT_SLOTS + it->index();
2369       if (slot_index < context.length()) {
2370         accumulator->Add("%o", context.get(slot_index));
2371       } else {
2372         accumulator->Add(
2373             "// warning: missing context slot - inconsistent frame?");
2374       }
2375     } else {
2376       accumulator->Add("// warning: no context found - inconsistent frame?");
2377     }
2378     accumulator->Add("\n");
2379   }
2380 
2381   // Print the expression stack.
2382   if (0 < expressions_count) {
2383     accumulator->Add("  // expression stack (top to bottom)\n");
2384   }
2385   for (int i = expressions_count - 1; i >= 0; i--) {
2386     accumulator->Add("  [%02d] : %o\n", i, GetExpression(i));
2387   }
2388 
2389   PrintFunctionSource(accumulator, *shared, code);
2390 
2391   accumulator->Add("}\n\n");
2392 }
2393 
Iterate(RootVisitor * v) const2394 void EntryFrame::Iterate(RootVisitor* v) const {
2395   IteratePc(v, pc_address(), constant_pool_address(), LookupCode());
2396 }
2397 
IterateExpressions(RootVisitor * v) const2398 void CommonFrame::IterateExpressions(RootVisitor* v) const {
2399   const int last_object_offset = StandardFrameConstants::kLastObjectOffset;
2400   intptr_t marker =
2401       Memory<intptr_t>(fp() + CommonFrameConstants::kContextOrFrameTypeOffset);
2402   FullObjectSlot base(&Memory<Address>(sp()));
2403   FullObjectSlot limit(&Memory<Address>(fp() + last_object_offset) + 1);
2404   if (StackFrame::IsTypeMarker(marker)) {
2405     v->VisitRootPointers(Root::kStackRoots, nullptr, base, limit);
2406   } else {
2407     // The frame contains the actual argument count (intptr) that should not be
2408     // visited.
2409     FullObjectSlot argc(
2410         &Memory<Address>(fp() + StandardFrameConstants::kArgCOffset));
2411     v->VisitRootPointers(Root::kStackRoots, nullptr, base, argc);
2412     v->VisitRootPointers(Root::kStackRoots, nullptr, argc + 1, limit);
2413   }
2414 }
2415 
Iterate(RootVisitor * v) const2416 void JavaScriptFrame::Iterate(RootVisitor* v) const {
2417   IterateExpressions(v);
2418   IteratePc(v, pc_address(), constant_pool_address(), LookupCode());
2419 }
2420 
Iterate(RootVisitor * v) const2421 void InternalFrame::Iterate(RootVisitor* v) const {
2422   Code code = LookupCode();
2423   IteratePc(v, pc_address(), constant_pool_address(), code);
2424   // Internal frames typically do not receive any arguments, hence their stack
2425   // only contains tagged pointers.
2426   // We are misusing the has_tagged_outgoing_params flag here to tell us whether
2427   // the full stack frame contains only tagged pointers or only raw values.
2428   // This is used for the WasmCompileLazy builtin, where we actually pass
2429   // untagged arguments and also store untagged values on the stack.
2430   if (code.has_tagged_outgoing_params()) IterateExpressions(v);
2431 }
2432 
2433 // -------------------------------------------------------------------------
2434 
2435 namespace {
2436 
2437 // Predictably converts PC to uint32 by calculating offset of the PC in
2438 // from the embedded builtins start or from respective MemoryChunk.
PcAddressForHashing(Isolate * isolate,Address address)2439 uint32_t PcAddressForHashing(Isolate* isolate, Address address) {
2440   uint32_t hashable_address;
2441   if (OffHeapInstructionStream::TryGetAddressForHashing(isolate, address,
2442                                                         &hashable_address)) {
2443     return hashable_address;
2444   }
2445   return ObjectAddressForHashing(address);
2446 }
2447 
2448 }  // namespace
2449 
2450 InnerPointerToCodeCache::InnerPointerToCodeCacheEntry*
GetCacheEntry(Address inner_pointer)2451 InnerPointerToCodeCache::GetCacheEntry(Address inner_pointer) {
2452   isolate_->counters()->pc_to_code()->Increment();
2453   DCHECK(base::bits::IsPowerOfTwo(kInnerPointerToCodeCacheSize));
2454   uint32_t hash =
2455       ComputeUnseededHash(PcAddressForHashing(isolate_, inner_pointer));
2456   uint32_t index = hash & (kInnerPointerToCodeCacheSize - 1);
2457   InnerPointerToCodeCacheEntry* entry = cache(index);
2458   if (entry->inner_pointer == inner_pointer) {
2459     isolate_->counters()->pc_to_code_cached()->Increment();
2460     DCHECK(entry->code ==
2461            isolate_->heap()->GcSafeFindCodeForInnerPointer(inner_pointer));
2462   } else {
2463     // Because this code may be interrupted by a profiling signal that
2464     // also queries the cache, we cannot update inner_pointer before the code
2465     // has been set. Otherwise, we risk trying to use a cache entry before
2466     // the code has been computed.
2467     entry->code =
2468         isolate_->heap()->GcSafeFindCodeForInnerPointer(inner_pointer);
2469     entry->safepoint_entry.Reset();
2470     entry->inner_pointer = inner_pointer;
2471   }
2472   return entry;
2473 }
2474 
2475 // Frame layout helper class implementation.
2476 // -------------------------------------------------------------------------
2477 
2478 namespace {
2479 
2480 // Some architectures need to push padding together with the TOS register
2481 // in order to maintain stack alignment.
TopOfStackRegisterPaddingSlots()2482 constexpr int TopOfStackRegisterPaddingSlots() {
2483   return ArgumentPaddingSlots(1);
2484 }
2485 
BuiltinContinuationModeIsWithCatch(BuiltinContinuationMode mode)2486 bool BuiltinContinuationModeIsWithCatch(BuiltinContinuationMode mode) {
2487   switch (mode) {
2488     case BuiltinContinuationMode::STUB:
2489     case BuiltinContinuationMode::JAVASCRIPT:
2490       return false;
2491     case BuiltinContinuationMode::JAVASCRIPT_WITH_CATCH:
2492     case BuiltinContinuationMode::JAVASCRIPT_HANDLE_EXCEPTION:
2493       return true;
2494   }
2495   UNREACHABLE();
2496 }
2497 
2498 }  // namespace
2499 
UnoptimizedFrameInfo(int parameters_count_with_receiver,int translation_height,bool is_topmost,bool pad_arguments,FrameInfoKind frame_info_kind)2500 UnoptimizedFrameInfo::UnoptimizedFrameInfo(int parameters_count_with_receiver,
2501                                            int translation_height,
2502                                            bool is_topmost, bool pad_arguments,
2503                                            FrameInfoKind frame_info_kind) {
2504   const int locals_count = translation_height;
2505 
2506   register_stack_slot_count_ =
2507       UnoptimizedFrameConstants::RegisterStackSlotCount(locals_count);
2508 
2509   static constexpr int kTheAccumulator = 1;
2510   static constexpr int kTopOfStackPadding = TopOfStackRegisterPaddingSlots();
2511   int maybe_additional_slots =
2512       (is_topmost || frame_info_kind == FrameInfoKind::kConservative)
2513           ? (kTheAccumulator + kTopOfStackPadding)
2514           : 0;
2515   frame_size_in_bytes_without_fixed_ =
2516       (register_stack_slot_count_ + maybe_additional_slots) *
2517       kSystemPointerSize;
2518 
2519   // The 'fixed' part of the frame consists of the incoming parameters and
2520   // the part described by InterpreterFrameConstants. This will include
2521   // argument padding, when needed.
2522   const int parameter_padding_slots =
2523       pad_arguments ? ArgumentPaddingSlots(parameters_count_with_receiver) : 0;
2524   const int fixed_frame_size =
2525       InterpreterFrameConstants::kFixedFrameSize +
2526       (parameters_count_with_receiver + parameter_padding_slots) *
2527           kSystemPointerSize;
2528   frame_size_in_bytes_ = frame_size_in_bytes_without_fixed_ + fixed_frame_size;
2529 }
2530 
2531 // static
GetStackSizeForAdditionalArguments(int parameters_count)2532 uint32_t UnoptimizedFrameInfo::GetStackSizeForAdditionalArguments(
2533     int parameters_count) {
2534   return (parameters_count + ArgumentPaddingSlots(parameters_count)) *
2535          kSystemPointerSize;
2536 }
2537 
ConstructStubFrameInfo(int translation_height,bool is_topmost,FrameInfoKind frame_info_kind)2538 ConstructStubFrameInfo::ConstructStubFrameInfo(int translation_height,
2539                                                bool is_topmost,
2540                                                FrameInfoKind frame_info_kind) {
2541   // Note: This is according to the Translation's notion of 'parameters' which
2542   // differs to that of the SharedFunctionInfo, e.g. by including the receiver.
2543   const int parameters_count = translation_height;
2544 
2545   // If the construct frame appears to be topmost we should ensure that the
2546   // value of result register is preserved during continuation execution.
2547   // We do this here by "pushing" the result of the constructor function to
2548   // the top of the reconstructed stack and popping it in
2549   // {Builtin::kNotifyDeoptimized}.
2550 
2551   static constexpr int kTopOfStackPadding = TopOfStackRegisterPaddingSlots();
2552   static constexpr int kTheResult = 1;
2553   const int argument_padding = ArgumentPaddingSlots(parameters_count);
2554 
2555   const int adjusted_height =
2556       (is_topmost || frame_info_kind == FrameInfoKind::kConservative)
2557           ? parameters_count + argument_padding + kTheResult +
2558                 kTopOfStackPadding
2559           : parameters_count + argument_padding;
2560   frame_size_in_bytes_without_fixed_ = adjusted_height * kSystemPointerSize;
2561   frame_size_in_bytes_ = frame_size_in_bytes_without_fixed_ +
2562                          ConstructFrameConstants::kFixedFrameSize;
2563 }
2564 
BuiltinContinuationFrameInfo(int translation_height,const CallInterfaceDescriptor & continuation_descriptor,const RegisterConfiguration * register_config,bool is_topmost,DeoptimizeKind deopt_kind,BuiltinContinuationMode continuation_mode,FrameInfoKind frame_info_kind)2565 BuiltinContinuationFrameInfo::BuiltinContinuationFrameInfo(
2566     int translation_height,
2567     const CallInterfaceDescriptor& continuation_descriptor,
2568     const RegisterConfiguration* register_config, bool is_topmost,
2569     DeoptimizeKind deopt_kind, BuiltinContinuationMode continuation_mode,
2570     FrameInfoKind frame_info_kind) {
2571   const bool is_conservative = frame_info_kind == FrameInfoKind::kConservative;
2572 
2573   // Note: This is according to the Translation's notion of 'parameters' which
2574   // differs to that of the SharedFunctionInfo, e.g. by including the receiver.
2575   const int parameters_count = translation_height;
2576   frame_has_result_stack_slot_ =
2577       !is_topmost || deopt_kind == DeoptimizeKind::kLazy;
2578   const int result_slot_count =
2579       (frame_has_result_stack_slot_ || is_conservative) ? 1 : 0;
2580 
2581   const int exception_slot_count =
2582       (BuiltinContinuationModeIsWithCatch(continuation_mode) || is_conservative)
2583           ? 1
2584           : 0;
2585 
2586   const int allocatable_register_count =
2587       register_config->num_allocatable_general_registers();
2588   const int padding_slot_count =
2589       BuiltinContinuationFrameConstants::PaddingSlotCount(
2590           allocatable_register_count);
2591 
2592   const int register_parameter_count =
2593       continuation_descriptor.GetRegisterParameterCount();
2594   translated_stack_parameter_count_ =
2595       parameters_count - register_parameter_count;
2596   stack_parameter_count_ = translated_stack_parameter_count_ +
2597                            result_slot_count + exception_slot_count;
2598   const int stack_param_pad_count =
2599       ArgumentPaddingSlots(stack_parameter_count_);
2600 
2601   // If the builtins frame appears to be topmost we should ensure that the
2602   // value of result register is preserved during continuation execution.
2603   // We do this here by "pushing" the result of callback function to the
2604   // top of the reconstructed stack and popping it in
2605   // {Builtin::kNotifyDeoptimized}.
2606   static constexpr int kTopOfStackPadding = TopOfStackRegisterPaddingSlots();
2607   static constexpr int kTheResult = 1;
2608   const int push_result_count =
2609       (is_topmost || is_conservative) ? kTheResult + kTopOfStackPadding : 0;
2610 
2611   frame_size_in_bytes_ =
2612       kSystemPointerSize * (stack_parameter_count_ + stack_param_pad_count +
2613                             allocatable_register_count + padding_slot_count +
2614                             push_result_count) +
2615       BuiltinContinuationFrameConstants::kFixedFrameSize;
2616 
2617   frame_size_in_bytes_above_fp_ =
2618       kSystemPointerSize * (allocatable_register_count + padding_slot_count +
2619                             push_result_count) +
2620       (BuiltinContinuationFrameConstants::kFixedFrameSize -
2621        BuiltinContinuationFrameConstants::kFixedFrameSizeAboveFp);
2622 }
2623 
2624 }  // namespace internal
2625 }  // namespace v8
2626