blob: de2ae1a3c23f57c32c3430a7e274ab0187f2f01a [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2014 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#ifndef V8_COMPILER_FRAME_H_
6#define V8_COMPILER_FRAME_H_
7
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008#include "src/bit-vector.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009#include "src/frames.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010
11namespace v8 {
12namespace internal {
13namespace compiler {
14
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015class CallDescriptor;
16
17// Collects the spill slot and other frame slot requirements for a compiled
18// function. Frames are usually populated by the register allocator and are used
19// by Linkage to generate code for the prologue and epilogue to compiled
20// code. Frame objects must be considered immutable once they've been
21// instantiated and the basic information about the frame has been collected
22// into them. Mutable state associated with the frame is stored separately in
23// FrameAccessState.
24//
25// Frames are divided up into three regions.
26// - The first is the fixed header, which always has a constant size and can be
27// predicted before code generation begins depending on the type of code being
28// generated.
29// - The second is the region for spill slots, which is immediately below the
30// fixed header and grows as the register allocator needs to spill to the
31// stack and asks the frame for more space.
32// - The third region, which contains the callee-saved registers must be
33// reserved after register allocation, since its size can only be precisely
34// determined after register allocation once the number of used callee-saved
35// register is certain.
36//
Ben Murdoch097c5b22016-05-18 11:27:45 +010037// The frame region immediately below the fixed header contains spill slots
38// starting at slot 4 for JSFunctions. The callee-saved frame region below that
39// starts at 4+spill_slot_count_. Callee stack slots corresponding to
40// parameters are accessible through negative slot ids.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000041//
42// Every slot of a caller or callee frame is accessible by the register
43// allocator and gap resolver with a SpillSlotOperand containing its
44// corresponding slot id.
45//
46// Below an example JSFunction Frame with slot ids, frame regions and contents:
47//
48// slot JS frame
49// +-----------------+--------------------------------
50// -n-1 | parameter 0 | ^
51// |- - - - - - - - -| |
52// -n | | Caller
53// ... | ... | frame slots
54// -2 | parameter n-1 | (slot < 0)
55// |- - - - - - - - -| |
56// -1 | parameter n | v
57// -----+-----------------+--------------------------------
58// 0 | return addr | ^ ^
59// |- - - - - - - - -| | |
60// 1 | saved frame ptr | Fixed |
61// |- - - - - - - - -| Header <-- frame ptr |
Ben Murdochda12d292016-06-02 14:46:10 +010062// 2 |Context/Frm. Type| | |
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000063// |- - - - - - - - -| | |
Ben Murdochda12d292016-06-02 14:46:10 +010064// 3 | [JSFunction] | v |
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000065// +-----------------+---- |
66// 4 | spill 1 | ^ Callee
67// |- - - - - - - - -| | frame slots
68// ... | ... | Spill slots (slot >= 0)
69// |- - - - - - - - -| | |
Ben Murdoch097c5b22016-05-18 11:27:45 +010070// m+3 | spill m | v |
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000071// +-----------------+---- |
Ben Murdoch097c5b22016-05-18 11:27:45 +010072// m+4 | callee-saved 1 | ^ |
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000073// |- - - - - - - - -| | |
74// | ... | Callee-saved |
75// |- - - - - - - - -| | |
Ben Murdoch097c5b22016-05-18 11:27:45 +010076// m+r+3 | callee-saved r | v v
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000077// -----+-----------------+----- <-- stack ptr -------------
78//
Emily Bernierd0a1eb72015-03-24 16:35:39 -040079class Frame : public ZoneObject {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000080 public:
Ben Murdochc5610432016-08-08 18:44:38 +010081 explicit Frame(int fixed_frame_size_in_slots);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000082
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000083 inline int GetTotalFrameSlotCount() const { return frame_slot_count_; }
84
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000085 inline int GetSpillSlotCount() const { return spill_slot_count_; }
86
Ben Murdochb8a8cc12014-11-26 15:28:44 +000087 void SetAllocatedRegisters(BitVector* regs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000088 DCHECK(allocated_registers_ == nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000089 allocated_registers_ = regs;
90 }
91
92 void SetAllocatedDoubleRegisters(BitVector* regs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000093 DCHECK(allocated_double_registers_ == nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000094 allocated_double_registers_ = regs;
95 }
96
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000097 bool DidAllocateDoubleRegisters() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000098 return !allocated_double_registers_->IsEmpty();
99 }
100
Ben Murdochc5610432016-08-08 18:44:38 +0100101 void AlignSavedCalleeRegisterSlots(int alignment = kDoubleSize) {
Ben Murdochda12d292016-06-02 14:46:10 +0100102 int alignment_slots = alignment / kPointerSize;
103 int delta = alignment_slots - (frame_slot_count_ & (alignment_slots - 1));
104 if (delta != alignment_slots) {
105 frame_slot_count_ += delta;
106 }
Ben Murdochc5610432016-08-08 18:44:38 +0100107 spill_slot_count_ += delta;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000108 }
109
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000110 void AllocateSavedCalleeRegisterSlots(int count) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000111 frame_slot_count_ += count;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000112 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000113
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000114 int AllocateSpillSlot(int width) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000115 int frame_slot_count_before = frame_slot_count_;
116 int slot = AllocateAlignedFrameSlot(width);
117 spill_slot_count_ += (frame_slot_count_ - frame_slot_count_before);
118 return slot;
119 }
120
Ben Murdochda12d292016-06-02 14:46:10 +0100121 int AlignFrame(int alignment = kDoubleSize);
122
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000123 int ReserveSpillSlots(size_t slot_count) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000124 DCHECK_EQ(0, spill_slot_count_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000125 spill_slot_count_ += static_cast<int>(slot_count);
126 frame_slot_count_ += static_cast<int>(slot_count);
127 return frame_slot_count_ - 1;
128 }
129
130 static const int kContextSlot = 2 + StandardFrameConstants::kCPSlotCount;
131 static const int kJSFunctionSlot = 3 + StandardFrameConstants::kCPSlotCount;
132
133 private:
134 int AllocateAlignedFrameSlot(int width) {
135 DCHECK(width == 4 || width == 8);
136 // Skip one slot if necessary.
137 if (width > kPointerSize) {
138 DCHECK(width == kPointerSize * 2);
139 frame_slot_count_++;
140 frame_slot_count_ |= 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000141 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000142 return frame_slot_count_++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000143 }
144
145 private:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000146 int frame_slot_count_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000147 int spill_slot_count_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000148 BitVector* allocated_registers_;
149 BitVector* allocated_double_registers_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400150
151 DISALLOW_COPY_AND_ASSIGN(Frame);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000152};
153
154
155// Represents an offset from either the stack pointer or frame pointer.
156class FrameOffset {
157 public:
158 inline bool from_stack_pointer() { return (offset_ & 1) == kFromSp; }
159 inline bool from_frame_pointer() { return (offset_ & 1) == kFromFp; }
160 inline int offset() { return offset_ & ~1; }
161
162 inline static FrameOffset FromStackPointer(int offset) {
163 DCHECK((offset & 1) == 0);
164 return FrameOffset(offset | kFromSp);
165 }
166
167 inline static FrameOffset FromFramePointer(int offset) {
168 DCHECK((offset & 1) == 0);
169 return FrameOffset(offset | kFromFp);
170 }
171
172 private:
173 explicit FrameOffset(int offset) : offset_(offset) {}
174
175 int offset_; // Encodes SP or FP in the low order bit.
176
177 static const int kFromSp = 1;
178 static const int kFromFp = 0;
179};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000180
181// Encapsulates the mutable state maintained during code generation about the
182// current function's frame.
183class FrameAccessState : public ZoneObject {
184 public:
Ben Murdochc5610432016-08-08 18:44:38 +0100185 explicit FrameAccessState(const Frame* const frame)
Ben Murdochda12d292016-06-02 14:46:10 +0100186 : frame_(frame),
187 access_frame_with_fp_(false),
188 sp_delta_(0),
189 has_frame_(false) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000190
Ben Murdochc5610432016-08-08 18:44:38 +0100191 const Frame* frame() const { return frame_; }
Ben Murdochda12d292016-06-02 14:46:10 +0100192 void MarkHasFrame(bool state);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000193
194 int sp_delta() const { return sp_delta_; }
195 void ClearSPDelta() { sp_delta_ = 0; }
196 void IncreaseSPDelta(int amount) { sp_delta_ += amount; }
197
198 bool access_frame_with_fp() const { return access_frame_with_fp_; }
Ben Murdochda12d292016-06-02 14:46:10 +0100199
200 // Regardless of how we access slots on the stack - using sp or fp - do we
201 // have a frame, at the current stage in code generation.
202 bool has_frame() const { return has_frame_; }
203
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000204 void SetFrameAccessToDefault();
205 void SetFrameAccessToFP() { access_frame_with_fp_ = true; }
206 void SetFrameAccessToSP() { access_frame_with_fp_ = false; }
207
Ben Murdochda12d292016-06-02 14:46:10 +0100208 int GetSPToFPSlotCount() const {
209 int frame_slot_count =
210 (has_frame() ? frame()->GetTotalFrameSlotCount() : kElidedFrameSlots) -
211 StandardFrameConstants::kFixedSlotCountAboveFp;
212 return frame_slot_count + sp_delta();
213 }
214 int GetSPToFPOffset() const { return GetSPToFPSlotCount() * kPointerSize; }
215
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000216 // Get the frame offset for a given spill slot. The location depends on the
217 // calling convention and the specific frame layout, and may thus be
218 // architecture-specific. Negative spill slots indicate arguments on the
219 // caller's frame.
220 FrameOffset GetFrameOffset(int spill_slot) const;
221
222 private:
Ben Murdochc5610432016-08-08 18:44:38 +0100223 const Frame* const frame_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000224 bool access_frame_with_fp_;
225 int sp_delta_;
Ben Murdochda12d292016-06-02 14:46:10 +0100226 bool has_frame_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000227};
228} // namespace compiler
229} // namespace internal
230} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000231
232#endif // V8_COMPILER_FRAME_H_