Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef jit_shared_IonAssemblerBuffer_h
8 #define jit_shared_IonAssemblerBuffer_h
10 // needed for the definition of Label :(
11 #include "jit/shared/Assembler-shared.h"
13 namespace js {
14 namespace jit {
16 // This should theoretically reside inside of AssemblerBuffer, but that won't be nice
17 // AssemblerBuffer is templated, BufferOffset would be indirectly.
18 // A BufferOffset is the offset into a buffer, expressed in bytes of instructions.
20 class BufferOffset
21 {
22 int offset;
23 public:
24 friend BufferOffset nextOffset();
25 explicit BufferOffset(int offset_) : offset(offset_) {}
26 // Return the offset as a raw integer.
27 int getOffset() const { return offset; }
29 // A BOffImm is a Branch Offset Immediate. It is an architecture-specific
30 // structure that holds the immediate for a pc relative branch.
31 // diffB takes the label for the destination of the branch, and encodes
32 // the immediate for the branch. This will need to be fixed up later, since
33 // A pool may be inserted between the branch and its destination
34 template <class BOffImm>
35 BOffImm diffB(BufferOffset other) const {
36 return BOffImm(offset - other.offset);
37 }
39 template <class BOffImm>
40 BOffImm diffB(Label *other) const {
41 JS_ASSERT(other->bound());
42 return BOffImm(offset - other->offset());
43 }
45 explicit BufferOffset(Label *l) : offset(l->offset()) {
46 }
47 explicit BufferOffset(RepatchLabel *l) : offset(l->offset()) {
48 }
50 BufferOffset() : offset(INT_MIN) {}
51 bool assigned() const { return offset != INT_MIN; };
52 };
54 template<int SliceSize>
55 struct BufferSlice {
56 protected:
57 BufferSlice<SliceSize> *prev;
58 BufferSlice<SliceSize> *next;
59 // How much data has been added to the current node.
60 uint32_t nodeSize;
61 public:
62 BufferSlice *getNext() { return this->next; }
63 BufferSlice *getPrev() { return this->prev; }
64 void setNext(BufferSlice<SliceSize> *next_) {
65 JS_ASSERT(this->next == nullptr);
66 JS_ASSERT(next_->prev == nullptr);
67 this->next = next_;
68 next_->prev = this;
69 }
71 mozilla::Array<uint8_t, SliceSize> instructions;
72 unsigned int size() {
73 return nodeSize;
74 }
75 BufferSlice() : prev(nullptr), next(nullptr), nodeSize(0) {}
76 void putBlob(uint32_t instSize, uint8_t* inst) {
77 if (inst != nullptr)
78 memcpy(&instructions[size()], inst, instSize);
79 nodeSize += instSize;
80 }
81 };
83 template<int SliceSize, class Inst>
84 struct AssemblerBuffer
85 {
86 public:
87 AssemblerBuffer() : head(nullptr), tail(nullptr), m_oom(false), m_bail(false), bufferSize(0), LifoAlloc_(8192) {}
88 protected:
89 typedef BufferSlice<SliceSize> Slice;
90 typedef AssemblerBuffer<SliceSize, Inst> AssemblerBuffer_;
91 Slice *head;
92 Slice *tail;
93 public:
94 bool m_oom;
95 bool m_bail;
96 // How much data has been added to the buffer thusfar.
97 uint32_t bufferSize;
98 uint32_t lastInstSize;
99 bool isAligned(int alignment) const {
100 // make sure the requested alignment is a power of two.
101 JS_ASSERT((alignment & (alignment-1)) == 0);
102 return !(size() & (alignment - 1));
103 }
104 virtual Slice *newSlice(LifoAlloc &a) {
105 Slice *tmp = static_cast<Slice*>(a.alloc(sizeof(Slice)));
106 if (!tmp) {
107 m_oom = true;
108 return nullptr;
109 }
110 new (tmp) Slice;
111 return tmp;
112 }
113 bool ensureSpace(int size) {
114 if (tail != nullptr && tail->size()+size <= SliceSize)
115 return true;
116 Slice *tmp = newSlice(LifoAlloc_);
117 if (tmp == nullptr)
118 return false;
119 if (tail != nullptr) {
120 bufferSize += tail->size();
121 tail->setNext(tmp);
122 }
123 tail = tmp;
124 if (head == nullptr) {
125 finger = tmp;
126 finger_offset = 0;
127 head = tmp;
128 }
129 return true;
130 }
132 BufferOffset putByte(uint8_t value) {
133 return putBlob(sizeof(value), (uint8_t*)&value);
134 }
136 BufferOffset putShort(uint16_t value) {
137 return putBlob(sizeof(value), (uint8_t*)&value);
138 }
140 BufferOffset putInt(uint32_t value) {
141 return putBlob(sizeof(value), (uint8_t*)&value);
142 }
143 BufferOffset putBlob(uint32_t instSize, uint8_t *inst) {
144 if (!ensureSpace(instSize))
145 return BufferOffset();
146 BufferOffset ret = nextOffset();
147 tail->putBlob(instSize, inst);
148 return ret;
149 }
150 unsigned int size() const {
151 int executableSize;
152 if (tail != nullptr)
153 executableSize = bufferSize + tail->size();
154 else
155 executableSize = bufferSize;
156 return executableSize;
157 }
158 unsigned int uncheckedSize() const {
159 return size();
160 }
161 bool oom() const {
162 return m_oom || m_bail;
163 }
164 bool bail() const {
165 return m_bail;
166 }
167 void fail_oom() {
168 m_oom = true;
169 }
170 void fail_bail() {
171 m_bail = true;
172 }
173 // finger for speeding up accesses
174 Slice *finger;
175 unsigned int finger_offset;
176 Inst *getInst(BufferOffset off) {
177 int local_off = off.getOffset();
178 // don't update the structure's finger in place, so there is the option
179 // to not update it.
180 Slice *cur = nullptr;
181 int cur_off;
182 // get the offset that we'd be dealing with by walking through backwards
183 int end_off = bufferSize - local_off;
184 // If end_off is negative, then it is in the last chunk, and there is no
185 // real work to be done.
186 if (end_off <= 0) {
187 return (Inst*)&tail->instructions[-end_off];
188 }
189 bool used_finger = false;
190 int finger_off = abs((int)(local_off - finger_offset));
191 if (finger_off < Min(local_off, end_off)) {
192 // The finger offset is minimal, use the finger.
193 cur = finger;
194 cur_off = finger_offset;
195 used_finger = true;
196 } else if (local_off < end_off) {
197 // it is closest to the start
198 cur = head;
199 cur_off = 0;
200 } else {
201 // it is closest to the end
202 cur = tail;
203 cur_off = bufferSize;
204 }
205 int count = 0;
206 if (local_off < cur_off) {
207 for (; cur != nullptr; cur = cur->getPrev(), cur_off -= cur->size()) {
208 if (local_off >= cur_off) {
209 local_off -= cur_off;
210 break;
211 }
212 count++;
213 }
214 JS_ASSERT(cur != nullptr);
215 } else {
216 for (; cur != nullptr; cur = cur->getNext()) {
217 int cur_size = cur->size();
218 if (local_off < cur_off + cur_size) {
219 local_off -= cur_off;
220 break;
221 }
222 cur_off += cur_size;
223 count++;
224 }
225 JS_ASSERT(cur != nullptr);
226 }
227 if (count > 2 || used_finger) {
228 finger = cur;
229 finger_offset = cur_off;
230 }
231 // the offset within this node should not be larger than the node itself.
232 JS_ASSERT(local_off < (int)cur->size());
233 return (Inst*)&cur->instructions[local_off];
234 }
235 BufferOffset nextOffset() const {
236 if (tail != nullptr)
237 return BufferOffset(bufferSize + tail->size());
238 else
239 return BufferOffset(bufferSize);
240 }
241 BufferOffset prevOffset() const {
242 MOZ_ASSUME_UNREACHABLE("Don't current record lastInstSize");
243 }
245 // Break the instruction stream so we can go back and edit it at this point
246 void perforate() {
247 Slice *tmp = newSlice(LifoAlloc_);
248 if (!tmp)
249 m_oom = true;
250 bufferSize += tail->size();
251 tail->setNext(tmp);
252 tail = tmp;
253 }
255 class AssemblerBufferInstIterator {
256 private:
257 BufferOffset bo;
258 AssemblerBuffer_ *m_buffer;
259 public:
260 AssemblerBufferInstIterator(BufferOffset off, AssemblerBuffer_ *buff) : bo(off), m_buffer(buff) {}
261 Inst *next() {
262 Inst *i = m_buffer->getInst(bo);
263 bo = BufferOffset(bo.getOffset()+i->size());
264 return cur();
265 };
266 Inst *cur() {
267 return m_buffer->getInst(bo);
268 }
269 };
270 public:
271 LifoAlloc LifoAlloc_;
272 };
274 } // ion
275 } // js
276 #endif /* jit_shared_IonAssemblerBuffer_h */