Skip to content

Commit 041daaa

Browse files
addaleaxtargos
authored andcommitted
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 <[email protected]> PR-URL: #30745 Refs: nodejs/quic#126 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Rich Trott <[email protected]>
1 parent ccf0917 commit 041daaa

File tree

3 files changed

+155
-0
lines changed

3 files changed

+155
-0
lines changed

node.gyp

+2
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,8 @@
627627
'src/node_i18n.h',
628628
'src/node_internals.h',
629629
'src/node_main_instance.h',
630+
'src/node_mem.h',
631+
'src/node_mem-inl.h',
630632
'src/node_messaging.h',
631633
'src/node_metadata.h',
632634
'src/node_mutex.h',

src/node_mem-inl.h

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
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+
9+
namespace node {
10+
namespace mem {
11+
12+
template <typename Class, typename AllocatorStruct>
13+
AllocatorStruct 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+
23+
template <typename Class, typename T>
24+
void* 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+
74+
template <typename Class, typename T>
75+
void* NgLibMemoryManager<Class, T>::MallocImpl(size_t size, void* user_data) {
76+
return ReallocImpl(nullptr, size, user_data);
77+
}
78+
79+
template <typename Class, typename T>
80+
void NgLibMemoryManager<Class, T>::FreeImpl(void* ptr, void* user_data) {
81+
if (ptr == nullptr) return;
82+
CHECK_NULL(ReallocImpl(ptr, 0, user_data));
83+
}
84+
85+
template <typename Class, typename T>
86+
void* 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+
96+
template <typename Class, typename T>
97+
void 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_

src/node_mem.h

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#ifndef SRC_NODE_MEM_H_
2+
#define SRC_NODE_MEM_H_
3+
4+
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5+
6+
#include <cstddef>
7+
8+
namespace node {
9+
namespace mem {
10+
11+
// Both ngtcp2 and nghttp2 allow custom allocators that
12+
// follow exactly the same structure and behavior, but
13+
// use different struct names. To allow for code re-use,
14+
// the NgLibMemoryManager template class can be used for both.
15+
16+
template <typename Class, typename AllocatorStructName>
17+
class NgLibMemoryManager {
18+
public:
19+
// Class needs to provide these methods:
20+
// void CheckAllocatedSize(size_t previous_size) const;
21+
// void IncreaseAllocatedSize(size_t size);
22+
// void DecreaseAllocatedSize(size_t size);
23+
// Environment* env() const;
24+
25+
AllocatorStructName MakeAllocator();
26+
27+
void StopTrackingMemory(void* ptr);
28+
29+
private:
30+
static void* ReallocImpl(void* ptr, size_t size, void* user_data);
31+
static void* MallocImpl(size_t size, void* user_data);
32+
static void FreeImpl(void* ptr, void* user_data);
33+
static void* CallocImpl(size_t nmemb, size_t size, void* user_data);
34+
};
35+
36+
} // namespace mem
37+
} // namespace node
38+
39+
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
40+
41+
#endif // SRC_NODE_MEM_H_

0 commit comments

Comments
 (0)