1 /*
   2  * Copyright (c) 2015, 2018, 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/debug.hpp"
  30 #include "utilities/globalDefinitions.hpp"
  31 #ifdef TARGET_ARCH_x86
  32 # include "bytes_x86.hpp"
  33 #endif
  34 #ifdef TARGET_ARCH_sparc
  35 # include "bytes_sparc.hpp"
  36 #endif
  37 #ifdef TARGET_ARCH_zero
  38 # include "bytes_zero.hpp"
  39 #endif
  40 #ifdef TARGET_ARCH_arm
  41 # include "bytes_arm.hpp"
  42 #endif
  43 #ifdef TARGET_ARCH_ppc
  44 # include "bytes_ppc.hpp"
  45 #endif
  46 
  47 //
  48 // The Encoding policy prescribes a template
  49 // method taking a first parameter of type T.
  50 // This is the value to be encoded. The second
  51 // parameter is a memory address - where to write
  52 // the encoded value.
  53 // The encoder method(s) should return the
  54 // number of bytes encoded into that memory address.
  55 //
  56 // template <typename T>
  57 // size_t encoder(T value, u1* dest);
  58 //
  59 // The caller ensures the destination
  60 // address is not null and that T can be fitted
  61 // in encoded form.
  62 //
  63 
  64 // Encoding policy classes
  65 
  66 class BigEndianEncoderImpl {
  67  public:
  68   template <typename T>
  69   static size_t encode(T value, u1* dest);
  70 
  71   template <typename T>
  72   static size_t encode(const T* src, size_t len, u1* dest);
  73 
  74   template <typename T>
  75   static size_t encode_padded(T value, u1* dest);
  76 
  77   template <typename T>
  78   static size_t encode_padded(const T* src, size_t len, u1* dest);
  79 
  80 };
  81 
  82 template <typename T>
  83 inline size_t BigEndianEncoderImpl::encode(T value, u1* dest) {
  84   assert(dest != NULL, "invariant");
  85   switch (sizeof(T)) {
  86     case 1: {
  87       ShouldNotReachHere();
  88        return 0;
  89      }
  90      case 2: {
  91        Bytes::put_Java_u2(dest, value);
  92        return 2;
  93      }
  94      case 4: {
  95        Bytes::put_Java_u4(dest, value);
  96        return 4;
  97      }
  98      case 8: {
  99        Bytes::put_Java_u8(dest, value);
 100        return 8;
 101      }
 102   }
 103   ShouldNotReachHere();
 104   return 0;
 105 }
 106 
 107 template <typename T>
 108 inline size_t BigEndianEncoderImpl::encode(const T* src, size_t len, u1* dest) {
 109   assert(dest != NULL, "invariant");
 110   assert(len >= 1, "invariant");
 111   if (1 == sizeof(T)) {
 112     memcpy(dest, src, len);
 113     return len;
 114   }
 115   size_t size = encode(*src, dest);
 116   if (len > 1) {
 117     for (size_t i = 1; i < len; ++i) {
 118       size += encode(*(src + i), dest + size);
 119     }
 120   }
 121   return size;
 122 }
 123 
 124 template <typename T>
 125 inline size_t BigEndianEncoderImpl::encode_padded(T value, u1* dest) {
 126   return encode(value, dest);
 127 }
 128 
 129 template <typename T>
 130 inline size_t BigEndianEncoderImpl::encode_padded(const T* src, size_t len, u1* dest) {
 131   assert(dest != NULL, "invariant");
 132   assert(len >= 1, "invariant");
 133   if (1 == sizeof(T)) {
 134     memcpy(dest, src, len);
 135     return len;
 136   }
 137   size_t size = encode_padded(*src, dest);
 138   if (len > 1) {
 139     for (size_t i = 1; i < len; ++i) {
 140       size += encode_padded(*(src + i), dest + size);
 141     }
 142   }
 143   return size;
 144 }
 145 
 146 
 147 // The Varint128 encoder implements encoding according to
 148 // msb(it) 128bit encoding (1 encode bit | 7 value bits),
 149 // using least significant byte order.
 150 //
 151 // Example (little endian platform):
 152 // Value: 25674
 153 // Binary: 00000000 0000000 01100100 01001010
 154 // Varint encoded (3 bytes):
 155 // Value: 13289473
 156 // Varint encoded: 11001010 11001000 00000001
 157 //
 158 
 159 class Varint128EncoderImpl {
 160  private:
 161   template <typename T>
 162   static u8 to_u8(T value);
 163 
 164  public:
 165   template <typename T>
 166   static size_t encode(T value, u1* dest);
 167 
 168   template <typename T>
 169   static size_t encode(const T* src, size_t len, u1* dest);
 170 
 171   template <typename T>
 172   static size_t encode_padded(T value, u1* dest);
 173 
 174   template <typename T>
 175   static size_t encode_padded(const T* src, size_t len, u1* dest);
 176 
 177 };
 178 
 179 template <typename T>
 180 inline u8 Varint128EncoderImpl::to_u8(T value) {
 181   switch(sizeof(T)) {
 182     case 1:
 183      return static_cast<u8>(static_cast<u1>(value) & static_cast<u1>(0xff));
 184     case 2:
 185       return static_cast<u8>(static_cast<u2>(value) & static_cast<u2>(0xffff));
 186     case 4:
 187       return static_cast<u8>(static_cast<u4>(value) & static_cast<u4>(0xffffffff));
 188     case 8:
 189       return static_cast<u8>(value);
 190     default:
 191       fatal("unsupported type");
 192   }
 193   return 0;
 194 }
 195 
 196 static const u1 ext_bit = 0x80;
 197 #define GREATER_THAN_OR_EQUAL_TO_128(v) (((u8)(~(ext_bit - 1)) & (v)))
 198 #define LESS_THAN_128(v) !GREATER_THAN_OR_EQUAL_TO_128(v)
 199 
 200 template <typename T>
 201 inline size_t Varint128EncoderImpl::encode(T value, u1* dest) {
 202   assert(dest != NULL, "invariant");
 203 
 204   const u8 v = to_u8(value);
 205 
 206   if (LESS_THAN_128(v)) {
 207     *dest = static_cast<u1>(v); // set bit 0-6, no extension
 208     return 1;
 209   }
 210   *dest = static_cast<u1>(v | ext_bit); // set bit 0-6, with extension
 211   if (LESS_THAN_128(v >> 7)) {
 212     *(dest + 1) = static_cast<u1>(v >> 7); // set bit 7-13, no extension
 213     return 2;
 214   }
 215   *(dest + 1) = static_cast<u1>((v >> 7) | ext_bit); // set bit 7-13, with extension
 216   if (LESS_THAN_128(v >> 14)) {
 217     *(dest + 2) = static_cast<u1>(v >> 14); // set bit 14-20, no extension
 218     return 3;
 219   }
 220   *(dest + 2) = static_cast<u1>((v >> 14) | ext_bit); // set bit 14-20, with extension
 221   if (LESS_THAN_128(v >> 21)) {
 222     *(dest + 3) = static_cast<u1>(v >> 21); // set bit 21-27, no extension
 223     return 4;
 224   }
 225   *(dest + 3) = static_cast<u1>((v >> 21) | ext_bit); // set bit 21-27, with extension
 226   if (LESS_THAN_128(v >> 28)) {
 227     *(dest + 4) = static_cast<u1>(v >> 28); // set bit 28-34, no extension
 228     return 5;
 229   }
 230   *(dest + 4) = static_cast<u1>((v >> 28) | ext_bit); // set bit 28-34, with extension
 231   if (LESS_THAN_128(v >> 35)) {
 232     *(dest + 5) = static_cast<u1>(v >> 35); // set bit 35-41, no extension
 233     return 6;
 234   }
 235   *(dest + 5) = static_cast<u1>((v >> 35) | ext_bit); // set bit 35-41, with extension
 236   if (LESS_THAN_128(v >> 42)) {
 237     *(dest + 6) = static_cast<u1>(v >> 42); // set bit 42-48, no extension
 238     return 7;
 239   }
 240   *(dest + 6) = static_cast<u1>((v >> 42) | ext_bit); // set bit 42-48, with extension
 241   if (LESS_THAN_128(v >> 49)) {
 242     *(dest + 7) = static_cast<u1>(v >> 49); // set bit 49-55, no extension
 243     return 8;
 244   }
 245   *(dest + 7) = static_cast<u1>((v >> 49) | ext_bit); // set bit 49-55, with extension
 246   // no need to extend since only 64 bits allowed.
 247   *(dest + 8) = static_cast<u1>(v >> 56);  // set bit 56-63
 248   return 9;
 249 }
 250 
 251 template <typename T>
 252 inline size_t Varint128EncoderImpl::encode(const T* src, size_t len, u1* dest) {
 253   assert(dest != NULL, "invariant");
 254   assert(len >= 1, "invariant");
 255   size_t size = encode(*src, dest);
 256   if (len > 1) {
 257     for (size_t i = 1; i < len; ++i) {
 258       size += encode(*(src + i), dest + size);
 259     }
 260   }
 261   return size;
 262 }
 263 
 264 template <typename T>
 265 inline size_t Varint128EncoderImpl::encode_padded(T value, u1* dest) {
 266   assert(dest != NULL, "invariant");
 267   const u8 v = to_u8(value);
 268   switch (sizeof(T)) {
 269     case 1:
 270       dest[0] = static_cast<u1>(v);
 271       return 1;
 272     case 2:
 273       dest[0] = static_cast<u1>(v | 0x80);
 274       dest[1] = static_cast<u1>(v >> 7);
 275       return 2;
 276     case 4:
 277       dest[0] = static_cast<u1>(v | 0x80);
 278       dest[1] = static_cast<u1>(v >> 7 | 0x80);
 279       dest[2] = static_cast<u1>(v >> 14 | 0x80);
 280       dest[3] = static_cast<u1>(v >> 21);
 281       return 4;
 282     case 8:
 283       dest[0] = static_cast<u1>(v | 0x80);
 284       dest[1] = static_cast<u1>(v >> 7 | 0x80);
 285       dest[2] = static_cast<u1>(v >> 14 | 0x80);
 286       dest[3] = static_cast<u1>(v >> 21 | 0x80);
 287       dest[4] = static_cast<u1>(v >> 28 | 0x80);
 288       dest[5] = static_cast<u1>(v >> 35 | 0x80);
 289       dest[6] = static_cast<u1>(v >> 42 | 0x80);
 290       dest[7] = static_cast<u1>(v >> 49);
 291       return 8;
 292     default:
 293       ShouldNotReachHere();
 294     }
 295   return 0;
 296 }
 297 
 298 
 299 template <typename T>
 300 inline size_t Varint128EncoderImpl::encode_padded(const T* src, size_t len, u1* dest) {
 301   assert(dest != NULL, "invariant");
 302   assert(len >= 1, "invariant");
 303   size_t size = encode_padded(*src, dest);
 304   if (len > 1) {
 305     for (size_t i = 1; i < len; ++i) {
 306       size += encode_padded(*(src + i), dest + size);
 307     }
 308   }
 309   return size;
 310 }
 311 
 312 #endif // SHARE_VM_JFR_WRITERS_JFRENCODERS_HPP