|
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 uint32_t readVariableLength() { |
|
35 uint32_t val = 0; |
|
36 uint32_t shift = 0; |
|
37 uint8_t byte; |
|
38 while (true) { |
|
39 JS_ASSERT(shift < 32); |
|
40 byte = readByte(); |
|
41 val |= (uint32_t(byte) >> 1) << shift; |
|
42 shift += 7; |
|
43 if (!(byte & 1)) |
|
44 return val; |
|
45 } |
|
46 MOZ_ASSUME_UNREACHABLE("unreachable"); |
|
47 } |
|
48 |
|
49 public: |
|
50 CompactBufferReader(const uint8_t *start, const uint8_t *end) |
|
51 : buffer_(start), |
|
52 end_(end) |
|
53 { } |
|
54 inline CompactBufferReader(const CompactBufferWriter &writer); |
|
55 uint8_t readByte() { |
|
56 JS_ASSERT(buffer_ < end_); |
|
57 return *buffer_++; |
|
58 } |
|
59 uint32_t readFixedUint32_t() { |
|
60 uint32_t b0 = readByte(); |
|
61 uint32_t b1 = readByte(); |
|
62 uint32_t b2 = readByte(); |
|
63 uint32_t b3 = readByte(); |
|
64 return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); |
|
65 } |
|
66 uint16_t readFixedUint16_t() { |
|
67 uint32_t b0 = readByte(); |
|
68 uint32_t b1 = readByte(); |
|
69 return b0 | (b1 << 8); |
|
70 } |
|
71 uint32_t readUnsigned() { |
|
72 return readVariableLength(); |
|
73 } |
|
74 int32_t readSigned() { |
|
75 uint8_t b = readByte(); |
|
76 bool isNegative = !!(b & (1 << 0)); |
|
77 bool more = !!(b & (1 << 1)); |
|
78 int32_t result = b >> 2; |
|
79 if (more) |
|
80 result |= readUnsigned() << 6; |
|
81 if (isNegative) |
|
82 return -result; |
|
83 return result; |
|
84 } |
|
85 |
|
86 bool more() const { |
|
87 JS_ASSERT(buffer_ <= end_); |
|
88 return buffer_ < end_; |
|
89 } |
|
90 |
|
91 void seek(const uint8_t *start, uint32_t offset) { |
|
92 buffer_ = start + offset; |
|
93 MOZ_ASSERT(start < end_); |
|
94 MOZ_ASSERT(buffer_ < end_); |
|
95 } |
|
96 }; |
|
97 |
|
98 class CompactBufferWriter |
|
99 { |
|
100 js::Vector<uint8_t, 32, SystemAllocPolicy> buffer_; |
|
101 bool enoughMemory_; |
|
102 |
|
103 public: |
|
104 CompactBufferWriter() |
|
105 : enoughMemory_(true) |
|
106 { } |
|
107 |
|
108 // Note: writeByte() takes uint32 to catch implicit casts with a runtime |
|
109 // assert. |
|
110 void writeByte(uint32_t byte) { |
|
111 JS_ASSERT(byte <= 0xFF); |
|
112 enoughMemory_ &= buffer_.append(byte); |
|
113 } |
|
114 void writeUnsigned(uint32_t value) { |
|
115 do { |
|
116 uint8_t byte = ((value & 0x7F) << 1) | (value > 0x7F); |
|
117 writeByte(byte); |
|
118 value >>= 7; |
|
119 } while (value); |
|
120 } |
|
121 void writeSigned(int32_t v) { |
|
122 bool isNegative = v < 0; |
|
123 uint32_t value = isNegative ? -v : v; |
|
124 uint8_t byte = ((value & 0x3F) << 2) | ((value > 0x3F) << 1) | uint32_t(isNegative); |
|
125 writeByte(byte); |
|
126 |
|
127 // Write out the rest of the bytes, if needed. |
|
128 value >>= 6; |
|
129 if (value == 0) |
|
130 return; |
|
131 writeUnsigned(value); |
|
132 } |
|
133 void writeFixedUint32_t(uint32_t value) { |
|
134 writeByte(value & 0xFF); |
|
135 writeByte((value >> 8) & 0xFF); |
|
136 writeByte((value >> 16) & 0xFF); |
|
137 writeByte((value >> 24) & 0xFF); |
|
138 } |
|
139 void writeFixedUint16_t(uint16_t value) { |
|
140 writeByte(value & 0xFF); |
|
141 writeByte(value >> 8); |
|
142 } |
|
143 size_t length() const { |
|
144 return buffer_.length(); |
|
145 } |
|
146 uint8_t *buffer() { |
|
147 return &buffer_[0]; |
|
148 } |
|
149 const uint8_t *buffer() const { |
|
150 return &buffer_[0]; |
|
151 } |
|
152 bool oom() const { |
|
153 return !enoughMemory_; |
|
154 } |
|
155 }; |
|
156 |
|
157 CompactBufferReader::CompactBufferReader(const CompactBufferWriter &writer) |
|
158 : buffer_(writer.buffer()), |
|
159 end_(writer.buffer() + writer.length()) |
|
160 { |
|
161 } |
|
162 |
|
163 } // namespace jit |
|
164 } // namespace js |
|
165 |
|
166 #endif /* jit_Compactbuffer_h */ |