blob: 84462c55fcfcab4f0d2bafd4ca23ddcf28b76176 [file] [log] [blame]
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -07001// Copyright 2011 Google Inc. All Rights Reserved.
2
3#ifndef ART_SRC_ASSEMBLER_H_
4#define ART_SRC_ASSEMBLER_H_
5
6#include "src/logging.h"
7#include "src/macros.h"
8#include "src/memory_region.h"
9
Carl Shapiro6b6b5f02011-06-21 15:05:09 -070010namespace art {
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070011
12class Assembler;
13class AssemblerBuffer;
14class AssemblerFixup;
15
Ian Rogersb033c752011-07-20 12:22:35 -070016// Allow the meaning of offsets to be strongly typed
17class Offset {
18 public:
19 explicit Offset(size_t val) : val_(val) {}
20 int32_t Int32Value() const {
21 return static_cast<int32_t>(val_);
22 }
23 uint32_t Uint32Value() const {
24 return static_cast<uint32_t>(val_);
25 }
26 protected:
27 size_t val_;
28};
29std::ostream& operator<<(std::ostream& os, const Offset& offs);
30
31// Offsets relative to the current frame
32class FrameOffset : public Offset {
33 public:
34 explicit FrameOffset(size_t val) : Offset(val) {}
35 bool operator>(FrameOffset other) const { return val_ > other.val_; }
36 bool operator<(FrameOffset other) const { return val_ < other.val_; }
37};
38
39// Offsets relative to the current running thread
40class ThreadOffset : public Offset {
41 public:
42 explicit ThreadOffset(size_t val) : Offset(val) {}
43};
44
45// Offsets relative to an object
46class MemberOffset : public Offset {
47 public:
48 explicit MemberOffset(size_t val) : Offset(val) {}
49};
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070050
51class Label {
52 public:
53 Label() : position_(0) {}
54
55 ~Label() {
56 // Assert if label is being destroyed with unresolved branches pending.
57 CHECK(!IsLinked());
58 }
59
60 // Returns the position for bound and linked labels. Cannot be used
61 // for unused labels.
62 int Position() const {
63 CHECK(!IsUnused());
64 return IsBound() ? -position_ - kPointerSize : position_ - kPointerSize;
65 }
66
67 int LinkPosition() const {
68 CHECK(IsLinked());
69 return position_ - kWordSize;
70 }
71
72 bool IsBound() const { return position_ < 0; }
73 bool IsUnused() const { return position_ == 0; }
74 bool IsLinked() const { return position_ > 0; }
75
76 private:
77 int position_;
78
79 void Reinitialize() {
80 position_ = 0;
81 }
82
83 void BindTo(int position) {
84 CHECK(!IsBound());
85 position_ = -position - kPointerSize;
86 CHECK(IsBound());
87 }
88
89 void LinkTo(int position) {
90 CHECK(!IsBound());
91 position_ = position + kPointerSize;
92 CHECK(IsLinked());
93 }
94
95 friend class Assembler;
96 DISALLOW_COPY_AND_ASSIGN(Label);
97};
98
99
100// Assembler fixups are positions in generated code that require processing
101// after the code has been copied to executable memory. This includes building
102// relocation information.
103class AssemblerFixup {
104 public:
105 virtual void Process(const MemoryRegion& region, int position) = 0;
106 virtual ~AssemblerFixup() {}
107
108 private:
109 AssemblerFixup* previous_;
110 int position_;
111
112 AssemblerFixup* previous() const { return previous_; }
113 void set_previous(AssemblerFixup* previous) { previous_ = previous; }
114
115 int position() const { return position_; }
116 void set_position(int position) { position_ = position; }
117
118 friend class AssemblerBuffer;
119};
120
121
122class AssemblerBuffer {
123 public:
124 AssemblerBuffer();
125 ~AssemblerBuffer();
126
127 // Basic support for emitting, loading, and storing.
128 template<typename T> void Emit(T value) {
129 CHECK(HasEnsuredCapacity());
130 *reinterpret_cast<T*>(cursor_) = value;
131 cursor_ += sizeof(T);
132 }
133
134 template<typename T> T Load(size_t position) {
135 CHECK_LE(position, Size() - static_cast<int>(sizeof(T)));
136 return *reinterpret_cast<T*>(contents_ + position);
137 }
138
139 template<typename T> void Store(size_t position, T value) {
140 CHECK_LE(position, Size() - static_cast<int>(sizeof(T)));
141 *reinterpret_cast<T*>(contents_ + position) = value;
142 }
143
144 // Emit a fixup at the current location.
145 void EmitFixup(AssemblerFixup* fixup) {
146 fixup->set_previous(fixup_);
147 fixup->set_position(Size());
148 fixup_ = fixup;
149 }
150
151 // Get the size of the emitted code.
152 size_t Size() const {
153 CHECK_GE(cursor_, contents_);
154 return cursor_ - contents_;
155 }
156
157 byte* contents() const { return contents_; }
158
159 // Copy the assembled instructions into the specified memory block
160 // and apply all fixups.
161 void FinalizeInstructions(const MemoryRegion& region);
162
163 // To emit an instruction to the assembler buffer, the EnsureCapacity helper
164 // must be used to guarantee that the underlying data area is big enough to
165 // hold the emitted instruction. Usage:
166 //
167 // AssemblerBuffer buffer;
168 // AssemblerBuffer::EnsureCapacity ensured(&buffer);
169 // ... emit bytes for single instruction ...
170
171#ifdef DEBUG
172
173 class EnsureCapacity {
174 public:
175 explicit EnsureCapacity(AssemblerBuffer* buffer) {
176 if (buffer->cursor() >= buffer->limit()) buffer->ExtendCapacity();
177 // In debug mode, we save the assembler buffer along with the gap
178 // size before we start emitting to the buffer. This allows us to
179 // check that any single generated instruction doesn't overflow the
180 // limit implied by the minimum gap size.
181 buffer_ = buffer;
182 gap_ = ComputeGap();
183 // Make sure that extending the capacity leaves a big enough gap
184 // for any kind of instruction.
185 CHECK_GE(gap_, kMinimumGap);
186 // Mark the buffer as having ensured the capacity.
187 CHECK(!buffer->HasEnsuredCapacity()); // Cannot nest.
188 buffer->has_ensured_capacity_ = true;
189 }
190
191 ~EnsureCapacity() {
192 // Unmark the buffer, so we cannot emit after this.
193 buffer_->has_ensured_capacity_ = false;
194 // Make sure the generated instruction doesn't take up more
195 // space than the minimum gap.
196 int delta = gap_ - ComputeGap();
Ian Rogersb033c752011-07-20 12:22:35 -0700197 CHECK_LE(delta, kMinimumGap);
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -0700198 }
199
200 private:
201 AssemblerBuffer* buffer_;
202 int gap_;
203
204 int ComputeGap() { return buffer_->Capacity() - buffer_->Size(); }
205 };
206
207 bool has_ensured_capacity_;
208 bool HasEnsuredCapacity() const { return has_ensured_capacity_; }
209
210#else
211
212 class EnsureCapacity {
213 public:
214 explicit EnsureCapacity(AssemblerBuffer* buffer) {
215 if (buffer->cursor() >= buffer->limit()) buffer->ExtendCapacity();
216 }
217 };
218
219 // When building the C++ tests, assertion code is enabled. To allow
220 // asserting that the user of the assembler buffer has ensured the
221 // capacity needed for emitting, we add a dummy method in non-debug mode.
222 bool HasEnsuredCapacity() const { return true; }
223
224#endif
225
226 // Returns the position in the instruction stream.
227 int GetPosition() { return cursor_ - contents_; }
228
229 private:
230 // The limit is set to kMinimumGap bytes before the end of the data area.
231 // This leaves enough space for the longest possible instruction and allows
232 // for a single, fast space check per instruction.
233 static const int kMinimumGap = 32;
234
235 byte* contents_;
236 byte* cursor_;
237 byte* limit_;
238 AssemblerFixup* fixup_;
239 bool fixups_processed_;
240
241 byte* cursor() const { return cursor_; }
242 byte* limit() const { return limit_; }
243 size_t Capacity() const {
244 CHECK_GE(limit_, contents_);
245 return (limit_ - contents_) + kMinimumGap;
246 }
247
248 // Process the fixup chain starting at the given fixup. The offset is
249 // non-zero for fixups in the body if the preamble is non-empty.
250 void ProcessFixups(const MemoryRegion& region);
251
252 // Compute the limit based on the data area and the capacity. See
253 // description of kMinimumGap for the reasoning behind the value.
254 static byte* ComputeLimit(byte* data, size_t capacity) {
255 return data + capacity - kMinimumGap;
256 }
257
258 void ExtendCapacity();
259
260 friend class AssemblerFixup;
261};
262
Carl Shapiro6b6b5f02011-06-21 15:05:09 -0700263} // namespace art
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -0700264
265#if defined(__i386__)
266#include "src/assembler_x86.h"
267#elif defined(__arm__)
268#include "src/assembler_arm.h"
269#endif
270
271#endif // ART_SRC_ASSEMBLER_H_