summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2019-12-01 01:30:40 +0100
committerAnna Henningsen <anna@addaleax.net>2019-12-07 22:55:17 +0100
commit1e5911d5a3c35672941f2dcad6b9a95efa367404 (patch)
tree2013cb6ae236576f9578da1e719f059258f17756 /src
parent4e119202512c16abdc9e97b87bae73cc6353b575 (diff)
downloadandroid-node-v8-1e5911d5a3c35672941f2dcad6b9a95efa367404.tar.gz
android-node-v8-1e5911d5a3c35672941f2dcad6b9a95efa367404.tar.bz2
android-node-v8-1e5911d5a3c35672941f2dcad6b9a95efa367404.zip
src: port memory-tracking allocator from QUIC repo
This implements a memory-tracking allocator that can be used to provide memory allocation facilities to several thread-safe C libraries, including nghttp2, nghttp3, ngtcp3 and uvwasi. Refs: https://github.com/nodejs/quic/blob/34ee0bc96f804c73cb22b2945a1a78f780938492/src/node_mem.h Co-authored-by: James M Snell <jasnell@gmail.com> PR-URL: https://github.com/nodejs/node/pull/30745 Refs: https://github.com/nodejs/quic/pull/126 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/node_mem-inl.h112
-rw-r--r--src/node_mem.h41
2 files changed, 153 insertions, 0 deletions
diff --git a/src/node_mem-inl.h b/src/node_mem-inl.h
new file mode 100644
index 0000000000..ad6fc45b36
--- /dev/null
+++ b/src/node_mem-inl.h
@@ -0,0 +1,112 @@
+#ifndef SRC_NODE_MEM_INL_H_
+#define SRC_NODE_MEM_INL_H_
+
+#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
+
+#include "node_mem.h"
+#include "node_internals.h"
+
+namespace node {
+namespace mem {
+
+template <typename Class, typename AllocatorStruct>
+AllocatorStruct NgLibMemoryManager<Class, AllocatorStruct>::MakeAllocator() {
+ return AllocatorStruct {
+ static_cast<void*>(static_cast<Class*>(this)),
+ MallocImpl,
+ FreeImpl,
+ CallocImpl,
+ ReallocImpl
+ };
+}
+
+template <typename Class, typename T>
+void* NgLibMemoryManager<Class, T>::ReallocImpl(void* ptr,
+ size_t size,
+ void* user_data) {
+ Class* manager = static_cast<Class*>(user_data);
+
+ size_t previous_size = 0;
+ char* original_ptr = nullptr;
+
+ // We prepend each allocated buffer with a size_t containing the full
+ // size of the allocation.
+ if (size > 0) size += sizeof(size_t);
+
+ if (ptr != nullptr) {
+ // We are free()ing or re-allocating.
+ original_ptr = static_cast<char*>(ptr) - sizeof(size_t);
+ previous_size = *reinterpret_cast<size_t*>(original_ptr);
+ // This means we called StopTracking() on this pointer before.
+ if (previous_size == 0) {
+ // Fall back to the standard Realloc() function.
+ char* ret = UncheckedRealloc(original_ptr, size);
+ if (ret != nullptr)
+ ret += sizeof(size_t);
+ return ret;
+ }
+ }
+
+ manager->CheckAllocatedSize(previous_size);
+
+ char* mem = UncheckedRealloc(original_ptr, size);
+
+ if (mem != nullptr) {
+ // Adjust the memory info counter.
+ // TODO(addaleax): Avoid the double bookkeeping we do with
+ // current_nghttp2_memory_ + AdjustAmountOfExternalAllocatedMemory
+ // and provide versions of our memory allocation utilities that take an
+ // Environment*/Isolate* parameter and call the V8 method transparently.
+ const int64_t new_size = size - previous_size;
+ manager->IncreaseAllocatedSize(new_size);
+ manager->env()->isolate()->AdjustAmountOfExternalAllocatedMemory(
+ new_size);
+ *reinterpret_cast<size_t*>(mem) = size;
+ mem += sizeof(size_t);
+ } else if (size == 0) {
+ manager->DecreaseAllocatedSize(previous_size);
+ manager->env()->isolate()->AdjustAmountOfExternalAllocatedMemory(
+ -static_cast<int64_t>(previous_size));
+ }
+ return mem;
+}
+
+template <typename Class, typename T>
+void* NgLibMemoryManager<Class, T>::MallocImpl(size_t size, void* user_data) {
+ return ReallocImpl(nullptr, size, user_data);
+}
+
+template <typename Class, typename T>
+void NgLibMemoryManager<Class, T>::FreeImpl(void* ptr, void* user_data) {
+ if (ptr == nullptr) return;
+ CHECK_NULL(ReallocImpl(ptr, 0, user_data));
+}
+
+template <typename Class, typename T>
+void* NgLibMemoryManager<Class, T>::CallocImpl(size_t nmemb,
+ size_t size,
+ void* user_data) {
+ size_t real_size = MultiplyWithOverflowCheck(nmemb, size);
+ void* mem = MallocImpl(real_size, user_data);
+ if (mem != nullptr)
+ memset(mem, 0, real_size);
+ return mem;
+}
+
+template <typename Class, typename T>
+void NgLibMemoryManager<Class, T>::StopTrackingMemory(void* ptr) {
+ size_t* original_ptr = reinterpret_cast<size_t*>(
+ static_cast<char*>(ptr) - sizeof(size_t));
+ Class* manager = static_cast<Class*>(this);
+ manager->DecreaseAllocatedSize(*original_ptr);
+ manager->env()->isolate()->AdjustAmountOfExternalAllocatedMemory(
+ -static_cast<int64_t>(*original_ptr));
+ *original_ptr = 0;
+}
+
+} // namespace mem
+} // namespace node
+
+#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
+
+#endif // SRC_NODE_MEM_INL_H_
diff --git a/src/node_mem.h b/src/node_mem.h
new file mode 100644
index 0000000000..0d3388ad47
--- /dev/null
+++ b/src/node_mem.h
@@ -0,0 +1,41 @@
+#ifndef SRC_NODE_MEM_H_
+#define SRC_NODE_MEM_H_
+
+#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
+
+#include <cstddef>
+
+namespace node {
+namespace mem {
+
+// Both ngtcp2 and nghttp2 allow custom allocators that
+// follow exactly the same structure and behavior, but
+// use different struct names. To allow for code re-use,
+// the NgLibMemoryManager template class can be used for both.
+
+template <typename Class, typename AllocatorStructName>
+class NgLibMemoryManager {
+ public:
+ // Class needs to provide these methods:
+ // void CheckAllocatedSize(size_t previous_size) const;
+ // void IncreaseAllocatedSize(size_t size);
+ // void DecreaseAllocatedSize(size_t size);
+ // Environment* env() const;
+
+ AllocatorStructName MakeAllocator();
+
+ void StopTrackingMemory(void* ptr);
+
+ private:
+ static void* ReallocImpl(void* ptr, size_t size, void* user_data);
+ static void* MallocImpl(size_t size, void* user_data);
+ static void FreeImpl(void* ptr, void* user_data);
+ static void* CallocImpl(size_t nmemb, size_t size, void* user_data);
+};
+
+} // namespace mem
+} // namespace node
+
+#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
+
+#endif // SRC_NODE_MEM_H_