js/src/jit/shared/IonAssemblerBuffer.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial