src/hotspot/share/jfr/writers/jfrStorageAdapter.hpp
changeset 50113 caf115bb98ad
child 53244 9807daeb47c4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrStorageAdapter.hpp	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_WRITERS_JFRSTORAGEADAPTER_HPP
+#define SHARE_VM_JFR_WRITERS_JFRSTORAGEADAPTER_HPP
+
+#include "jfr/utilities/jfrAllocation.hpp"
+
+class Thread;
+
+//
+// The adapters present writers with a uniform interface over storage.
+//
+// Adapter policy
+//
+// StorageType* storage();
+// const u1* start() const;
+// const u1* pos();
+// const u1* end() const;
+// void commit(u1* position);
+// bool flush(size_t used, size_t requested);
+// void release();
+//
+
+template <typename Flush>
+class Adapter {
+ public:
+  typedef typename Flush::Type StorageType;
+  Adapter(StorageType* storage, Thread* thread) : _storage(storage), _thread(thread) {}
+  Adapter(Thread* thread) : _storage(NULL), _thread(thread) {}
+
+  void set_storage(StorageType* storage) {
+    _storage = storage;
+  }
+
+  StorageType* storage() {
+    return _storage;
+  }
+
+  const u1* start() const {
+    assert(_storage != NULL, "invariant");
+    return _storage->start();
+  }
+
+  u1* pos() {
+    assert(_storage != NULL, "invariant");
+    return _storage->pos();
+  }
+
+  const u1* end() const {
+    assert(_storage != NULL, "invariant");
+    return _storage->end();
+  }
+
+  void commit(u1* position) {
+    assert(_storage != NULL, "invariant");
+    _storage->set_pos(position);
+  }
+
+  bool flush(size_t used, size_t requested) {
+    assert(_thread != NULL, "invariant");
+    Flush f(_storage, used, requested, _thread);
+    _storage = f.result();
+    return _storage != NULL;
+  }
+
+  void release() {
+    if (_storage != NULL && _storage->lease()) {
+      // This flush call will return the lease
+      // of a temporary storage area.
+      // Since the requested size is 0,
+      // the flush implementation will accomodate
+      // that 'size' request in the
+      // original thread local storage,
+      // by implication restoring the original
+      // in the process of returning a lease.
+      flush(0, 0);
+    }
+  }
+
+ private:
+  StorageType* _storage;
+  Thread* _thread;
+};
+
+template <size_t DEFAULT_SIZE = K>
+class MallocAdapter {
+ private:
+  u1* _start;
+  u1* _pos;
+  u1* _end;
+  size_t _initial_size;
+  bool _has_ownership;
+
+  bool allocate(size_t size);
+  void deallocate();
+
+ public:
+  typedef u1 StorageType;
+  MallocAdapter(u1* storage, Thread* thread);
+  MallocAdapter(u1* storage, size_t size);
+  MallocAdapter(Thread* thread);
+  ~MallocAdapter();
+
+  StorageType* storage() { return _start; }
+  const u1* start() const { return _start; }
+  u1* pos() { return _pos; }
+  void commit(u1* position) { _pos = position; }
+  const u1* end() const { return _end; }
+  void release() {}
+  bool flush(size_t used, size_t requested);
+};
+
+template <size_t DEFAULT_SIZE>
+MallocAdapter<DEFAULT_SIZE>::MallocAdapter(u1* storage, size_t size) :
+  _start(storage),
+  _pos(storage),
+  _end(storage + size),
+  _initial_size(size),
+  _has_ownership(false) {
+}
+
+template <size_t DEFAULT_SIZE>
+MallocAdapter<DEFAULT_SIZE> ::MallocAdapter(u1* storage, Thread* thread) :
+  _start(storage),
+  _pos(storage),
+  _end(storage),
+  _initial_size(0),
+  _has_ownership(false) {
+}
+
+template <size_t DEFAULT_SIZE>
+MallocAdapter<DEFAULT_SIZE>::MallocAdapter(Thread* thread) :
+  _start(NULL),
+  _pos(NULL),
+  _end(NULL),
+  _initial_size(DEFAULT_SIZE),
+  _has_ownership(true) {
+  allocate(DEFAULT_SIZE);
+}
+
+template <size_t DEFAULT_SIZE>
+MallocAdapter<DEFAULT_SIZE>::~MallocAdapter() {
+  if (_has_ownership) {
+    deallocate();
+  }
+}
+
+template <size_t DEFAULT_SIZE>
+bool MallocAdapter<DEFAULT_SIZE>::allocate(size_t size) {
+  if (NULL == _start) {
+    _start = JfrCHeapObj::new_array<u1>(size);
+    if (_start) {
+      _pos = _start;
+      _end = _start + size;
+      _initial_size = size;
+    }
+  }
+  return _start != NULL;
+}
+
+template <size_t DEFAULT_SIZE>
+void MallocAdapter<DEFAULT_SIZE>::deallocate() {
+  if (_start != NULL) {
+    JfrCHeapObj::free(_start, (size_t)(_end - _start));
+  }
+}
+
+template <size_t DEFAULT_SIZE>
+bool MallocAdapter<DEFAULT_SIZE>::flush(size_t used, size_t requested) {
+  if (!_has_ownership) {
+    // can't just realloc a storage that we don't own
+    return false;
+  }
+  assert(_start != NULL, "invariant");
+  assert(used <= (size_t)(_end - _pos), "invariant");
+  assert(_pos + used <= _end, "invariant");
+  const size_t previous_storage_size = _end - _start;
+  const size_t new_storage_size = used + requested + (previous_storage_size * 2);
+  u1* const new_storage = JfrCHeapObj::new_array<u1>(new_storage_size);
+  if (!new_storage) {
+    return false;
+  }
+  const size_t previous_pos_offset = _pos - _start;
+  // migrate in-flight data
+  memcpy(new_storage, _start, previous_pos_offset + used);
+  JfrCHeapObj::free(_start, previous_storage_size);
+  _start = new_storage;
+  _pos = _start + previous_pos_offset;
+  _end = _start + new_storage_size;
+  return true;
+}
+
+class NoOwnershipAdapter {
+ private:
+  u1* _start;
+  u1* _pos;
+  u1* _end;
+  size_t _size;
+
+ public:
+  typedef u1 StorageType;
+  NoOwnershipAdapter(u1* storage, size_t size) : _start(storage), _pos(storage), _end(storage + size), _size(size) {}
+  NoOwnershipAdapter(u1* storage, Thread* thread) : _start(storage), _pos(storage), _end(storage), _size(0) {
+    ShouldNotCallThis();
+  }
+  NoOwnershipAdapter(Thread* thread) : _start(NULL), _pos(NULL), _end(NULL), _size(0) {
+    ShouldNotCallThis();
+  }
+  StorageType* storage() { return _start; }
+  const u1* start() const { return _start; }
+  u1* pos() { return _pos; }
+  void commit(u1* position) { _pos = position; }
+  const u1* end() const { return _end; }
+  void release() {}
+  bool flush(size_t used, size_t requested) {
+    // don't flush/expand a buffer that is not our own
+    return false;
+  }
+};
+
+#endif // SHARE_VM_JFR_WRITERS_JFRSTORAGEADAPTER_HPP