summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--node.gyp2
-rw-r--r--src/node_mem-inl.h112
-rw-r--r--src/node_mem.h41
3 files changed, 155 insertions, 0 deletions
diff --git a/node.gyp b/node.gyp
index 0a6bbd6100..7b971b5739 100644
--- a/node.gyp
+++ b/node.gyp
@@ -627,6 +627,8 @@
'src/node_i18n.h',
'src/node_internals.h',
'src/node_main_instance.h',
+ 'src/node_mem.h',
+ 'src/node_mem-inl.h',
'src/node_messaging.h',
'src/node_metadata.h',
'src/node_mutex.h',
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_