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