1 | /* |
2 | * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. |
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | * |
5 | * This code is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 only, as |
7 | * published by the Free Software Foundation. |
8 | * |
9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
12 | * version 2 for more details (a copy is included in the LICENSE file that |
13 | * accompanied this code). |
14 | * |
15 | * You should have received a copy of the GNU General Public License version |
16 | * 2 along with this work; if not, write to the Free Software Foundation, |
17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
18 | * |
19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
20 | * or visit www.oracle.com if you need additional information or have any |
21 | * questions. |
22 | * |
23 | */ |
24 | |
25 | #ifndef SHARE_JFR_WRITERS_JFRENCODERS_HPP |
26 | #define SHARE_JFR_WRITERS_JFRENCODERS_HPP |
27 | |
28 | #include "memory/allocation.hpp" |
29 | #include "utilities/bytes.hpp" |
30 | #include "utilities/debug.hpp" |
31 | #include "utilities/globalDefinitions.hpp" |
32 | |
33 | // |
34 | // The Encoding policy prescribes a template |
35 | // method taking a first parameter of type T. |
36 | // This is the value to be encoded. The second |
37 | // parameter is a memory address - where to write |
38 | // the encoded value. |
39 | // The encoder method(s) should return the |
40 | // number of bytes encoded into that memory address. |
41 | // |
42 | // template <typename T> |
43 | // size_t encoder(T value, u1* dest); |
44 | // |
45 | // The caller ensures the destination |
46 | // address is not null and that T can be fitted |
47 | // in encoded form. |
48 | // |
49 | |
50 | // Encoding policy classes |
51 | |
52 | class BigEndianEncoderImpl { |
53 | public: |
54 | template <typename T> |
55 | static size_t encode(T value, u1* dest); |
56 | |
57 | template <typename T> |
58 | static size_t encode(const T* src, size_t len, u1* dest); |
59 | |
60 | template <typename T> |
61 | static size_t encode_padded(T value, u1* dest); |
62 | |
63 | template <typename T> |
64 | static size_t encode_padded(const T* src, size_t len, u1* dest); |
65 | |
66 | }; |
67 | |
68 | template <typename T> |
69 | inline size_t BigEndianEncoderImpl::encode(T value, u1* dest) { |
70 | assert(dest != NULL, "invariant" ); |
71 | switch (sizeof(T)) { |
72 | case 1: { |
73 | ShouldNotReachHere(); |
74 | return 0; |
75 | } |
76 | case 2: { |
77 | Bytes::put_Java_u2(dest, value); |
78 | return 2; |
79 | } |
80 | case 4: { |
81 | Bytes::put_Java_u4(dest, value); |
82 | return 4; |
83 | } |
84 | case 8: { |
85 | Bytes::put_Java_u8(dest, value); |
86 | return 8; |
87 | } |
88 | } |
89 | ShouldNotReachHere(); |
90 | return 0; |
91 | } |
92 | |
93 | template <typename T> |
94 | inline size_t BigEndianEncoderImpl::encode(const T* src, size_t len, u1* dest) { |
95 | assert(dest != NULL, "invariant" ); |
96 | assert(len >= 1, "invariant" ); |
97 | if (1 == sizeof(T)) { |
98 | memcpy(dest, src, len); |
99 | return len; |
100 | } |
101 | size_t size = encode(*src, dest); |
102 | if (len > 1) { |
103 | for (size_t i = 1; i < len; ++i) { |
104 | size += encode(*(src + i), dest + size); |
105 | } |
106 | } |
107 | return size; |
108 | } |
109 | |
110 | template <typename T> |
111 | inline size_t BigEndianEncoderImpl::encode_padded(T value, u1* dest) { |
112 | return encode(value, dest); |
113 | } |
114 | |
115 | template <typename T> |
116 | inline size_t BigEndianEncoderImpl::encode_padded(const T* src, size_t len, u1* dest) { |
117 | assert(dest != NULL, "invariant" ); |
118 | assert(len >= 1, "invariant" ); |
119 | if (1 == sizeof(T)) { |
120 | memcpy(dest, src, len); |
121 | return len; |
122 | } |
123 | size_t size = encode_padded(*src, dest); |
124 | if (len > 1) { |
125 | for (size_t i = 1; i < len; ++i) { |
126 | size += encode_padded(*(src + i), dest + size); |
127 | } |
128 | } |
129 | return size; |
130 | } |
131 | |
132 | |
133 | // The Varint128 encoder implements encoding according to |
134 | // msb(it) 128bit encoding (1 encode bit | 7 value bits), |
135 | // using least significant byte order. |
136 | // |
137 | // Example (little endian platform): |
138 | // Value: 25674 |
139 | // Binary: 00000000 0000000 01100100 01001010 |
140 | // Varint encoded (3 bytes): |
141 | // Value: 13289473 |
142 | // Varint encoded: 11001010 11001000 00000001 |
143 | // |
144 | |
145 | class Varint128EncoderImpl { |
146 | private: |
147 | template <typename T> |
148 | static u8 to_u8(T value); |
149 | |
150 | public: |
151 | template <typename T> |
152 | static size_t encode(T value, u1* dest); |
153 | |
154 | template <typename T> |
155 | static size_t encode(const T* src, size_t len, u1* dest); |
156 | |
157 | template <typename T> |
158 | static size_t encode_padded(T value, u1* dest); |
159 | |
160 | template <typename T> |
161 | static size_t encode_padded(const T* src, size_t len, u1* dest); |
162 | |
163 | }; |
164 | |
165 | template <typename T> |
166 | inline u8 Varint128EncoderImpl::to_u8(T value) { |
167 | switch(sizeof(T)) { |
168 | case 1: |
169 | return static_cast<u8>(static_cast<u1>(value) & static_cast<u1>(0xff)); |
170 | case 2: |
171 | return static_cast<u8>(static_cast<u2>(value) & static_cast<u2>(0xffff)); |
172 | case 4: |
173 | return static_cast<u8>(static_cast<u4>(value) & static_cast<u4>(0xffffffff)); |
174 | case 8: |
175 | return static_cast<u8>(value); |
176 | default: |
177 | fatal("unsupported type" ); |
178 | } |
179 | return 0; |
180 | } |
181 | |
182 | static const u1 ext_bit = 0x80; |
183 | #define GREATER_THAN_OR_EQUAL_TO_128(v) (((u8)(~(ext_bit - 1)) & (v))) |
184 | #define LESS_THAN_128(v) !GREATER_THAN_OR_EQUAL_TO_128(v) |
185 | |
186 | template <typename T> |
187 | inline size_t Varint128EncoderImpl::encode(T value, u1* dest) { |
188 | assert(dest != NULL, "invariant" ); |
189 | |
190 | const u8 v = to_u8(value); |
191 | |
192 | if (LESS_THAN_128(v)) { |
193 | *dest = static_cast<u1>(v); // set bit 0-6, no extension |
194 | return 1; |
195 | } |
196 | *dest = static_cast<u1>(v | ext_bit); // set bit 0-6, with extension |
197 | if (LESS_THAN_128(v >> 7)) { |
198 | *(dest + 1) = static_cast<u1>(v >> 7); // set bit 7-13, no extension |
199 | return 2; |
200 | } |
201 | *(dest + 1) = static_cast<u1>((v >> 7) | ext_bit); // set bit 7-13, with extension |
202 | if (LESS_THAN_128(v >> 14)) { |
203 | *(dest + 2) = static_cast<u1>(v >> 14); // set bit 14-20, no extension |
204 | return 3; |
205 | } |
206 | *(dest + 2) = static_cast<u1>((v >> 14) | ext_bit); // set bit 14-20, with extension |
207 | if (LESS_THAN_128(v >> 21)) { |
208 | *(dest + 3) = static_cast<u1>(v >> 21); // set bit 21-27, no extension |
209 | return 4; |
210 | } |
211 | *(dest + 3) = static_cast<u1>((v >> 21) | ext_bit); // set bit 21-27, with extension |
212 | if (LESS_THAN_128(v >> 28)) { |
213 | *(dest + 4) = static_cast<u1>(v >> 28); // set bit 28-34, no extension |
214 | return 5; |
215 | } |
216 | *(dest + 4) = static_cast<u1>((v >> 28) | ext_bit); // set bit 28-34, with extension |
217 | if (LESS_THAN_128(v >> 35)) { |
218 | *(dest + 5) = static_cast<u1>(v >> 35); // set bit 35-41, no extension |
219 | return 6; |
220 | } |
221 | *(dest + 5) = static_cast<u1>((v >> 35) | ext_bit); // set bit 35-41, with extension |
222 | if (LESS_THAN_128(v >> 42)) { |
223 | *(dest + 6) = static_cast<u1>(v >> 42); // set bit 42-48, no extension |
224 | return 7; |
225 | } |
226 | *(dest + 6) = static_cast<u1>((v >> 42) | ext_bit); // set bit 42-48, with extension |
227 | if (LESS_THAN_128(v >> 49)) { |
228 | *(dest + 7) = static_cast<u1>(v >> 49); // set bit 49-55, no extension |
229 | return 8; |
230 | } |
231 | *(dest + 7) = static_cast<u1>((v >> 49) | ext_bit); // set bit 49-55, with extension |
232 | // no need to extend since only 64 bits allowed. |
233 | *(dest + 8) = static_cast<u1>(v >> 56); // set bit 56-63 |
234 | return 9; |
235 | } |
236 | |
237 | template <typename T> |
238 | inline size_t Varint128EncoderImpl::encode(const T* src, size_t len, u1* dest) { |
239 | assert(dest != NULL, "invariant" ); |
240 | assert(len >= 1, "invariant" ); |
241 | size_t size = encode(*src, dest); |
242 | if (len > 1) { |
243 | for (size_t i = 1; i < len; ++i) { |
244 | size += encode(*(src + i), dest + size); |
245 | } |
246 | } |
247 | return size; |
248 | } |
249 | |
250 | template <typename T> |
251 | inline size_t Varint128EncoderImpl::encode_padded(T value, u1* dest) { |
252 | assert(dest != NULL, "invariant" ); |
253 | const u8 v = to_u8(value); |
254 | switch (sizeof(T)) { |
255 | case 1: |
256 | dest[0] = static_cast<u1>(v); |
257 | return 1; |
258 | case 2: |
259 | dest[0] = static_cast<u1>(v | 0x80); |
260 | dest[1] = static_cast<u1>(v >> 7); |
261 | return 2; |
262 | case 4: |
263 | dest[0] = static_cast<u1>(v | 0x80); |
264 | dest[1] = static_cast<u1>(v >> 7 | 0x80); |
265 | dest[2] = static_cast<u1>(v >> 14 | 0x80); |
266 | dest[3] = static_cast<u1>(v >> 21); |
267 | return 4; |
268 | case 8: |
269 | dest[0] = static_cast<u1>(v | 0x80); |
270 | dest[1] = static_cast<u1>(v >> 7 | 0x80); |
271 | dest[2] = static_cast<u1>(v >> 14 | 0x80); |
272 | dest[3] = static_cast<u1>(v >> 21 | 0x80); |
273 | dest[4] = static_cast<u1>(v >> 28 | 0x80); |
274 | dest[5] = static_cast<u1>(v >> 35 | 0x80); |
275 | dest[6] = static_cast<u1>(v >> 42 | 0x80); |
276 | dest[7] = static_cast<u1>(v >> 49); |
277 | return 8; |
278 | default: |
279 | ShouldNotReachHere(); |
280 | } |
281 | return 0; |
282 | } |
283 | |
284 | |
285 | template <typename T> |
286 | inline size_t Varint128EncoderImpl::encode_padded(const T* src, size_t len, u1* dest) { |
287 | assert(dest != NULL, "invariant" ); |
288 | assert(len >= 1, "invariant" ); |
289 | size_t size = encode_padded(*src, dest); |
290 | if (len > 1) { |
291 | for (size_t i = 1; i < len; ++i) { |
292 | size += encode_padded(*(src + i), dest + size); |
293 | } |
294 | } |
295 | return size; |
296 | } |
297 | |
298 | #endif // SHARE_JFR_WRITERS_JFRENCODERS_HPP |
299 | |