1 /*
   2  * Copyright (c) 2016, 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_JFRSTORAGEADAPTER_HPP
  26 #define SHARE_VM_JFR_WRITERS_JFRSTORAGEADAPTER_HPP
  27 
  28 #include "jfr/utilities/jfrAllocation.hpp"
  29 
  30 class Thread;
  31 
  32 //
  33 // The adapters present writers with a uniform interface over storage.
  34 //
  35 // Adapter policy
  36 //
  37 // StorageType* storage();
  38 // const u1* start() const;
  39 // const u1* pos();
  40 // const u1* end() const;
  41 // void commit(u1* position);
  42 // bool flush(size_t used, size_t requested);
  43 // void release();
  44 //
  45 
  46 template <typename Flush>
  47 class Adapter {
  48  public:
  49   typedef typename Flush::Type StorageType;
  50   Adapter(StorageType* storage, Thread* thread) : _storage(storage), _thread(thread) {}
  51   Adapter(Thread* thread) : _storage(NULL), _thread(thread) {}
  52 
  53   void set_storage(StorageType* storage) {
  54     _storage = storage;
  55   }
  56 
  57   StorageType* storage() {
  58     return _storage;
  59   }
  60 
  61   const u1* start() const {
  62     assert(_storage != NULL, "invariant");
  63     return _storage->start();
  64   }
  65 
  66   u1* pos() {
  67     assert(_storage != NULL, "invariant");
  68     return _storage->pos();
  69   }
  70 
  71   const u1* end() const {
  72     assert(_storage != NULL, "invariant");
  73     return _storage->end();
  74   }
  75 
  76   void commit(u1* position) {
  77     assert(_storage != NULL, "invariant");
  78     _storage->set_pos(position);
  79   }
  80 
  81   bool flush(size_t used, size_t requested) {
  82     assert(_thread != NULL, "invariant");
  83     Flush f(_storage, used, requested, _thread);
  84     _storage = f.result();
  85     return _storage != NULL;
  86   }
  87 
  88   void release() {
  89     if (_storage != NULL && _storage->lease()) {
  90       // This flush call will return the lease
  91       // of a temporary storage area.
  92       // Since the requested size is 0,
  93       // the flush implementation will accomodate
  94       // that 'size' request in the
  95       // original thread local storage,
  96       // by implication restoring the original
  97       // in the process of returning a lease.
  98       flush(0, 0);
  99     }
 100   }
 101 
 102  private:
 103   StorageType* _storage;
 104   Thread* _thread;
 105 };
 106 
 107 template <size_t DEFAULT_SIZE = K>
 108 class MallocAdapter {
 109  private:
 110   u1* _start;
 111   u1* _pos;
 112   u1* _end;
 113   size_t _initial_size;
 114   bool _has_ownership;
 115 
 116   bool allocate(size_t size);
 117   void deallocate();
 118 
 119  public:
 120   typedef u1 StorageType;
 121   MallocAdapter(u1* storage, Thread* thread);
 122   MallocAdapter(u1* storage, size_t size);
 123   MallocAdapter(Thread* thread);
 124   ~MallocAdapter();
 125 
 126   StorageType* storage() { return _start; }
 127   const u1* start() const { return _start; }
 128   u1* pos() { return _pos; }
 129   void commit(u1* position) { _pos = position; }
 130   const u1* end() const { return _end; }
 131   void release() {}
 132   bool flush(size_t used, size_t requested);
 133 };
 134 
 135 template <size_t DEFAULT_SIZE>
 136 MallocAdapter<DEFAULT_SIZE>::MallocAdapter(u1* storage, size_t size) :
 137   _start(storage),
 138   _pos(storage),
 139   _end(storage + size),
 140   _initial_size(size),
 141   _has_ownership(false) {
 142 }
 143 
 144 template <size_t DEFAULT_SIZE>
 145 MallocAdapter<DEFAULT_SIZE> ::MallocAdapter(u1* storage, Thread* thread) :
 146   _start(storage),
 147   _pos(storage),
 148   _end(storage),
 149   _initial_size(0),
 150   _has_ownership(false) {
 151 }
 152 
 153 template <size_t DEFAULT_SIZE>
 154 MallocAdapter<DEFAULT_SIZE>::MallocAdapter(Thread* thread) :
 155   _start(NULL),
 156   _pos(NULL),
 157   _end(NULL),
 158   _initial_size(DEFAULT_SIZE),
 159   _has_ownership(true) {
 160   allocate(DEFAULT_SIZE);
 161 }
 162 
 163 template <size_t DEFAULT_SIZE>
 164 MallocAdapter<DEFAULT_SIZE>::~MallocAdapter() {
 165   if (_has_ownership) {
 166     deallocate();
 167   }
 168 }
 169 
 170 template <size_t DEFAULT_SIZE>
 171 bool MallocAdapter<DEFAULT_SIZE>::allocate(size_t size) {
 172   if (NULL == _start) {
 173     _start = JfrCHeapObj::new_array<u1>(size);
 174     if (_start) {
 175       _pos = _start;
 176       _end = _start + size;
 177       _initial_size = size;
 178     }
 179   }
 180   return _start != NULL;
 181 }
 182 
 183 template <size_t DEFAULT_SIZE>
 184 void MallocAdapter<DEFAULT_SIZE>::deallocate() {
 185   if (_start != NULL) {
 186     JfrCHeapObj::free(_start, (size_t)(_end - _start));
 187   }
 188 }
 189 
 190 template <size_t DEFAULT_SIZE>
 191 bool MallocAdapter<DEFAULT_SIZE>::flush(size_t used, size_t requested) {
 192   if (!_has_ownership) {
 193     // can't just realloc a storage that we don't own
 194     return false;
 195   }
 196   assert(_start != NULL, "invariant");
 197   assert(used <= (size_t)(_end - _pos), "invariant");
 198   assert(_pos + used <= _end, "invariant");
 199   const size_t previous_storage_size = _end - _start;
 200   const size_t new_storage_size = used + requested + (previous_storage_size * 2);
 201   u1* const new_storage = JfrCHeapObj::new_array<u1>(new_storage_size);
 202   if (!new_storage) {
 203     return false;
 204   }
 205   const size_t previous_pos_offset = _pos - _start;
 206   // migrate in-flight data
 207   memcpy(new_storage, _start, previous_pos_offset + used);
 208   JfrCHeapObj::free(_start, previous_storage_size);
 209   _start = new_storage;
 210   _pos = _start + previous_pos_offset;
 211   _end = _start + new_storage_size;
 212   return true;
 213 }
 214 
 215 class NoOwnershipAdapter {
 216  private:
 217   u1* _start;
 218   u1* _pos;
 219   u1* _end;
 220   size_t _size;
 221 
 222  public:
 223   typedef u1 StorageType;
 224   NoOwnershipAdapter(u1* storage, size_t size) : _start(storage), _pos(storage), _end(storage + size), _size(size) {}
 225   NoOwnershipAdapter(u1* storage, Thread* thread) : _start(storage), _pos(storage), _end(storage), _size(0) {
 226     ShouldNotCallThis();
 227   }
 228   NoOwnershipAdapter(Thread* thread) : _start(NULL), _pos(NULL), _end(NULL), _size(0) {
 229     ShouldNotCallThis();
 230   }
 231   StorageType* storage() { return _start; }
 232   const u1* start() const { return _start; }
 233   u1* pos() { return _pos; }
 234   void commit(u1* position) { _pos = position; }
 235   const u1* end() const { return _end; }
 236   void release() {}
 237   bool flush(size_t used, size_t requested) {
 238     // don't flush/expand a buffer that is not our own
 239     return false;
 240   }
 241 };
 242 
 243 #endif // SHARE_VM_JFR_WRITERS_JFRSTORAGEADAPTER_HPP