blob: 72f756b0dcd8e9693e21b9a5bf88f7ef3132d27f [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//
37// Every pointer in a frame has a slot id. On 32-bit platforms, doubles consume
38// two slots.
39//
40// Stack slot indices >= 0 access the callee stack with slot 0 corresponding to
41// the callee's saved return address and 1 corresponding to the saved frame
42// pointer. Some frames have additional information stored in the fixed header,
43// for example JSFunctions store the function context and marker in the fixed
44// header, with slot index 2 corresponding to the current function context and 3
45// corresponding to the frame marker/JSFunction. The frame region immediately
46// below the fixed header contains spill slots starting at 4 for JsFunctions.
47// The callee-saved frame region below that starts at 4+spill_slot_count_.
48// Callee stack slots corresponding to parameters are accessible through
49// negative slot ids.
50//
51// Every slot of a caller or callee frame is accessible by the register
52// allocator and gap resolver with a SpillSlotOperand containing its
53// corresponding slot id.
54//
55// Below an example JSFunction Frame with slot ids, frame regions and contents:
56//
57// slot JS frame
58// +-----------------+--------------------------------
59// -n-1 | parameter 0 | ^
60// |- - - - - - - - -| |
61// -n | | Caller
62// ... | ... | frame slots
63// -2 | parameter n-1 | (slot < 0)
64// |- - - - - - - - -| |
65// -1 | parameter n | v
66// -----+-----------------+--------------------------------
67// 0 | return addr | ^ ^
68// |- - - - - - - - -| | |
69// 1 | saved frame ptr | Fixed |
70// |- - - - - - - - -| Header <-- frame ptr |
71// 2 | Context | | |
72// |- - - - - - - - -| | |
73// 3 |JSFunction/Marker| v |
74// +-----------------+---- |
75// 4 | spill 1 | ^ Callee
76// |- - - - - - - - -| | frame slots
77// ... | ... | Spill slots (slot >= 0)
78// |- - - - - - - - -| | |
79// m+4 | spill m | v |
80// +-----------------+---- |
81// m+5 | callee-saved 1 | ^ |
82// |- - - - - - - - -| | |
83// | ... | Callee-saved |
84// |- - - - - - - - -| | |
85// m+r+4 | callee-saved r | v v
86// -----+-----------------+----- <-- stack ptr -------------
87//
Emily Bernierd0a1eb72015-03-24 16:35:39 -040088class Frame : public ZoneObject {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000089 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000090 explicit Frame(int fixed_frame_size_in_slots,
91 const CallDescriptor* descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000092
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000093 static int FPOffsetToSlot(int frame_offset) {
94 return StandardFrameConstants::kFixedSlotCountAboveFp - 1 -
95 frame_offset / kPointerSize;
96 }
97
98 static int SlotToFPOffset(int slot) {
99 return (StandardFrameConstants::kFixedSlotCountAboveFp - 1 - slot) *
100 kPointerSize;
101 }
102
103 inline bool needs_frame() const { return needs_frame_; }
104 inline void MarkNeedsFrame() { needs_frame_ = true; }
105
106 inline int GetTotalFrameSlotCount() const { return frame_slot_count_; }
107
108 inline int GetSpToFpSlotCount() const {
109 return GetTotalFrameSlotCount() -
110 StandardFrameConstants::kFixedSlotCountAboveFp;
111 }
112 inline int GetSavedCalleeRegisterSlotCount() const {
113 return callee_saved_slot_count_;
114 }
115 inline int GetSpillSlotCount() const { return spill_slot_count_; }
116
117 inline void SetElidedFrameSizeInSlots(int slots) {
118 DCHECK_EQ(0, callee_saved_slot_count_);
119 DCHECK_EQ(0, spill_slot_count_);
120 frame_slot_count_ = slots;
121 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000122
123 void SetAllocatedRegisters(BitVector* regs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000124 DCHECK(allocated_registers_ == nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000125 allocated_registers_ = regs;
126 }
127
128 void SetAllocatedDoubleRegisters(BitVector* regs) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000129 DCHECK(allocated_double_registers_ == nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000130 allocated_double_registers_ = regs;
131 }
132
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000133 bool DidAllocateDoubleRegisters() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000134 return !allocated_double_registers_->IsEmpty();
135 }
136
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000137 int AlignSavedCalleeRegisterSlots() {
138 DCHECK_EQ(0, callee_saved_slot_count_);
139 needs_frame_ = true;
140 int delta = frame_slot_count_ & 1;
141 frame_slot_count_ += delta;
142 return delta;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000143 }
144
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000145 void AllocateSavedCalleeRegisterSlots(int count) {
146 needs_frame_ = true;
147 frame_slot_count_ += count;
148 callee_saved_slot_count_ += count;
149 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000150
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000151 int AllocateSpillSlot(int width) {
152 DCHECK_EQ(0, callee_saved_slot_count_);
153 needs_frame_ = true;
154 int frame_slot_count_before = frame_slot_count_;
155 int slot = AllocateAlignedFrameSlot(width);
156 spill_slot_count_ += (frame_slot_count_ - frame_slot_count_before);
157 return slot;
158 }
159
160 int ReserveSpillSlots(size_t slot_count) {
161 DCHECK_EQ(0, callee_saved_slot_count_);
162 DCHECK_EQ(0, spill_slot_count_);
163 needs_frame_ = true;
164 spill_slot_count_ += static_cast<int>(slot_count);
165 frame_slot_count_ += static_cast<int>(slot_count);
166 return frame_slot_count_ - 1;
167 }
168
169 static const int kContextSlot = 2 + StandardFrameConstants::kCPSlotCount;
170 static const int kJSFunctionSlot = 3 + StandardFrameConstants::kCPSlotCount;
171
172 private:
173 int AllocateAlignedFrameSlot(int width) {
174 DCHECK(width == 4 || width == 8);
175 // Skip one slot if necessary.
176 if (width > kPointerSize) {
177 DCHECK(width == kPointerSize * 2);
178 frame_slot_count_++;
179 frame_slot_count_ |= 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000180 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000181 return frame_slot_count_++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000182 }
183
184 private:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000185 bool needs_frame_;
186 int frame_slot_count_;
187 int callee_saved_slot_count_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000188 int spill_slot_count_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000189 BitVector* allocated_registers_;
190 BitVector* allocated_double_registers_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400191
192 DISALLOW_COPY_AND_ASSIGN(Frame);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000193};
194
195
196// Represents an offset from either the stack pointer or frame pointer.
197class FrameOffset {
198 public:
199 inline bool from_stack_pointer() { return (offset_ & 1) == kFromSp; }
200 inline bool from_frame_pointer() { return (offset_ & 1) == kFromFp; }
201 inline int offset() { return offset_ & ~1; }
202
203 inline static FrameOffset FromStackPointer(int offset) {
204 DCHECK((offset & 1) == 0);
205 return FrameOffset(offset | kFromSp);
206 }
207
208 inline static FrameOffset FromFramePointer(int offset) {
209 DCHECK((offset & 1) == 0);
210 return FrameOffset(offset | kFromFp);
211 }
212
213 private:
214 explicit FrameOffset(int offset) : offset_(offset) {}
215
216 int offset_; // Encodes SP or FP in the low order bit.
217
218 static const int kFromSp = 1;
219 static const int kFromFp = 0;
220};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221
222// Encapsulates the mutable state maintained during code generation about the
223// current function's frame.
224class FrameAccessState : public ZoneObject {
225 public:
226 explicit FrameAccessState(Frame* const frame)
227 : frame_(frame), access_frame_with_fp_(false), sp_delta_(0) {
228 SetFrameAccessToDefault();
229 }
230
231 Frame* frame() const { return frame_; }
232
233 int sp_delta() const { return sp_delta_; }
234 void ClearSPDelta() { sp_delta_ = 0; }
235 void IncreaseSPDelta(int amount) { sp_delta_ += amount; }
236
237 bool access_frame_with_fp() const { return access_frame_with_fp_; }
238 void SetFrameAccessToDefault();
239 void SetFrameAccessToFP() { access_frame_with_fp_ = true; }
240 void SetFrameAccessToSP() { access_frame_with_fp_ = false; }
241
242 // Get the frame offset for a given spill slot. The location depends on the
243 // calling convention and the specific frame layout, and may thus be
244 // architecture-specific. Negative spill slots indicate arguments on the
245 // caller's frame.
246 FrameOffset GetFrameOffset(int spill_slot) const;
247
248 private:
249 Frame* const frame_;
250 bool access_frame_with_fp_;
251 int sp_delta_;
252};
253} // namespace compiler
254} // namespace internal
255} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000256
257#endif // V8_COMPILER_FRAME_H_