11cb0ef41Sopenharmony_ci// Copyright 2014 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#ifndef V8_COMPILER_FRAME_H_
61cb0ef41Sopenharmony_ci#define V8_COMPILER_FRAME_H_
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci#include "src/base/bits.h"
91cb0ef41Sopenharmony_ci#include "src/codegen/aligned-slot-allocator.h"
101cb0ef41Sopenharmony_ci#include "src/execution/frame-constants.h"
111cb0ef41Sopenharmony_ci#include "src/utils/bit-vector.h"
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_cinamespace v8 {
141cb0ef41Sopenharmony_cinamespace internal {
151cb0ef41Sopenharmony_cinamespace compiler {
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ciclass CallDescriptor;
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ci// Collects the spill slot and other frame slot requirements for a compiled
201cb0ef41Sopenharmony_ci// function. Frames are usually populated by the register allocator and are used
211cb0ef41Sopenharmony_ci// by Linkage to generate code for the prologue and epilogue to compiled
221cb0ef41Sopenharmony_ci// code. Frame objects must be considered immutable once they've been
231cb0ef41Sopenharmony_ci// instantiated and the basic information about the frame has been collected
241cb0ef41Sopenharmony_ci// into them. Mutable state associated with the frame is stored separately in
251cb0ef41Sopenharmony_ci// FrameAccessState.
261cb0ef41Sopenharmony_ci//
271cb0ef41Sopenharmony_ci// Frames are divided up into four regions.
281cb0ef41Sopenharmony_ci// - The first is the fixed header, which always has a constant size and can be
291cb0ef41Sopenharmony_ci//   predicted before code generation begins depending on the type of code being
301cb0ef41Sopenharmony_ci//   generated.
311cb0ef41Sopenharmony_ci// - The second is the region for spill slots, which is immediately below the
321cb0ef41Sopenharmony_ci//   fixed header and grows as the register allocator needs to spill to the
331cb0ef41Sopenharmony_ci//   stack and asks the frame for more space.
341cb0ef41Sopenharmony_ci// - The third region, which contains the callee-saved registers must be
351cb0ef41Sopenharmony_ci//   reserved after register allocation, since its size can only be precisely
361cb0ef41Sopenharmony_ci//   determined after register allocation once the number of used callee-saved
371cb0ef41Sopenharmony_ci//   register is certain.
381cb0ef41Sopenharmony_ci// - The fourth region is a scratch area for return values from other functions
391cb0ef41Sopenharmony_ci//   called, if multiple returns cannot all be passed in registers. This region
401cb0ef41Sopenharmony_ci//   Must be last in a stack frame, so that it is positioned immediately below
411cb0ef41Sopenharmony_ci//   the stack frame of a callee to store to.
421cb0ef41Sopenharmony_ci//
431cb0ef41Sopenharmony_ci// The frame region immediately below the fixed header contains spill slots
441cb0ef41Sopenharmony_ci// starting at slot 4 for JSFunctions.  The callee-saved frame region below that
451cb0ef41Sopenharmony_ci// starts at 4+spill_slot_count_.  Callee stack slots correspond to
461cb0ef41Sopenharmony_ci// parameters that are accessible through negative slot ids.
471cb0ef41Sopenharmony_ci//
481cb0ef41Sopenharmony_ci// Every slot of a caller or callee frame is accessible by the register
491cb0ef41Sopenharmony_ci// allocator and gap resolver with a SpillSlotOperand containing its
501cb0ef41Sopenharmony_ci// corresponding slot id.
511cb0ef41Sopenharmony_ci//
521cb0ef41Sopenharmony_ci// Below an example JSFunction Frame with slot ids, frame regions and contents:
531cb0ef41Sopenharmony_ci//
541cb0ef41Sopenharmony_ci//  slot      JS frame
551cb0ef41Sopenharmony_ci//       +-----------------+--------------------------------
561cb0ef41Sopenharmony_ci//  -n-1 |  parameter n    |                            ^
571cb0ef41Sopenharmony_ci//       |- - - - - - - - -|                            |
581cb0ef41Sopenharmony_ci//  -n   |  parameter n-1  |                          Caller
591cb0ef41Sopenharmony_ci//  ...  |       ...       |                       frame slots
601cb0ef41Sopenharmony_ci//  -2   |  parameter 1    |                       (slot < 0)
611cb0ef41Sopenharmony_ci//       |- - - - - - - - -|                            |
621cb0ef41Sopenharmony_ci//  -1   |  parameter 0    |                            v
631cb0ef41Sopenharmony_ci//  -----+-----------------+--------------------------------
641cb0ef41Sopenharmony_ci//   0   |   return addr   |   ^                        ^
651cb0ef41Sopenharmony_ci//       |- - - - - - - - -|   |                        |
661cb0ef41Sopenharmony_ci//   1   | saved frame ptr | Fixed                      |
671cb0ef41Sopenharmony_ci//       |- - - - - - - - -| Header <-- frame ptr       |
681cb0ef41Sopenharmony_ci//   2   |Context/Frm. Type|   |                        |
691cb0ef41Sopenharmony_ci//       |- - - - - - - - -|   |                        |
701cb0ef41Sopenharmony_ci//   3   |   [JSFunction]  |   v                        |
711cb0ef41Sopenharmony_ci//       +-----------------+----                        |
721cb0ef41Sopenharmony_ci//   4   |    spill 1      |   ^                      Callee
731cb0ef41Sopenharmony_ci//       |- - - - - - - - -|   |                   frame slots
741cb0ef41Sopenharmony_ci//  ...  |      ...        | Spill slots           (slot >= 0)
751cb0ef41Sopenharmony_ci//       |- - - - - - - - -|   |                        |
761cb0ef41Sopenharmony_ci//  m+3  |    spill m      |   v                        |
771cb0ef41Sopenharmony_ci//       +-----------------+----                        |
781cb0ef41Sopenharmony_ci//  m+4  |  callee-saved 1 |   ^                        |
791cb0ef41Sopenharmony_ci//       |- - - - - - - - -|   |                        |
801cb0ef41Sopenharmony_ci//       |      ...        | Callee-saved               |
811cb0ef41Sopenharmony_ci//       |- - - - - - - - -|   |                        |
821cb0ef41Sopenharmony_ci// m+r+3 |  callee-saved r |   v                        |
831cb0ef41Sopenharmony_ci//       +-----------------+----                        |
841cb0ef41Sopenharmony_ci// m+r+4 |    return 0     |   ^                        |
851cb0ef41Sopenharmony_ci//       |- - - - - - - - -|   |                        |
861cb0ef41Sopenharmony_ci//       |      ...        | Return                     |
871cb0ef41Sopenharmony_ci//       |- - - - - - - - -|   |                        |
881cb0ef41Sopenharmony_ci//       |    return q-1   |   v                        v
891cb0ef41Sopenharmony_ci//  -----+-----------------+----- <-- stack ptr -------------
901cb0ef41Sopenharmony_ci//
911cb0ef41Sopenharmony_ciclass V8_EXPORT_PRIVATE Frame : public ZoneObject {
921cb0ef41Sopenharmony_ci public:
931cb0ef41Sopenharmony_ci  explicit Frame(int fixed_frame_size_in_slots);
941cb0ef41Sopenharmony_ci  Frame(const Frame&) = delete;
951cb0ef41Sopenharmony_ci  Frame& operator=(const Frame&) = delete;
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_ci  inline int GetTotalFrameSlotCount() const {
981cb0ef41Sopenharmony_ci    return slot_allocator_.Size() + return_slot_count_;
991cb0ef41Sopenharmony_ci  }
1001cb0ef41Sopenharmony_ci  inline int GetFixedSlotCount() const { return fixed_slot_count_; }
1011cb0ef41Sopenharmony_ci  inline int GetSpillSlotCount() const { return spill_slot_count_; }
1021cb0ef41Sopenharmony_ci  inline int GetReturnSlotCount() const { return return_slot_count_; }
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci  void SetAllocatedRegisters(BitVector* regs) {
1051cb0ef41Sopenharmony_ci    DCHECK_NULL(allocated_registers_);
1061cb0ef41Sopenharmony_ci    allocated_registers_ = regs;
1071cb0ef41Sopenharmony_ci  }
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ci  void SetAllocatedDoubleRegisters(BitVector* regs) {
1101cb0ef41Sopenharmony_ci    DCHECK_NULL(allocated_double_registers_);
1111cb0ef41Sopenharmony_ci    allocated_double_registers_ = regs;
1121cb0ef41Sopenharmony_ci  }
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_ci  bool DidAllocateDoubleRegisters() const {
1151cb0ef41Sopenharmony_ci    return !allocated_double_registers_->IsEmpty();
1161cb0ef41Sopenharmony_ci  }
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci  void AlignSavedCalleeRegisterSlots(int alignment = kDoubleSize) {
1191cb0ef41Sopenharmony_ci    DCHECK(!frame_aligned_);
1201cb0ef41Sopenharmony_ci#if DEBUG
1211cb0ef41Sopenharmony_ci    spill_slots_finished_ = true;
1221cb0ef41Sopenharmony_ci#endif
1231cb0ef41Sopenharmony_ci    DCHECK(base::bits::IsPowerOfTwo(alignment));
1241cb0ef41Sopenharmony_ci    DCHECK_LE(alignment, kSimd128Size);
1251cb0ef41Sopenharmony_ci    int alignment_in_slots = AlignedSlotAllocator::NumSlotsForWidth(alignment);
1261cb0ef41Sopenharmony_ci    int padding = slot_allocator_.Align(alignment_in_slots);
1271cb0ef41Sopenharmony_ci    spill_slot_count_ += padding;
1281cb0ef41Sopenharmony_ci  }
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_ci  void AllocateSavedCalleeRegisterSlots(int count) {
1311cb0ef41Sopenharmony_ci    DCHECK(!frame_aligned_);
1321cb0ef41Sopenharmony_ci#if DEBUG
1331cb0ef41Sopenharmony_ci    spill_slots_finished_ = true;
1341cb0ef41Sopenharmony_ci#endif
1351cb0ef41Sopenharmony_ci    slot_allocator_.AllocateUnaligned(count);
1361cb0ef41Sopenharmony_ci  }
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_ci  int AllocateSpillSlot(int width, int alignment = 0) {
1391cb0ef41Sopenharmony_ci    DCHECK_EQ(GetTotalFrameSlotCount(),
1401cb0ef41Sopenharmony_ci              fixed_slot_count_ + spill_slot_count_ + return_slot_count_);
1411cb0ef41Sopenharmony_ci    // Never allocate spill slots after the callee-saved slots are defined.
1421cb0ef41Sopenharmony_ci    DCHECK(!spill_slots_finished_);
1431cb0ef41Sopenharmony_ci    DCHECK(!frame_aligned_);
1441cb0ef41Sopenharmony_ci    int actual_width = std::max({width, AlignedSlotAllocator::kSlotSize});
1451cb0ef41Sopenharmony_ci    int actual_alignment =
1461cb0ef41Sopenharmony_ci        std::max({alignment, AlignedSlotAllocator::kSlotSize});
1471cb0ef41Sopenharmony_ci    int slots = AlignedSlotAllocator::NumSlotsForWidth(actual_width);
1481cb0ef41Sopenharmony_ci    int old_end = slot_allocator_.Size();
1491cb0ef41Sopenharmony_ci    int slot;
1501cb0ef41Sopenharmony_ci    if (actual_width == actual_alignment) {
1511cb0ef41Sopenharmony_ci      // Simple allocation, alignment equal to width.
1521cb0ef41Sopenharmony_ci      slot = slot_allocator_.Allocate(slots);
1531cb0ef41Sopenharmony_ci    } else {
1541cb0ef41Sopenharmony_ci      // Complex allocation, alignment different from width.
1551cb0ef41Sopenharmony_ci      if (actual_alignment > AlignedSlotAllocator::kSlotSize) {
1561cb0ef41Sopenharmony_ci        // Alignment required.
1571cb0ef41Sopenharmony_ci        int alignment_in_slots =
1581cb0ef41Sopenharmony_ci            AlignedSlotAllocator::NumSlotsForWidth(actual_alignment);
1591cb0ef41Sopenharmony_ci        slot_allocator_.Align(alignment_in_slots);
1601cb0ef41Sopenharmony_ci      }
1611cb0ef41Sopenharmony_ci      slot = slot_allocator_.AllocateUnaligned(slots);
1621cb0ef41Sopenharmony_ci    }
1631cb0ef41Sopenharmony_ci    int end = slot_allocator_.Size();
1641cb0ef41Sopenharmony_ci
1651cb0ef41Sopenharmony_ci    spill_slot_count_ += end - old_end;
1661cb0ef41Sopenharmony_ci    return slot + slots - 1;
1671cb0ef41Sopenharmony_ci  }
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci  void EnsureReturnSlots(int count) {
1701cb0ef41Sopenharmony_ci    DCHECK(!frame_aligned_);
1711cb0ef41Sopenharmony_ci    return_slot_count_ = std::max(return_slot_count_, count);
1721cb0ef41Sopenharmony_ci  }
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci  void AlignFrame(int alignment = kDoubleSize);
1751cb0ef41Sopenharmony_ci
1761cb0ef41Sopenharmony_ci  int ReserveSpillSlots(size_t slot_count) {
1771cb0ef41Sopenharmony_ci    DCHECK_EQ(0, spill_slot_count_);
1781cb0ef41Sopenharmony_ci    DCHECK(!frame_aligned_);
1791cb0ef41Sopenharmony_ci    spill_slot_count_ += static_cast<int>(slot_count);
1801cb0ef41Sopenharmony_ci    slot_allocator_.AllocateUnaligned(static_cast<int>(slot_count));
1811cb0ef41Sopenharmony_ci    return slot_allocator_.Size() - 1;
1821cb0ef41Sopenharmony_ci  }
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ci private:
1851cb0ef41Sopenharmony_ci  int fixed_slot_count_;
1861cb0ef41Sopenharmony_ci  int spill_slot_count_ = 0;
1871cb0ef41Sopenharmony_ci  // Account for return slots separately. Conceptually, they follow all
1881cb0ef41Sopenharmony_ci  // allocated spill slots.
1891cb0ef41Sopenharmony_ci  int return_slot_count_ = 0;
1901cb0ef41Sopenharmony_ci  AlignedSlotAllocator slot_allocator_;
1911cb0ef41Sopenharmony_ci  BitVector* allocated_registers_;
1921cb0ef41Sopenharmony_ci  BitVector* allocated_double_registers_;
1931cb0ef41Sopenharmony_ci#if DEBUG
1941cb0ef41Sopenharmony_ci  bool spill_slots_finished_ = false;
1951cb0ef41Sopenharmony_ci  bool frame_aligned_ = false;
1961cb0ef41Sopenharmony_ci#endif
1971cb0ef41Sopenharmony_ci};
1981cb0ef41Sopenharmony_ci
1991cb0ef41Sopenharmony_ci// Represents an offset from either the stack pointer or frame pointer.
2001cb0ef41Sopenharmony_ciclass FrameOffset {
2011cb0ef41Sopenharmony_ci public:
2021cb0ef41Sopenharmony_ci  inline bool from_stack_pointer() { return (offset_ & 1) == kFromSp; }
2031cb0ef41Sopenharmony_ci  inline bool from_frame_pointer() { return (offset_ & 1) == kFromFp; }
2041cb0ef41Sopenharmony_ci  inline int offset() { return offset_ & ~1; }
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ci  inline static FrameOffset FromStackPointer(int offset) {
2071cb0ef41Sopenharmony_ci    DCHECK_EQ(0, offset & 1);
2081cb0ef41Sopenharmony_ci    return FrameOffset(offset | kFromSp);
2091cb0ef41Sopenharmony_ci  }
2101cb0ef41Sopenharmony_ci
2111cb0ef41Sopenharmony_ci  inline static FrameOffset FromFramePointer(int offset) {
2121cb0ef41Sopenharmony_ci    DCHECK_EQ(0, offset & 1);
2131cb0ef41Sopenharmony_ci    return FrameOffset(offset | kFromFp);
2141cb0ef41Sopenharmony_ci  }
2151cb0ef41Sopenharmony_ci
2161cb0ef41Sopenharmony_ci private:
2171cb0ef41Sopenharmony_ci  explicit FrameOffset(int offset) : offset_(offset) {}
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_ci  int offset_;  // Encodes SP or FP in the low order bit.
2201cb0ef41Sopenharmony_ci
2211cb0ef41Sopenharmony_ci  static const int kFromSp = 1;
2221cb0ef41Sopenharmony_ci  static const int kFromFp = 0;
2231cb0ef41Sopenharmony_ci};
2241cb0ef41Sopenharmony_ci
2251cb0ef41Sopenharmony_ci// Encapsulates the mutable state maintained during code generation about the
2261cb0ef41Sopenharmony_ci// current function's frame.
2271cb0ef41Sopenharmony_ciclass FrameAccessState : public ZoneObject {
2281cb0ef41Sopenharmony_ci public:
2291cb0ef41Sopenharmony_ci  explicit FrameAccessState(const Frame* const frame)
2301cb0ef41Sopenharmony_ci      : frame_(frame),
2311cb0ef41Sopenharmony_ci        access_frame_with_fp_(false),
2321cb0ef41Sopenharmony_ci        sp_delta_(0),
2331cb0ef41Sopenharmony_ci        has_frame_(false) {}
2341cb0ef41Sopenharmony_ci
2351cb0ef41Sopenharmony_ci  const Frame* frame() const { return frame_; }
2361cb0ef41Sopenharmony_ci  V8_EXPORT_PRIVATE void MarkHasFrame(bool state);
2371cb0ef41Sopenharmony_ci
2381cb0ef41Sopenharmony_ci  int sp_delta() const { return sp_delta_; }
2391cb0ef41Sopenharmony_ci  void ClearSPDelta() { sp_delta_ = 0; }
2401cb0ef41Sopenharmony_ci  void IncreaseSPDelta(int amount) { sp_delta_ += amount; }
2411cb0ef41Sopenharmony_ci
2421cb0ef41Sopenharmony_ci  bool access_frame_with_fp() const { return access_frame_with_fp_; }
2431cb0ef41Sopenharmony_ci
2441cb0ef41Sopenharmony_ci  // Regardless of how we access slots on the stack - using sp or fp - do we
2451cb0ef41Sopenharmony_ci  // have a frame, at the current stage in code generation.
2461cb0ef41Sopenharmony_ci  bool has_frame() const { return has_frame_; }
2471cb0ef41Sopenharmony_ci
2481cb0ef41Sopenharmony_ci  void SetFrameAccessToDefault();
2491cb0ef41Sopenharmony_ci  void SetFrameAccessToFP() { access_frame_with_fp_ = true; }
2501cb0ef41Sopenharmony_ci  void SetFrameAccessToSP() { access_frame_with_fp_ = false; }
2511cb0ef41Sopenharmony_ci
2521cb0ef41Sopenharmony_ci  int GetSPToFPSlotCount() const {
2531cb0ef41Sopenharmony_ci    int frame_slot_count =
2541cb0ef41Sopenharmony_ci        (has_frame() ? frame()->GetTotalFrameSlotCount() : kElidedFrameSlots) -
2551cb0ef41Sopenharmony_ci        StandardFrameConstants::kFixedSlotCountAboveFp;
2561cb0ef41Sopenharmony_ci    return frame_slot_count + sp_delta();
2571cb0ef41Sopenharmony_ci  }
2581cb0ef41Sopenharmony_ci  int GetSPToFPOffset() const {
2591cb0ef41Sopenharmony_ci    return GetSPToFPSlotCount() * kSystemPointerSize;
2601cb0ef41Sopenharmony_ci  }
2611cb0ef41Sopenharmony_ci
2621cb0ef41Sopenharmony_ci  // Get the frame offset for a given spill slot. The location depends on the
2631cb0ef41Sopenharmony_ci  // calling convention and the specific frame layout, and may thus be
2641cb0ef41Sopenharmony_ci  // architecture-specific. Negative spill slots indicate arguments on the
2651cb0ef41Sopenharmony_ci  // caller's frame.
2661cb0ef41Sopenharmony_ci  FrameOffset GetFrameOffset(int spill_slot) const;
2671cb0ef41Sopenharmony_ci
2681cb0ef41Sopenharmony_ci private:
2691cb0ef41Sopenharmony_ci  const Frame* const frame_;
2701cb0ef41Sopenharmony_ci  bool access_frame_with_fp_;
2711cb0ef41Sopenharmony_ci  int sp_delta_;
2721cb0ef41Sopenharmony_ci  bool has_frame_;
2731cb0ef41Sopenharmony_ci};
2741cb0ef41Sopenharmony_ci}  // namespace compiler
2751cb0ef41Sopenharmony_ci}  // namespace internal
2761cb0ef41Sopenharmony_ci}  // namespace v8
2771cb0ef41Sopenharmony_ci
2781cb0ef41Sopenharmony_ci#endif  // V8_COMPILER_FRAME_H_
279