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