xref: /third_party/node/src/node_mem-inl.h (revision 1cb0ef41)
1#ifndef SRC_NODE_MEM_INL_H_
2#define SRC_NODE_MEM_INL_H_
3
4#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5
6#include "node_mem.h"
7#include "node_internals.h"
8
9namespace node {
10namespace mem {
11
12template <typename Class, typename AllocatorStruct>
13AllocatorStruct NgLibMemoryManager<Class, AllocatorStruct>::MakeAllocator() {
14  return AllocatorStruct {
15    static_cast<void*>(static_cast<Class*>(this)),
16    MallocImpl,
17    FreeImpl,
18    CallocImpl,
19    ReallocImpl
20  };
21}
22
23template <typename Class, typename T>
24void* NgLibMemoryManager<Class, T>::ReallocImpl(void* ptr,
25                                             size_t size,
26                                             void* user_data) {
27  Class* manager = static_cast<Class*>(user_data);
28
29  size_t previous_size = 0;
30  char* original_ptr = nullptr;
31
32  // We prepend each allocated buffer with a size_t containing the full
33  // size of the allocation.
34  if (size > 0) size += sizeof(size_t);
35
36  if (ptr != nullptr) {
37    // We are free()ing or re-allocating.
38    original_ptr = static_cast<char*>(ptr) - sizeof(size_t);
39    previous_size = *reinterpret_cast<size_t*>(original_ptr);
40    // This means we called StopTracking() on this pointer before.
41    if (previous_size == 0) {
42      // Fall back to the standard Realloc() function.
43      char* ret = UncheckedRealloc(original_ptr, size);
44      if (ret != nullptr)
45        ret += sizeof(size_t);
46      return ret;
47    }
48  }
49
50  manager->CheckAllocatedSize(previous_size);
51
52  char* mem = UncheckedRealloc(original_ptr, size);
53
54  if (mem != nullptr) {
55    // Adjust the memory info counter.
56    // TODO(addaleax): Avoid the double bookkeeping we do with
57    // current_nghttp2_memory_ + AdjustAmountOfExternalAllocatedMemory
58    // and provide versions of our memory allocation utilities that take an
59    // Environment*/Isolate* parameter and call the V8 method transparently.
60    const int64_t new_size = size - previous_size;
61    manager->IncreaseAllocatedSize(new_size);
62    manager->env()->isolate()->AdjustAmountOfExternalAllocatedMemory(
63        new_size);
64    *reinterpret_cast<size_t*>(mem) = size;
65    mem += sizeof(size_t);
66  } else if (size == 0) {
67    manager->DecreaseAllocatedSize(previous_size);
68    manager->env()->isolate()->AdjustAmountOfExternalAllocatedMemory(
69        -static_cast<int64_t>(previous_size));
70  }
71  return mem;
72}
73
74template <typename Class, typename T>
75void* NgLibMemoryManager<Class, T>::MallocImpl(size_t size, void* user_data) {
76  return ReallocImpl(nullptr, size, user_data);
77}
78
79template <typename Class, typename T>
80void NgLibMemoryManager<Class, T>::FreeImpl(void* ptr, void* user_data) {
81  if (ptr == nullptr) return;
82  CHECK_NULL(ReallocImpl(ptr, 0, user_data));
83}
84
85template <typename Class, typename T>
86void* NgLibMemoryManager<Class, T>::CallocImpl(size_t nmemb,
87                                            size_t size,
88                                            void* user_data) {
89  size_t real_size = MultiplyWithOverflowCheck(nmemb, size);
90  void* mem = MallocImpl(real_size, user_data);
91  if (mem != nullptr)
92    memset(mem, 0, real_size);
93  return mem;
94}
95
96template <typename Class, typename T>
97void NgLibMemoryManager<Class, T>::StopTrackingMemory(void* ptr) {
98  size_t* original_ptr = reinterpret_cast<size_t*>(
99      static_cast<char*>(ptr) - sizeof(size_t));
100  Class* manager = static_cast<Class*>(this);
101  manager->DecreaseAllocatedSize(*original_ptr);
102  manager->env()->isolate()->AdjustAmountOfExternalAllocatedMemory(
103      -static_cast<int64_t>(*original_ptr));
104  *original_ptr = 0;
105}
106
107}  // namespace mem
108}  // namespace node
109
110#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
111
112#endif  // SRC_NODE_MEM_INL_H_
113