CompactBuffer.h (6615B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 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/. */ 6 7 #ifndef jit_Compactbuffer_h 8 #define jit_Compactbuffer_h 9 10 #include "mozilla/Assertions.h" 11 12 #include <stddef.h> 13 #include <stdint.h> 14 15 #include "js/AllocPolicy.h" 16 #include "js/Vector.h" 17 18 namespace js { 19 namespace jit { 20 21 class CompactBufferWriter; 22 23 // CompactBuffers are byte streams designed for compressable integers. It has 24 // helper functions for writing bytes, fixed-size integers, and variable-sized 25 // integers. Variable sized integers are encoded in 1-5 bytes, each byte 26 // containing 7 bits of the integer and a bit which specifies whether the next 27 // byte is also part of the integer. 28 // 29 // Fixed-width integers are also available, in case the actual value will not 30 // be known until later. 31 32 class CompactBufferReader { 33 const uint8_t* buffer_; 34 const uint8_t* end_; 35 36 uint32_t readVariableLength() { 37 uint32_t val = 0; 38 uint32_t shift = 0; 39 uint8_t byte; 40 while (true) { 41 MOZ_ASSERT(shift < 32); 42 byte = readByte(); 43 val |= (uint32_t(byte) >> 1) << shift; 44 shift += 7; 45 if (!(byte & 1)) { 46 return val; 47 } 48 } 49 } 50 51 uint64_t readVariableLength64() { 52 uint64_t val = 0; 53 uint32_t shift = 0; 54 uint8_t byte; 55 while (true) { 56 MOZ_ASSERT(shift < 64); 57 byte = readByte(); 58 val |= (uint64_t(byte) >> 1) << shift; 59 shift += 7; 60 if (!(byte & 1)) { 61 return val; 62 } 63 } 64 } 65 66 public: 67 CompactBufferReader(const uint8_t* start, const uint8_t* end) 68 : buffer_(start), end_(end) {} 69 inline explicit CompactBufferReader(const CompactBufferWriter& writer); 70 uint8_t readByte() { 71 MOZ_ASSERT(buffer_ < end_); 72 return *buffer_++; 73 } 74 uint32_t readFixedUint32_t() { 75 uint32_t b0 = readByte(); 76 uint32_t b1 = readByte(); 77 uint32_t b2 = readByte(); 78 uint32_t b3 = readByte(); 79 return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); 80 } 81 uint16_t readFixedUint16_t() { 82 uint32_t b0 = readByte(); 83 uint32_t b1 = readByte(); 84 return b0 | (b1 << 8); 85 } 86 uint16_t peekFixedUint16_t() { 87 uint32_t b0 = buffer_[0]; 88 uint32_t b1 = buffer_[1]; 89 return b0 | (b1 << 8); 90 } 91 uint32_t readNativeEndianUint32_t() { 92 // Must be at 4-byte boundary 93 MOZ_ASSERT(uintptr_t(buffer_) % sizeof(uint32_t) == 0); 94 return *reinterpret_cast<const uint32_t*>(buffer_); 95 } 96 uint32_t readUnsigned() { return readVariableLength(); } 97 uint64_t readUnsigned64() { return readVariableLength64(); } 98 int32_t readSigned() { 99 uint8_t b = readByte(); 100 bool isNegative = !!(b & (1 << 0)); 101 bool more = !!(b & (1 << 1)); 102 int32_t result = b >> 2; 103 if (more) { 104 result |= readUnsigned() << 6; 105 } 106 if (isNegative) { 107 return -result; 108 } 109 return result; 110 } 111 void* readRawPointer() { 112 uintptr_t ptrWord = 0; 113 for (unsigned i = 0; i < sizeof(uintptr_t); i++) { 114 ptrWord |= static_cast<uintptr_t>(readByte()) << (i * 8); 115 } 116 return reinterpret_cast<void*>(ptrWord); 117 } 118 119 bool more() const { 120 MOZ_ASSERT(buffer_ <= end_); 121 return buffer_ < end_; 122 } 123 124 void seek(const uint8_t* start, uint32_t offset) { 125 buffer_ = start + offset; 126 MOZ_ASSERT(start < end_); 127 MOZ_ASSERT(buffer_ <= end_); 128 } 129 130 const uint8_t* currentPosition() const { return buffer_; } 131 }; 132 133 class CompactBufferWriter { 134 js::Vector<uint8_t, 32, SystemAllocPolicy> buffer_; 135 bool enoughMemory_; 136 137 public: 138 CompactBufferWriter() : enoughMemory_(true) {} 139 140 void setOOM() { enoughMemory_ = false; } 141 142 // Note: writeByte() takes uint32 to catch implicit casts with a runtime 143 // assert. 144 void writeByte(uint32_t byte) { 145 MOZ_ASSERT(byte <= 0xFF); 146 if (!buffer_.append(byte)) { 147 enoughMemory_ = false; 148 } 149 } 150 void writeByteAt(uint32_t pos, uint32_t byte) { 151 MOZ_ASSERT(byte <= 0xFF); 152 if (!oom()) { 153 buffer_[pos] = byte; 154 } 155 } 156 void writeUnsigned(uint32_t value) { 157 do { 158 uint8_t byte = ((value & 0x7F) << 1) | (value > 0x7F); 159 writeByte(byte); 160 value >>= 7; 161 } while (value); 162 } 163 void writeUnsignedAt(uint32_t pos, uint32_t value, uint32_t original) { 164 MOZ_ASSERT(value <= original); 165 do { 166 uint8_t byte = ((value & 0x7F) << 1) | (original > 0x7F); 167 writeByteAt(pos++, byte); 168 value >>= 7; 169 original >>= 7; 170 } while (original); 171 } 172 void writeUnsigned64(uint64_t value) { 173 do { 174 uint8_t byte = ((value & 0x7F) << 1) | (value > 0x7F); 175 writeByte(byte); 176 value >>= 7; 177 } while (value); 178 } 179 void writeSigned(int32_t v) { 180 bool isNegative = v < 0; 181 uint32_t value = isNegative ? -v : v; 182 uint8_t byte = 183 ((value & 0x3F) << 2) | ((value > 0x3F) << 1) | uint32_t(isNegative); 184 writeByte(byte); 185 186 // Write out the rest of the bytes, if needed. 187 value >>= 6; 188 if (value == 0) { 189 return; 190 } 191 writeUnsigned(value); 192 } 193 void writeFixedUint32_t(uint32_t value) { 194 writeByte(value & 0xFF); 195 writeByte((value >> 8) & 0xFF); 196 writeByte((value >> 16) & 0xFF); 197 writeByte((value >> 24) & 0xFF); 198 } 199 void writeFixedUint16_t(uint16_t value) { 200 writeByte(value & 0xFF); 201 writeByte(value >> 8); 202 } 203 void writeNativeEndianUint32_t(uint32_t value) { 204 // Must be at 4-byte boundary 205 MOZ_ASSERT_IF(!oom(), length() % sizeof(uint32_t) == 0); 206 writeFixedUint32_t(0); 207 if (oom()) { 208 return; 209 } 210 uint8_t* endPtr = buffer() + length(); 211 reinterpret_cast<uint32_t*>(endPtr)[-1] = value; 212 } 213 void writeRawPointer(const void* ptr) { 214 uintptr_t ptrWord = reinterpret_cast<uintptr_t>(ptr); 215 for (unsigned i = 0; i < sizeof(uintptr_t); i++) { 216 writeByte((ptrWord >> (i * 8)) & 0xFF); 217 } 218 } 219 void writeBytes(const uint8_t* data, size_t len) { 220 if (!buffer_.append(data, len)) { 221 enoughMemory_ = false; 222 } 223 } 224 size_t length() const { return buffer_.length(); } 225 uint8_t* buffer() { 226 MOZ_ASSERT(!oom()); 227 return &buffer_[0]; 228 } 229 const uint8_t* buffer() const { 230 MOZ_ASSERT(!oom()); 231 return &buffer_[0]; 232 } 233 bool oom() const { return !enoughMemory_; } 234 void propagateOOM(bool success) { enoughMemory_ &= success; } 235 }; 236 237 CompactBufferReader::CompactBufferReader(const CompactBufferWriter& writer) 238 : buffer_(writer.buffer()), end_(writer.buffer() + writer.length()) {} 239 240 } // namespace jit 241 } // namespace js 242 243 #endif /* jit_Compactbuffer_h */