xref: /third_party/node/deps/v8/src/execution/frames.cc (revision 1cb0ef41)
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
37namespace v8 {
38namespace internal {
39
40ReturnAddressLocationResolver StackFrame::return_address_location_resolver_ =
41    nullptr;
42
43namespace {
44
45Address 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.
62class StackHandlerIterator {
63 public:
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
82  StackHandler* handler() const { return handler_; }
83
84  bool done() { return handler_ == nullptr || AddressOf(handler_) > limit_; }
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),
98StackFrameIteratorBase::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
106StackFrameIterator::StackFrameIterator(Isolate* isolate)
107    : StackFrameIterator(isolate, isolate->thread_local_top()) {}
108
109StackFrameIterator::StackFrameIterator(Isolate* isolate, ThreadLocalTop* t)
110    : StackFrameIteratorBase(isolate, true) {
111  Reset(t);
112}
113#if V8_ENABLE_WEBASSEMBLY
114StackFrameIterator::StackFrameIterator(Isolate* isolate,
115                                       wasm::StackMemory* stack)
116    : StackFrameIteratorBase(isolate, true) {
117  Reset(isolate->thread_local_top(), stack);
118}
119#endif
120
121void 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
149StackFrame* StackFrameIterator::Reframe() {
150  StackFrame::Type type = frame_->ComputeType(this, &frame_->state_);
151  frame_ = SingletonFor(type, &frame_->state_);
152  return frame();
153}
154
155void 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
164void 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
177StackFrame* 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
185StackFrame* 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
204void TypedFrameWithJSLinkage::Iterate(RootVisitor* v) const {
205  IterateExpressions(v);
206  IteratePc(v, pc_address(), constant_pool_address(), LookupCode());
207}
208
209// -------------------------------------------------------------------------
210
211void JavaScriptFrameIterator::Advance() {
212  do {
213    iterator_.Advance();
214  } while (!iterator_.done() && !iterator_.frame()->is_java_script());
215}
216
217// -------------------------------------------------------------------------
218
219StackTraceFrameIterator::StackTraceFrameIterator(Isolate* isolate)
220    : iterator_(isolate) {
221  if (!done() && !IsValidFrame(iterator_.frame())) Advance();
222}
223
224StackTraceFrameIterator::StackTraceFrameIterator(Isolate* isolate,
225                                                 StackFrameId id)
226    : StackTraceFrameIterator(isolate) {
227  while (!done() && frame()->id() != id) Advance();
228}
229
230void StackTraceFrameIterator::Advance() {
231  do {
232    iterator_.Advance();
233  } while (!done() && !IsValidFrame(iterator_.frame()));
234}
235
236int 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
244FrameSummary 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
264bool 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
275bool StackTraceFrameIterator::IsValidJSFunction(JSFunction f) {
276  if (!f.IsJSFunction()) return false;
277  return f.shared().IsSubjectToDebugging();
278}
279
280// -------------------------------------------------------------------------
281
282namespace {
283
284bool 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
319bool 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
350SafeStackFrameIterator::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
459bool 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
469void 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
492bool SafeStackFrameIterator::IsValidFrame(StackFrame* frame) const {
493  return IsValidStackAddress(frame->sp()) && IsValidStackAddress(frame->fp());
494}
495
496bool 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
511bool 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
521void 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
560namespace {
561Code GetContainingCode(Isolate* isolate, Address pc) {
562  return isolate->inner_pointer_to_code_cache()->GetCacheEntry(pc)->code;
563}
564}  // namespace
565
566Code 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
573void 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
591void StackFrame::SetReturnAddressLocationResolver(
592    ReturnAddressLocationResolver resolver) {
593  DCHECK_NULL(return_address_location_resolver_);
594  return_address_location_resolver_ = resolver;
595}
596
597StackFrame::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
737bool StackFrame::can_access_heap_objects() const {
738  return iterator_->can_access_heap_objects_;
739}
740#endif
741
742StackFrame::Type StackFrame::GetCallerState(State* state) const {
743  ComputeCallerState(state);
744  return ComputeType(iterator_, state);
745}
746
747Address CommonFrame::GetCallerStackPointer() const {
748  return fp() + CommonFrameConstants::kCallerSPOffset;
749}
750
751void 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
760Code EntryFrame::unchecked_code() const {
761  return FromCodeT(isolate()->builtins()->code(Builtin::kJSEntry));
762}
763
764void EntryFrame::ComputeCallerState(State* state) const {
765  GetCallerState(state);
766}
767
768StackFrame::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
775StackFrame::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
782Code ConstructEntryFrame::unchecked_code() const {
783  return FromCodeT(isolate()->builtins()->code(Builtin::kJSConstructEntry));
784}
785
786void 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
799void 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
805StackFrame::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
819StackFrame::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
844Address 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
851Address 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
861void 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
874void 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
886JSFunction BuiltinExitFrame::function() const {
887  return JSFunction::cast(target_slot_object());
888}
889
890Object BuiltinExitFrame::receiver() const { return receiver_slot_object(); }
891
892Object 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
899int 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
909Handle<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
921bool BuiltinExitFrame::IsConstructor() const {
922  return !new_target_slot_object().IsUndefined(isolate());
923}
924
925namespace {
926void PrintIndex(StringStream* accumulator, StackFrame::PrintMode mode,
927                int index) {
928  accumulator->Add((mode == StackFrame::OVERVIEW) ? "%5d: " : "[%d]: ", index);
929}
930
931const 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
944void 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
952void 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
976Address CommonFrame::GetExpressionAddress(int n) const {
977  const int offset = StandardFrameConstants::kExpressionsOffset;
978  return fp() + offset - n * kSystemPointerSize;
979}
980
981Address UnoptimizedFrame::GetExpressionAddress(int n) const {
982  const int offset = UnoptimizedFrameConstants::kExpressionsOffset;
983  return fp() + offset - n * kSystemPointerSize;
984}
985
986Object CommonFrame::context() const {
987  return ReadOnlyRoots(isolate()).undefined_value();
988}
989
990int 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
996int 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
1004void 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
1023void CommonFrame::Summarize(std::vector<FrameSummary>* functions) const {
1024  // This should only be called on frames which override this method.
1025  UNREACHABLE();
1026}
1027
1028void 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
1274Code StubFrame::unchecked_code() const {
1275  return isolate()->FindCodeObject(pc());
1276}
1277
1278int 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
1287void OptimizedFrame::Iterate(RootVisitor* v) const { IterateCompiledFrame(v); }
1288
1289void JavaScriptFrame::SetParameterValue(int index, Object value) const {
1290  Memory<Address>(GetParameterSlot(index)) = value.ptr();
1291}
1292
1293bool JavaScriptFrame::IsConstructor() const {
1294  return IsConstructFrame(caller_fp());
1295}
1296
1297bool JavaScriptFrame::HasInlinedFrames() const {
1298  std::vector<SharedFunctionInfo> functions;
1299  GetFunctions(&functions);
1300  return functions.size() > 1;
1301}
1302
1303Code CommonFrameWithJSLinkage::unchecked_code() const {
1304  return FromCodeT(function().code());
1305}
1306
1307int 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
1318Address JavaScriptFrame::GetCallerStackPointer() const {
1319  return fp() + StandardFrameConstants::kCallerSPOffset;
1320}
1321
1322void JavaScriptFrame::GetFunctions(
1323    std::vector<SharedFunctionInfo>* functions) const {
1324  DCHECK(functions->empty());
1325  functions->push_back(function().shared());
1326}
1327
1328void 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
1339bool CommonFrameWithJSLinkage::IsConstructor() const {
1340  return IsConstructFrame(caller_fp());
1341}
1342
1343void 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
1356JSFunction JavaScriptFrame::function() const {
1357  return JSFunction::cast(function_slot_object());
1358}
1359
1360Object 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
1369Object CommonFrameWithJSLinkage::receiver() const { return GetParameter(-1); }
1370
1371Object 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
1378Script JavaScriptFrame::script() const {
1379  return Script::cast(function().shared().script());
1380}
1381
1382int 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
1390void 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
1419void 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
1464void 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
1484Object CommonFrameWithJSLinkage::GetParameter(int index) const {
1485  return Object(Memory<Address>(GetParameterSlot(index)));
1486}
1487
1488int 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
1494int JavaScriptFrame::GetActualArgumentCount() const {
1495  return static_cast<int>(
1496             Memory<intptr_t>(fp() + StandardFrameConstants::kArgCOffset)) -
1497         kJSArgcReceiverSlots;
1498}
1499
1500Handle<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
1514JSFunction JavaScriptBuiltinContinuationFrame::function() const {
1515  const int offset = BuiltinContinuationFrameConstants::kFunctionOffset;
1516  return JSFunction::cast(Object(base::Memory<Address>(fp() + offset)));
1517}
1518
1519int 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
1529intptr_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
1536Object JavaScriptBuiltinContinuationFrame::context() const {
1537  return Object(Memory<Address>(
1538      fp() + BuiltinContinuationFrameConstants::kBuiltinContextOffset));
1539}
1540
1541void 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
1554FrameSummary::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
1569void FrameSummary::EnsureSourcePositionsAvailable() {
1570  if (IsJavaScript()) {
1571    java_script_summary_.EnsureSourcePositionsAvailable();
1572  }
1573}
1574
1575bool FrameSummary::AreSourcePositionsAvailable() const {
1576  if (IsJavaScript()) {
1577    return java_script_summary_.AreSourcePositionsAvailable();
1578  }
1579  return true;
1580}
1581
1582void FrameSummary::JavaScriptFrameSummary::EnsureSourcePositionsAvailable() {
1583  Handle<SharedFunctionInfo> shared(function()->shared(), isolate());
1584  SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate(), shared);
1585}
1586
1587bool FrameSummary::JavaScriptFrameSummary::AreSourcePositionsAvailable() const {
1588  return !FLAG_enable_lazy_source_positions || function()
1589                                                   ->shared()
1590                                                   .GetBytecodeArray(isolate())
1591                                                   .HasSourcePositionTable();
1592}
1593
1594bool FrameSummary::JavaScriptFrameSummary::is_subject_to_debugging() const {
1595  return function()->shared().IsSubjectToDebugging();
1596}
1597
1598int FrameSummary::JavaScriptFrameSummary::SourcePosition() const {
1599  return abstract_code()->SourcePosition(code_offset());
1600}
1601
1602int FrameSummary::JavaScriptFrameSummary::SourceStatementPosition() const {
1603  return abstract_code()->SourceStatementPosition(code_offset());
1604}
1605
1606Handle<Object> FrameSummary::JavaScriptFrameSummary::script() const {
1607  return handle(function_->shared().script(), isolate());
1608}
1609
1610Handle<Context> FrameSummary::JavaScriptFrameSummary::native_context() const {
1611  return handle(function_->native_context(), isolate());
1612}
1613
1614Handle<StackFrameInfo>
1615FrameSummary::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
1640FrameSummary::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
1649Handle<Object> FrameSummary::WasmFrameSummary::receiver() const {
1650  return wasm_instance_->GetIsolate()->global_proxy();
1651}
1652
1653uint32_t FrameSummary::WasmFrameSummary::function_index() const {
1654  return code()->index();
1655}
1656
1657int FrameSummary::WasmFrameSummary::byte_offset() const {
1658  return code_->GetSourcePositionBefore(code_offset());
1659}
1660
1661int 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
1667Handle<Script> FrameSummary::WasmFrameSummary::script() const {
1668  return handle(wasm_instance()->module_object().script(),
1669                wasm_instance()->GetIsolate());
1670}
1671
1672Handle<Context> FrameSummary::WasmFrameSummary::native_context() const {
1673  return handle(wasm_instance()->native_context(), isolate());
1674}
1675
1676Handle<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
1685FrameSummary::~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
1698FrameSummary 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
1705FrameSummary FrameSummary::GetBottom(const CommonFrame* frame) {
1706  return Get(frame, 0);
1707}
1708
1709FrameSummary 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
1716FrameSummary 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
1744FRAME_SUMMARY_DISPATCH(Handle<Object>, receiver)
1745FRAME_SUMMARY_DISPATCH(int, code_offset)
1746FRAME_SUMMARY_DISPATCH(bool, is_constructor)
1747FRAME_SUMMARY_DISPATCH(bool, is_subject_to_debugging)
1748FRAME_SUMMARY_DISPATCH(Handle<Object>, script)
1749FRAME_SUMMARY_DISPATCH(int, SourcePosition)
1750FRAME_SUMMARY_DISPATCH(int, SourceStatementPosition)
1751FRAME_SUMMARY_DISPATCH(Handle<Context>, native_context)
1752FRAME_SUMMARY_DISPATCH(Handle<StackFrameInfo>, CreateStackFrameInfo)
1753
1754#undef FRAME_SUMMARY_DISPATCH
1755
1756void 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
1837int 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
1858DeoptimizationData 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
1883void 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
1934int OptimizedFrame::StackSlotOffsetRelativeToFp(int slot_index) {
1935  return StandardFrameConstants::kCallerSPOffset -
1936         ((slot_index + 1) * kSystemPointerSize);
1937}
1938
1939Object OptimizedFrame::StackSlotAt(int index) const {
1940  return Object(Memory<Address>(fp() + StackSlotOffsetRelativeToFp(index)));
1941}
1942
1943int UnoptimizedFrame::position() const {
1944  AbstractCode code = AbstractCode::cast(GetBytecodeArray());
1945  int code_offset = GetBytecodeOffset();
1946  return code.SourcePosition(code_offset);
1947}
1948
1949int UnoptimizedFrame::LookupExceptionHandlerInTable(
1950    int* context_register, HandlerTable::CatchPrediction* prediction) {
1951  HandlerTable table(GetBytecodeArray());
1952  return table.LookupRange(GetBytecodeOffset(), context_register, prediction);
1953}
1954
1955BytecodeArray 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
1963Object 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
1971void 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
1982int 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
1992int 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
2003void 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
2012void 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
2020int BaselineFrame::GetBytecodeOffset() const {
2021  return LookupCode().GetBytecodeOffsetForBaselinePC(this->pc(),
2022                                                     GetBytecodeArray());
2023}
2024
2025intptr_t BaselineFrame::GetPCForBytecodeOffset(int bytecode_offset) const {
2026  return LookupCode().GetBaselineStartPCForBytecodeOffset(bytecode_offset,
2027                                                          GetBytecodeArray());
2028}
2029
2030void BaselineFrame::PatchContext(Context value) {
2031  base::Memory<Address>(fp() + BaselineFrameConstants::kContextOffset) =
2032      value.ptr();
2033}
2034
2035JSFunction BuiltinFrame::function() const {
2036  const int offset = BuiltinFrameConstants::kFunctionOffset;
2037  return JSFunction::cast(Object(base::Memory<Address>(fp() + offset)));
2038}
2039
2040int 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
2047void 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
2077wasm::WasmCode* WasmFrame::wasm_code() const {
2078  return wasm::GetWasmCodeManager()->LookupCode(pc());
2079}
2080
2081WasmInstanceObject WasmFrame::wasm_instance() const {
2082  const int offset = WasmFrameConstants::kWasmInstanceOffset;
2083  Object instance(Memory<Address>(fp() + offset));
2084  return WasmInstanceObject::cast(instance);
2085}
2086
2087wasm::NativeModule* WasmFrame::native_module() const {
2088  return module_object().native_module();
2089}
2090
2091WasmModuleObject WasmFrame::module_object() const {
2092  return wasm_instance().module_object();
2093}
2094
2095int WasmFrame::function_index() const {
2096  wasm::WasmCodeRefScope code_ref_scope;
2097  return wasm_code()->index();
2098}
2099
2100Script WasmFrame::script() const { return module_object().script(); }
2101
2102int 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
2109int 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
2115bool WasmFrame::is_inspectable() const {
2116  wasm::WasmCodeRefScope code_ref_scope;
2117  return wasm_code()->is_inspectable();
2118}
2119
2120Object WasmFrame::context() const { return wasm_instance().native_context(); }
2121
2122void 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
2135bool 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
2151int 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
2161void 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
2180void 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
2187void 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
2222void 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
2239void 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
2247WasmInstanceObject WasmCompileLazyFrame::wasm_instance() const {
2248  return WasmInstanceObject::cast(*wasm_instance_slot());
2249}
2250
2251FullObjectSlot WasmCompileLazyFrame::wasm_instance_slot() const {
2252  const int offset = WasmCompileLazyFrameConstants::kWasmInstanceOffset;
2253  return FullObjectSlot(&Memory<Address>(fp() + offset));
2254}
2255
2256void 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
2265namespace {
2266
2267void 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
2280void 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
2394void EntryFrame::Iterate(RootVisitor* v) const {
2395  IteratePc(v, pc_address(), constant_pool_address(), LookupCode());
2396}
2397
2398void 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
2416void JavaScriptFrame::Iterate(RootVisitor* v) const {
2417  IterateExpressions(v);
2418  IteratePc(v, pc_address(), constant_pool_address(), LookupCode());
2419}
2420
2421void 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
2435namespace {
2436
2437// Predictably converts PC to uint32 by calculating offset of the PC in
2438// from the embedded builtins start or from respective MemoryChunk.
2439uint32_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
2450InnerPointerToCodeCache::InnerPointerToCodeCacheEntry*
2451InnerPointerToCodeCache::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
2478namespace {
2479
2480// Some architectures need to push padding together with the TOS register
2481// in order to maintain stack alignment.
2482constexpr int TopOfStackRegisterPaddingSlots() {
2483  return ArgumentPaddingSlots(1);
2484}
2485
2486bool 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
2500UnoptimizedFrameInfo::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
2532uint32_t UnoptimizedFrameInfo::GetStackSizeForAdditionalArguments(
2533    int parameters_count) {
2534  return (parameters_count + ArgumentPaddingSlots(parameters_count)) *
2535         kSystemPointerSize;
2536}
2537
2538ConstructStubFrameInfo::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
2565BuiltinContinuationFrameInfo::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