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>
encode(T value,u1 * dest)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>
encode(const T * src,size_t len,u1 * dest)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>
encode_padded(T value,u1 * dest)111 inline size_t BigEndianEncoderImpl::encode_padded(T value, u1* dest) {
112   return encode(value, dest);
113 }
114 
115 template <typename T>
encode_padded(const T * src,size_t len,u1 * dest)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>
to_u8(T value)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>
encode(T value,u1 * dest)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>
encode(const T * src,size_t len,u1 * dest)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>
encode_padded(T value,u1 * dest)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>
encode_padded(const T * src,size_t len,u1 * dest)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