1 /*
   2  * Copyright (c) 2014, 2015, Dynatrace and/or its affiliates. All rights reserved.
   3  *
   4  * This file is part of the Lock Contention Tracing Subsystem for the HotSpot
   5  * Virtual Machine, which is developed at Christian Doppler Laboratory on
   6  * Monitoring and Evolution of Very-Large-Scale Software Systems. Please
   7  * contact us at <http://mevss.jku.at/> if you need additional information
   8  * or have any questions.
   9  *
  10  * This code is free software; you can redistribute it and/or modify it
  11  * under the terms of the GNU General Public License version 2 only, as
  12  * published by the Free Software Foundation.
  13  *
  14  * This code is distributed in the hope that it will be useful, but WITHOUT
  15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  17  * version 2 for more details (a copy is included in the LICENSE file that
  18  * accompanied this code).
  19  *
  20  * You should have received a copy of the GNU General Public License version
  21  * 2 along with this work. If not, see <http://www.gnu.org/licenses/>.
  22  *
  23  */
  24 
  25 #ifndef SHARE_VM_EVTRACE_TRACEWRITER_INLINE_HPP
  26 #define SHARE_VM_EVTRACE_TRACEWRITER_INLINE_HPP
  27 
  28 #include "evtrace/traceBuffer.hpp"
  29 #include "evtrace/traceManager.hpp"
  30 
  31 //
  32 // TraceWriterBase
  33 //
  34 
  35 inline TraceWriterBase::TraceWriterBase(size_t nbytes)
  36 : _writer_top(NULL),
  37   _nsv(true, false)
  38 {
  39   assert(!SafepointSynchronize::is_at_safepoint() || Thread::current()->is_VM_thread(),
  40       "only the VM thread may write events during a safepoint");
  41   assert(!Thread::current()->trace_active(), "tracing already in use");
  42   debug_only(Thread::current()->toggle_trace_active();)
  43   reserve(nbytes);
  44 }
  45 
  46 inline TraceWriterBase::~TraceWriterBase() {
  47   assert(_writer_top == NULL || Thread::current()->trace_buffer() == NULL
  48       || _writer_top == Thread::current()->trace_buffer()->top,
  49       "must have used up reserved space");
  50   assert(Thread::current()->trace_active(), "tracing must be active");
  51   debug_only(Thread::current()->toggle_trace_active();)
  52 }
  53 
  54 inline void TraceWriterBase::assert_reserved(size_t nbytes) {
  55   assert(_writer_top != NULL, "no space reserved");
  56   assert(Thread::current()->trace_buffer() != NULL, "thread has no trace buffer");
  57   assert(_writer_top + nbytes <= Thread::current()->trace_buffer()->top, "not enough space reserved");
  58 }
  59 
  60 inline void TraceWriterBase::reserve(size_t nbytes) {
  61   if (!TraceManager::is_initialized()) {
  62     assert(_writer_top == NULL, "have pointer into buffer, but tracing is not initialized");
  63     return;
  64   }
  65 
  66   assert(_writer_top == NULL || Thread::current()->trace_buffer() == NULL
  67       || _writer_top == Thread::current()->trace_buffer()->top,
  68       "must finish writing before reserving more space");
  69 
  70   // NOTE: our No_Safepoint_Verifier ensures that no safepoint can happen
  71   // between submitting/requesting a buffer and setting it as the thread's
  72   // trace buffer
  73 
  74   TraceBuffer *buf = Thread::current()->trace_buffer();
  75   if (buf != NULL) {
  76     _writer_top = buf->top;
  77     if (!buf->reserve(nbytes)) {
  78       // does not fit
  79       _writer_top = NULL;
  80       TraceManager::submit_buffer(Thread::current()->trace_buffer());
  81       Thread::current()->set_trace_buffer(NULL);
  82       buf = NULL;
  83     }
  84   }
  85   if (buf == NULL && TraceManager::is_initialized()) {
  86     buf = TraceManager::request_buffer();
  87     buf->owner = Thread::current();
  88     _writer_top = buf->top;
  89     guarantee(buf->reserve(nbytes), "newly requested buffer does not fit the event");
  90     Thread::current()->set_trace_buffer(buf);
  91   }
  92 }
  93 
  94 inline void TraceWriterBase::put_u1(u1 v) {
  95   assert_reserved(1);
  96   *_writer_top++ = v;
  97 }
  98 
  99 inline void TraceWriterBase::put_u2(u2 v) {
 100   assert_reserved(2);
 101   *(u2 *) _writer_top = v;
 102   _writer_top += 2;
 103 }
 104 
 105 inline void TraceWriterBase::put_u4(u4 v) {
 106   assert_reserved(4);
 107   *(u4 *) _writer_top = v;
 108   _writer_top += 4;
 109 }
 110 
 111 inline void TraceWriterBase::put_u8(u8 v) {
 112   assert_reserved(8);
 113   *(u8 *) _writer_top = v;
 114   _writer_top += 8;
 115 }
 116 
 117 inline void TraceWriterBase::put_s4(s4 v) {
 118   assert_reserved(4);
 119   *(s4 *) _writer_top = v;
 120   _writer_top += 4;
 121 }
 122 
 123 inline void TraceWriterBase::put_s8(s8 v) {
 124   assert_reserved(8);
 125   *(s8 *) _writer_top = v;
 126   _writer_top += 8;
 127 }
 128 
 129 inline void TraceWriterBase::put_data(void *data, size_t length) {
 130   assert_reserved(length);
 131   memcpy(_writer_top, data, length);
 132   _writer_top += length;
 133 }
 134 
 135 inline void TraceWriterBase::put_utf8str(const char *s, size_t bytes) {
 136   assert_reserved(bytes);
 137 
 138   assert(bytes > 2, "invalid length");
 139   bytes -= 2;
 140   assert(bytes == (size_t) ((s2) bytes), "string length must fit in u2");
 141   *(s2 *) _writer_top = (s2) bytes;
 142   _writer_top += 2;
 143   if (s != NULL) {
 144     memcpy(_writer_top, s, bytes);
 145     _writer_top += bytes;
 146   }
 147 }
 148 
 149 inline size_t TraceWriterBase::nbytes_for_utf8str(const char* s, size_t maxbytes) {
 150   assert(s != NULL, "null string");
 151 
 152   size_t nbytes = 0;
 153   if (s != NULL) {
 154     jchar c;
 155     const char *end = s + maxbytes;
 156     for (;;) {
 157       const char *q = s;
 158       s = UTF8::next(s, &c);
 159       if (c == 0 || s >= end) {
 160         break;
 161       }
 162       nbytes += (size_t) (s - q);
 163     }
 164     assert(nbytes == (u2) nbytes, "string length must fit in u2");
 165   }
 166   nbytes += 2; // for u2 with length
 167   return nbytes;
 168 }
 169 
 170 #endif /* SHARE_VM_EVTRACE_TRACEWRITER_INLINE_HPP */