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_VM_JFR_WRITERS_JFRENCODERS_HPP
  26 #define SHARE_VM_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_VM_JFR_WRITERS_JFRENCODERS_HPP