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