1 /*
   2  * Copyright (c) 2016, 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_JFRWRITERHOST_INLINE_HPP
  26 #define SHARE_VM_JFR_WRITERS_JFRWRITERHOST_INLINE_HPP
  27 
  28 #include "classfile/javaClasses.hpp"
  29 #include "jfr/recorder/access/jfrOptionSet.hpp"
  30 #include "jfr/recorder/checkpoint/constant/traceid/jfrTraceId.inline.hpp"
  31 #include "jfr/utilities/jfrTraceTime.hpp"
  32 #include "jfr/writers/jfrEncoding.hpp"
  33 #include "jfr/writers/jfrWriterHost.hpp"
  34 #include "memory/resourceArea.hpp"
  35 #include "oops/oop.hpp"
  36 #include "oops/symbol.hpp"
  37 #include "oops/typeArrayOop.hpp"
  38 
  39 inline bool compressed_integers() {
  40   static const bool comp_integers = JfrOptionSet::compressed_integers();
  41   return comp_integers;
  42 }
  43 
  44 template <typename BE, typename IE, typename WriterPolicyImpl >
  45 template <typename T>
  46 inline void WriterHost<BE, IE, WriterPolicyImpl>::write_padded(T value) {
  47   write_padded(&value, 1);
  48 }
  49 
  50 template <typename BE, typename IE, typename WriterPolicyImpl >
  51 template <typename T>
  52 inline void WriterHost<BE, IE, WriterPolicyImpl>::write_padded(const T* value, size_t len) {
  53   assert(value != NULL, "invariant");
  54   assert(len > 0, "invariant");
  55   u1* const pos = ensure_size(sizeof(T) * len);
  56   if (pos) {
  57     this->set_current_pos(write_padded(value, len, pos));
  58   }
  59 }
  60 
  61 template <typename BE, typename IE, typename WriterPolicyImpl >
  62 template <typename T>
  63 inline u1* WriterHost<BE, IE, WriterPolicyImpl>::write_padded(const T* value, size_t len, u1* pos) {
  64   assert(value != NULL, "invariant");
  65   assert(len > 0, "invariant");
  66   assert(pos != NULL, "invariant");
  67   return _compressed_integers ? IE::write_padded(value, len, pos) : BE::write_padded(value, len, pos);
  68 }
  69 
  70 template <typename BE, typename IE, typename WriterPolicyImpl >
  71 template <typename T>
  72 inline void WriterHost<BE, IE, WriterPolicyImpl>::write(const T* value, size_t len) {
  73   assert(value != NULL, "invariant");
  74   assert(len > 0, "invariant");
  75   u1* const pos = ensure_size(sizeof(T) * len);
  76   if (pos) {
  77     this->set_current_pos(write(value, len, pos));
  78   }
  79 }
  80 
  81 template <typename BE, typename IE, typename WriterPolicyImpl >
  82 template <typename T>
  83 inline u1* WriterHost<BE, IE, WriterPolicyImpl>::write(const T* value, size_t len, u1* pos) {
  84   assert(value != NULL, "invariant");
  85   assert(len > 0, "invariant");
  86   assert(pos != NULL, "invariant");
  87   return _compressed_integers ? IE::write(value, len, pos) : BE::write(value, len, pos);
  88 }
  89 
  90 template <typename BE, typename IE, typename WriterPolicyImpl>
  91 void WriterHost<BE, IE, WriterPolicyImpl>::write_utf8(const char* value) {
  92   if (NULL == value) {
  93     // only write encoding byte indicating NULL string
  94     write<u1>(NULL_STRING);
  95     return;
  96   }
  97   write<u1>(UTF8); // designate encoding
  98   const jint len = MIN2<jint>(max_jint, (jint)strlen(value));
  99   write(len);
 100   if (len > 0) {
 101     be_write(value, len);
 102   }
 103 }
 104 
 105 template <typename BE, typename IE, typename WriterPolicyImpl>
 106 void WriterHost<BE, IE, WriterPolicyImpl>::write_utf16(const jchar* value, jint len) {
 107   assert(value != NULL, "invariant");
 108   write((u1)UTF16); // designate encoding
 109   write(len);
 110   if (len > 0) {
 111     write(value, len);
 112   }
 113 }
 114 
 115 template <typename BE, typename IE, typename WriterPolicyImpl >
 116 template <typename T>
 117 inline void WriterHost<BE, IE, WriterPolicyImpl>::be_write(T value) {
 118   u1* const pos = ensure_size(sizeof(T));
 119   if (pos) {
 120     this->set_current_pos(BE::be_write(&value, 1, pos));
 121   }
 122 }
 123 
 124 template <typename BE, typename IE, typename WriterPolicyImpl >
 125 template <typename T>
 126 inline void WriterHost<BE, IE, WriterPolicyImpl>::be_write(const T* value, size_t len) {
 127   assert(value != NULL, "invariant");
 128   assert(len > 0, "invariant");
 129   u1* const pos = ensure_size(sizeof(T) * len);
 130   if (pos) {
 131     this->set_current_pos(BE::be_write(value, len, pos));
 132   }
 133 }
 134 
 135 template <typename BE, typename IE, typename WriterPolicyImpl >
 136 template <typename StorageType>
 137 inline WriterHost<BE, IE, WriterPolicyImpl>::WriterHost(StorageType* storage, Thread* thread) :
 138   WriterPolicyImpl(storage, thread),
 139   _compressed_integers(compressed_integers()) {
 140 }
 141 
 142 template <typename BE, typename IE, typename WriterPolicyImpl >
 143 template <typename StorageType>
 144 inline WriterHost<BE, IE, WriterPolicyImpl>::WriterHost(StorageType* storage, size_t size) :
 145   WriterPolicyImpl(storage, size),
 146   _compressed_integers(compressed_integers()) {
 147 }
 148 
 149 template <typename BE, typename IE, typename WriterPolicyImpl >
 150 inline WriterHost<BE, IE, WriterPolicyImpl>::WriterHost(Thread* thread) :
 151   WriterPolicyImpl(thread),
 152   _compressed_integers(compressed_integers()) {
 153 }
 154 
 155 // Extra size added as a safety cushion when dimensioning memory.
 156 // With varint encoding, the worst case is
 157 // associated with writing negative values.
 158 // For example, writing a negative s1 (-1)
 159 // will encode as 0xff 0x0f (2 bytes).
 160 // In this example, the sizeof(T) == 1 and length == 1,
 161 // but the implementation will need to dimension
 162 // 2 bytes for the encoding.
 163 // Hopefully, negative values should be relatively rare.
 164 static const size_t size_safety_cushion = 1;
 165 
 166 template <typename BE, typename IE, typename WriterPolicyImpl>
 167 inline u1* WriterHost<BE, IE, WriterPolicyImpl>::ensure_size(size_t requested) {
 168   if (!this->is_valid()) {
 169     // cancelled
 170     return NULL;
 171   }
 172   if (this->available_size() < requested + size_safety_cushion) {
 173     if (!this->accommodate(this->used_size(), requested + size_safety_cushion)) {
 174       this->cancel();
 175       return NULL;
 176     }
 177   }
 178   assert(requested + size_safety_cushion <= this->available_size(), "invariant");
 179   return this->current_pos();
 180 }
 181 
 182 template <typename BE, typename IE, typename WriterPolicyImpl>
 183 template <typename T>
 184 inline void WriterHost<BE, IE, WriterPolicyImpl>::write(T value) {
 185   write(&value, 1);
 186 }
 187 
 188 template <typename BE, typename IE, typename WriterPolicyImpl>
 189 inline void WriterHost<BE, IE, WriterPolicyImpl>::write(bool value) {
 190   be_write((u1)value);
 191 }
 192 
 193 template <typename BE, typename IE, typename WriterPolicyImpl>
 194 inline void WriterHost<BE, IE, WriterPolicyImpl>::write(float value) {
 195   be_write(*(u4*)&(value));
 196 }
 197 
 198 template <typename BE, typename IE, typename WriterPolicyImpl>
 199 inline void WriterHost<BE, IE, WriterPolicyImpl>::write(double value) {
 200   be_write(*(uintptr_t*)&(value));
 201 }
 202 
 203 template <typename BE, typename IE, typename WriterPolicyImpl>
 204 inline void WriterHost<BE, IE, WriterPolicyImpl>::write(const char* value) {
 205   // UTF-8, max_jint len
 206   write_utf8(value);
 207 }
 208 
 209 template <typename BE, typename IE, typename WriterPolicyImpl>
 210 inline void WriterHost<BE, IE, WriterPolicyImpl>::write(char* value) {
 211   write(const_cast<const char*>(value));
 212 }
 213 
 214 template <typename BE, typename IE, typename WriterPolicyImpl>
 215 inline void WriterHost<BE, IE, WriterPolicyImpl>::write(jstring string) {
 216   if (string == NULL) {
 217     write<u1>(NULL_STRING);
 218     return;
 219   }
 220   const oop string_oop = JNIHandles::resolve_external_guard(string);
 221   assert(string_oop != NULL, "invariant");
 222   const size_t length = (size_t)java_lang_String::length(string_oop);
 223   if (0 == length) {
 224     write<u1>(EMPTY_STRING);
 225     return;
 226   }
 227   const typeArrayOop value = java_lang_String::value(string_oop);
 228   assert(value != NULL, "invariant");
 229   write<u1>(UTF16);
 230   write<u4>((u4)length);
 231   write(value->char_at_addr(0), length);
 232 }
 233 
 234 template <typename Writer, typename T>
 235 inline void tag_write(Writer* w, const T* t) {
 236   assert(w != NULL, "invariant");
 237   const traceid id = t == NULL ? 0 : JfrTraceId::use(t);
 238   w->write(id);
 239 }
 240 
 241 template <typename BE, typename IE, typename WriterPolicyImpl>
 242 void WriterHost<BE, IE, WriterPolicyImpl>::write(const ClassLoaderData* cld) {
 243   tag_write(this, cld);
 244 }
 245 
 246 template <typename BE, typename IE, typename WriterPolicyImpl>
 247 void WriterHost<BE, IE, WriterPolicyImpl>::write(const Klass* klass) {
 248   tag_write(this, klass);
 249 }
 250 
 251 template <typename BE, typename IE, typename WriterPolicyImpl>
 252 void WriterHost<BE, IE, WriterPolicyImpl>::write(const Method* method) {
 253   tag_write(this, method);
 254 }
 255 
 256 template <typename BE, typename IE, typename WriterPolicyImpl>
 257 void WriterHost<BE, IE, WriterPolicyImpl>::write(const Symbol* symbol) {
 258   ResourceMark rm;
 259   write_utf8(symbol != NULL ? symbol->as_C_string() : NULL);
 260 }
 261 
 262 template <typename BE, typename IE, typename WriterPolicyImpl>
 263 void WriterHost<BE, IE, WriterPolicyImpl>::write(const Ticks& time) {
 264   write((uintptr_t)JfrTraceTime::is_ft_enabled() ? time.ft_value() : time.value());
 265 }
 266 
 267 template <typename BE, typename IE, typename WriterPolicyImpl>
 268 void WriterHost<BE, IE, WriterPolicyImpl>::write(const Tickspan& time) {
 269   write((uintptr_t)JfrTraceTime::is_ft_enabled() ? time.ft_value() : time.value());
 270 }
 271 
 272 template <typename BE, typename IE, typename WriterPolicyImpl>
 273 void WriterHost<BE, IE, WriterPolicyImpl>::bytes(const void* buf, size_t len) {
 274   u1* const pos = this->ensure_size(len);
 275   if (pos != NULL) {
 276     WriterPolicyImpl::bytes(pos, buf, len); // WriterPolicyImpl responsible for position update
 277   }
 278 }
 279 
 280 // UTF-8 for use with classfile/bytecodes
 281 template <typename BE, typename IE, typename WriterPolicyImpl>
 282 inline void WriterHost<BE, IE, WriterPolicyImpl>::write_utf8_u2_len(const char* value) {
 283   u2 len = 0;
 284   if (value != NULL) {
 285     len = MIN2<u2>(max_jushort, (u2)strlen(value));
 286   }
 287   write(len);
 288   if (len > 0) {
 289     be_write(value, len);
 290   }
 291 }
 292 
 293 template <typename BE, typename IE, typename WriterPolicyImpl>
 294 inline intptr_t WriterHost<BE, IE, WriterPolicyImpl>::reserve(size_t size) {
 295   if (ensure_size(size) != NULL) {
 296     intptr_t reserved_offset = this->current_offset();
 297     this->set_current_pos(size);
 298     return reserved_offset;
 299   }
 300   this->cancel();
 301   return 0;
 302 }
 303 
 304 template <typename BE, typename IE, typename WriterPolicyImpl>
 305 template <typename T>
 306 inline void WriterHost<BE, IE, WriterPolicyImpl>::write_padded_at_offset(T value, intptr_t offset) {
 307   if (this->is_valid()) {
 308     const intptr_t current = this->current_offset();
 309     this->seek(offset);
 310     write_padded(value);
 311     this->seek(current); // restore
 312   }
 313 }
 314 
 315 template <typename BE, typename IE, typename WriterPolicyImpl>
 316 template <typename T>
 317 inline void WriterHost<BE, IE, WriterPolicyImpl>::write_at_offset(T value, intptr_t offset) {
 318   if (this->is_valid()) {
 319     const intptr_t current = this->current_offset();
 320     this->seek(offset);
 321     write(value);
 322     this->seek(current); // restore
 323   }
 324 }
 325 
 326 template <typename BE, typename IE, typename WriterPolicyImpl>
 327 template <typename T>
 328 inline void WriterHost<BE, IE, WriterPolicyImpl>::write_be_at_offset(T value, intptr_t offset) {
 329   if (this->is_valid()) {
 330     const intptr_t current = this->current_offset();
 331     this->seek(offset);
 332     be_write(value);
 333     this->seek(current); // restore
 334   }
 335 }
 336 
 337 #endif // SHARE_VM_JFR_WRITERS_JFRWRITERHOST_INLINE_HPP
 338