annotate libcxxabi/src/fallback_malloc.cpp @ 207:2e18cbf3894f

LLVM12
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Tue, 08 Jun 2021 06:07:14 +0900
parents 1d019706d866
children c4bab56944e8
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===------------------------ fallback_malloc.cpp -------------------------===//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8
anatofuz
parents:
diff changeset
9 #include "fallback_malloc.h"
anatofuz
parents:
diff changeset
10
anatofuz
parents:
diff changeset
11 #include <__threading_support>
anatofuz
parents:
diff changeset
12 #ifndef _LIBCXXABI_HAS_NO_THREADS
anatofuz
parents:
diff changeset
13 #if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
anatofuz
parents:
diff changeset
14 #pragma comment(lib, "pthread")
anatofuz
parents:
diff changeset
15 #endif
anatofuz
parents:
diff changeset
16 #endif
anatofuz
parents:
diff changeset
17
anatofuz
parents:
diff changeset
18 #include <stdlib.h> // for malloc, calloc, free
anatofuz
parents:
diff changeset
19 #include <string.h> // for memset
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
20 #include <new> // for std::__libcpp_aligned_{alloc,free}
150
anatofuz
parents:
diff changeset
21
anatofuz
parents:
diff changeset
22 // A small, simple heap manager based (loosely) on
anatofuz
parents:
diff changeset
23 // the startup heap manager from FreeBSD, optimized for space.
anatofuz
parents:
diff changeset
24 //
anatofuz
parents:
diff changeset
25 // Manages a fixed-size memory pool, supports malloc and free only.
anatofuz
parents:
diff changeset
26 // No support for realloc.
anatofuz
parents:
diff changeset
27 //
anatofuz
parents:
diff changeset
28 // Allocates chunks in multiples of four bytes, with a four byte header
anatofuz
parents:
diff changeset
29 // for each chunk. The overhead of each chunk is kept low by keeping pointers
anatofuz
parents:
diff changeset
30 // as two byte offsets within the heap, rather than (4 or 8 byte) pointers.
anatofuz
parents:
diff changeset
31
anatofuz
parents:
diff changeset
32 namespace {
anatofuz
parents:
diff changeset
33
anatofuz
parents:
diff changeset
34 // When POSIX threads are not available, make the mutex operations a nop
anatofuz
parents:
diff changeset
35 #ifndef _LIBCXXABI_HAS_NO_THREADS
anatofuz
parents:
diff changeset
36 _LIBCPP_SAFE_STATIC
anatofuz
parents:
diff changeset
37 static std::__libcpp_mutex_t heap_mutex = _LIBCPP_MUTEX_INITIALIZER;
anatofuz
parents:
diff changeset
38 #else
anatofuz
parents:
diff changeset
39 static void* heap_mutex = 0;
anatofuz
parents:
diff changeset
40 #endif
anatofuz
parents:
diff changeset
41
anatofuz
parents:
diff changeset
42 class mutexor {
anatofuz
parents:
diff changeset
43 public:
anatofuz
parents:
diff changeset
44 #ifndef _LIBCXXABI_HAS_NO_THREADS
anatofuz
parents:
diff changeset
45 mutexor(std::__libcpp_mutex_t* m) : mtx_(m) {
anatofuz
parents:
diff changeset
46 std::__libcpp_mutex_lock(mtx_);
anatofuz
parents:
diff changeset
47 }
anatofuz
parents:
diff changeset
48 ~mutexor() { std::__libcpp_mutex_unlock(mtx_); }
anatofuz
parents:
diff changeset
49 #else
anatofuz
parents:
diff changeset
50 mutexor(void*) {}
anatofuz
parents:
diff changeset
51 ~mutexor() {}
anatofuz
parents:
diff changeset
52 #endif
anatofuz
parents:
diff changeset
53 private:
anatofuz
parents:
diff changeset
54 mutexor(const mutexor& rhs);
anatofuz
parents:
diff changeset
55 mutexor& operator=(const mutexor& rhs);
anatofuz
parents:
diff changeset
56 #ifndef _LIBCXXABI_HAS_NO_THREADS
anatofuz
parents:
diff changeset
57 std::__libcpp_mutex_t* mtx_;
anatofuz
parents:
diff changeset
58 #endif
anatofuz
parents:
diff changeset
59 };
anatofuz
parents:
diff changeset
60
anatofuz
parents:
diff changeset
61 static const size_t HEAP_SIZE = 512;
anatofuz
parents:
diff changeset
62 char heap[HEAP_SIZE] __attribute__((aligned));
anatofuz
parents:
diff changeset
63
anatofuz
parents:
diff changeset
64 typedef unsigned short heap_offset;
anatofuz
parents:
diff changeset
65 typedef unsigned short heap_size;
anatofuz
parents:
diff changeset
66
anatofuz
parents:
diff changeset
67 struct heap_node {
anatofuz
parents:
diff changeset
68 heap_offset next_node; // offset into heap
anatofuz
parents:
diff changeset
69 heap_size len; // size in units of "sizeof(heap_node)"
anatofuz
parents:
diff changeset
70 };
anatofuz
parents:
diff changeset
71
anatofuz
parents:
diff changeset
72 static const heap_node* list_end =
anatofuz
parents:
diff changeset
73 (heap_node*)(&heap[HEAP_SIZE]); // one past the end of the heap
anatofuz
parents:
diff changeset
74 static heap_node* freelist = NULL;
anatofuz
parents:
diff changeset
75
anatofuz
parents:
diff changeset
76 heap_node* node_from_offset(const heap_offset offset) {
anatofuz
parents:
diff changeset
77 return (heap_node*)(heap + (offset * sizeof(heap_node)));
anatofuz
parents:
diff changeset
78 }
anatofuz
parents:
diff changeset
79
anatofuz
parents:
diff changeset
80 heap_offset offset_from_node(const heap_node* ptr) {
anatofuz
parents:
diff changeset
81 return static_cast<heap_offset>(
anatofuz
parents:
diff changeset
82 static_cast<size_t>(reinterpret_cast<const char*>(ptr) - heap) /
anatofuz
parents:
diff changeset
83 sizeof(heap_node));
anatofuz
parents:
diff changeset
84 }
anatofuz
parents:
diff changeset
85
anatofuz
parents:
diff changeset
86 void init_heap() {
anatofuz
parents:
diff changeset
87 freelist = (heap_node*)heap;
anatofuz
parents:
diff changeset
88 freelist->next_node = offset_from_node(list_end);
anatofuz
parents:
diff changeset
89 freelist->len = HEAP_SIZE / sizeof(heap_node);
anatofuz
parents:
diff changeset
90 }
anatofuz
parents:
diff changeset
91
anatofuz
parents:
diff changeset
92 // How big a chunk we allocate
anatofuz
parents:
diff changeset
93 size_t alloc_size(size_t len) {
anatofuz
parents:
diff changeset
94 return (len + sizeof(heap_node) - 1) / sizeof(heap_node) + 1;
anatofuz
parents:
diff changeset
95 }
anatofuz
parents:
diff changeset
96
anatofuz
parents:
diff changeset
97 bool is_fallback_ptr(void* ptr) {
anatofuz
parents:
diff changeset
98 return ptr >= heap && ptr < (heap + HEAP_SIZE);
anatofuz
parents:
diff changeset
99 }
anatofuz
parents:
diff changeset
100
anatofuz
parents:
diff changeset
101 void* fallback_malloc(size_t len) {
anatofuz
parents:
diff changeset
102 heap_node *p, *prev;
anatofuz
parents:
diff changeset
103 const size_t nelems = alloc_size(len);
anatofuz
parents:
diff changeset
104 mutexor mtx(&heap_mutex);
anatofuz
parents:
diff changeset
105
anatofuz
parents:
diff changeset
106 if (NULL == freelist)
anatofuz
parents:
diff changeset
107 init_heap();
anatofuz
parents:
diff changeset
108
anatofuz
parents:
diff changeset
109 // Walk the free list, looking for a "big enough" chunk
anatofuz
parents:
diff changeset
110 for (p = freelist, prev = 0; p && p != list_end;
anatofuz
parents:
diff changeset
111 prev = p, p = node_from_offset(p->next_node)) {
anatofuz
parents:
diff changeset
112
anatofuz
parents:
diff changeset
113 if (p->len > nelems) { // chunk is larger, shorten, and return the tail
anatofuz
parents:
diff changeset
114 heap_node* q;
anatofuz
parents:
diff changeset
115
anatofuz
parents:
diff changeset
116 p->len = static_cast<heap_size>(p->len - nelems);
anatofuz
parents:
diff changeset
117 q = p + p->len;
anatofuz
parents:
diff changeset
118 q->next_node = 0;
anatofuz
parents:
diff changeset
119 q->len = static_cast<heap_size>(nelems);
anatofuz
parents:
diff changeset
120 return (void*)(q + 1);
anatofuz
parents:
diff changeset
121 }
anatofuz
parents:
diff changeset
122
anatofuz
parents:
diff changeset
123 if (p->len == nelems) { // exact size match
anatofuz
parents:
diff changeset
124 if (prev == 0)
anatofuz
parents:
diff changeset
125 freelist = node_from_offset(p->next_node);
anatofuz
parents:
diff changeset
126 else
anatofuz
parents:
diff changeset
127 prev->next_node = p->next_node;
anatofuz
parents:
diff changeset
128 p->next_node = 0;
anatofuz
parents:
diff changeset
129 return (void*)(p + 1);
anatofuz
parents:
diff changeset
130 }
anatofuz
parents:
diff changeset
131 }
anatofuz
parents:
diff changeset
132 return NULL; // couldn't find a spot big enough
anatofuz
parents:
diff changeset
133 }
anatofuz
parents:
diff changeset
134
anatofuz
parents:
diff changeset
135 // Return the start of the next block
anatofuz
parents:
diff changeset
136 heap_node* after(struct heap_node* p) { return p + p->len; }
anatofuz
parents:
diff changeset
137
anatofuz
parents:
diff changeset
138 void fallback_free(void* ptr) {
anatofuz
parents:
diff changeset
139 struct heap_node* cp = ((struct heap_node*)ptr) - 1; // retrieve the chunk
anatofuz
parents:
diff changeset
140 struct heap_node *p, *prev;
anatofuz
parents:
diff changeset
141
anatofuz
parents:
diff changeset
142 mutexor mtx(&heap_mutex);
anatofuz
parents:
diff changeset
143
anatofuz
parents:
diff changeset
144 #ifdef DEBUG_FALLBACK_MALLOC
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
145 std::printf("Freeing item at %d of size %d\n", offset_from_node(cp), cp->len);
150
anatofuz
parents:
diff changeset
146 #endif
anatofuz
parents:
diff changeset
147
anatofuz
parents:
diff changeset
148 for (p = freelist, prev = 0; p && p != list_end;
anatofuz
parents:
diff changeset
149 prev = p, p = node_from_offset(p->next_node)) {
anatofuz
parents:
diff changeset
150 #ifdef DEBUG_FALLBACK_MALLOC
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
151 std::printf(" p=%d, cp=%d, after(p)=%d, after(cp)=%d\n",
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
152 offset_from_node(p), offset_from_node(cp),
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
153 offset_from_node(after(p)), offset_from_node(after(cp)));
150
anatofuz
parents:
diff changeset
154 #endif
anatofuz
parents:
diff changeset
155 if (after(p) == cp) {
anatofuz
parents:
diff changeset
156 #ifdef DEBUG_FALLBACK_MALLOC
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
157 std::printf(" Appending onto chunk at %d\n", offset_from_node(p));
150
anatofuz
parents:
diff changeset
158 #endif
anatofuz
parents:
diff changeset
159 p->len = static_cast<heap_size>(
anatofuz
parents:
diff changeset
160 p->len + cp->len); // make the free heap_node larger
anatofuz
parents:
diff changeset
161 return;
anatofuz
parents:
diff changeset
162 } else if (after(cp) == p) { // there's a free heap_node right after
anatofuz
parents:
diff changeset
163 #ifdef DEBUG_FALLBACK_MALLOC
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
164 std::printf(" Appending free chunk at %d\n", offset_from_node(p));
150
anatofuz
parents:
diff changeset
165 #endif
anatofuz
parents:
diff changeset
166 cp->len = static_cast<heap_size>(cp->len + p->len);
anatofuz
parents:
diff changeset
167 if (prev == 0) {
anatofuz
parents:
diff changeset
168 freelist = cp;
anatofuz
parents:
diff changeset
169 cp->next_node = p->next_node;
anatofuz
parents:
diff changeset
170 } else
anatofuz
parents:
diff changeset
171 prev->next_node = offset_from_node(cp);
anatofuz
parents:
diff changeset
172 return;
anatofuz
parents:
diff changeset
173 }
anatofuz
parents:
diff changeset
174 }
anatofuz
parents:
diff changeset
175 // Nothing to merge with, add it to the start of the free list
anatofuz
parents:
diff changeset
176 #ifdef DEBUG_FALLBACK_MALLOC
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
177 std::printf(" Making new free list entry %d\n", offset_from_node(cp));
150
anatofuz
parents:
diff changeset
178 #endif
anatofuz
parents:
diff changeset
179 cp->next_node = offset_from_node(freelist);
anatofuz
parents:
diff changeset
180 freelist = cp;
anatofuz
parents:
diff changeset
181 }
anatofuz
parents:
diff changeset
182
anatofuz
parents:
diff changeset
183 #ifdef INSTRUMENT_FALLBACK_MALLOC
anatofuz
parents:
diff changeset
184 size_t print_free_list() {
anatofuz
parents:
diff changeset
185 struct heap_node *p, *prev;
anatofuz
parents:
diff changeset
186 heap_size total_free = 0;
anatofuz
parents:
diff changeset
187 if (NULL == freelist)
anatofuz
parents:
diff changeset
188 init_heap();
anatofuz
parents:
diff changeset
189
anatofuz
parents:
diff changeset
190 for (p = freelist, prev = 0; p && p != list_end;
anatofuz
parents:
diff changeset
191 prev = p, p = node_from_offset(p->next_node)) {
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
192 std::printf("%sOffset: %d\tsize: %d Next: %d\n",
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
193 (prev == 0 ? "" : " "), offset_from_node(p), p->len, p->next_node);
150
anatofuz
parents:
diff changeset
194 total_free += p->len;
anatofuz
parents:
diff changeset
195 }
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
196 std::printf("Total Free space: %d\n", total_free);
150
anatofuz
parents:
diff changeset
197 return total_free;
anatofuz
parents:
diff changeset
198 }
anatofuz
parents:
diff changeset
199 #endif
anatofuz
parents:
diff changeset
200 } // end unnamed namespace
anatofuz
parents:
diff changeset
201
anatofuz
parents:
diff changeset
202 namespace __cxxabiv1 {
anatofuz
parents:
diff changeset
203
anatofuz
parents:
diff changeset
204 struct __attribute__((aligned)) __aligned_type {};
anatofuz
parents:
diff changeset
205
anatofuz
parents:
diff changeset
206 void* __aligned_malloc_with_fallback(size_t size) {
anatofuz
parents:
diff changeset
207 #if defined(_WIN32)
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
208 if (void* dest = std::__libcpp_aligned_alloc(alignof(__aligned_type), size))
150
anatofuz
parents:
diff changeset
209 return dest;
anatofuz
parents:
diff changeset
210 #elif defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION)
anatofuz
parents:
diff changeset
211 if (void* dest = ::malloc(size))
anatofuz
parents:
diff changeset
212 return dest;
anatofuz
parents:
diff changeset
213 #else
anatofuz
parents:
diff changeset
214 if (size == 0)
anatofuz
parents:
diff changeset
215 size = 1;
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
216 if (void* dest = std::__libcpp_aligned_alloc(__alignof(__aligned_type), size))
150
anatofuz
parents:
diff changeset
217 return dest;
anatofuz
parents:
diff changeset
218 #endif
anatofuz
parents:
diff changeset
219 return fallback_malloc(size);
anatofuz
parents:
diff changeset
220 }
anatofuz
parents:
diff changeset
221
anatofuz
parents:
diff changeset
222 void* __calloc_with_fallback(size_t count, size_t size) {
anatofuz
parents:
diff changeset
223 void* ptr = ::calloc(count, size);
anatofuz
parents:
diff changeset
224 if (NULL != ptr)
anatofuz
parents:
diff changeset
225 return ptr;
anatofuz
parents:
diff changeset
226 // if calloc fails, fall back to emergency stash
anatofuz
parents:
diff changeset
227 ptr = fallback_malloc(size * count);
anatofuz
parents:
diff changeset
228 if (NULL != ptr)
anatofuz
parents:
diff changeset
229 ::memset(ptr, 0, size * count);
anatofuz
parents:
diff changeset
230 return ptr;
anatofuz
parents:
diff changeset
231 }
anatofuz
parents:
diff changeset
232
anatofuz
parents:
diff changeset
233 void __aligned_free_with_fallback(void* ptr) {
anatofuz
parents:
diff changeset
234 if (is_fallback_ptr(ptr))
anatofuz
parents:
diff changeset
235 fallback_free(ptr);
anatofuz
parents:
diff changeset
236 else {
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
237 #if defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION)
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
238 ::free(ptr);
150
anatofuz
parents:
diff changeset
239 #else
207
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
240 std::__libcpp_aligned_free(ptr);
150
anatofuz
parents:
diff changeset
241 #endif
anatofuz
parents:
diff changeset
242 }
anatofuz
parents:
diff changeset
243 }
anatofuz
parents:
diff changeset
244
anatofuz
parents:
diff changeset
245 void __free_with_fallback(void* ptr) {
anatofuz
parents:
diff changeset
246 if (is_fallback_ptr(ptr))
anatofuz
parents:
diff changeset
247 fallback_free(ptr);
anatofuz
parents:
diff changeset
248 else
anatofuz
parents:
diff changeset
249 ::free(ptr);
anatofuz
parents:
diff changeset
250 }
anatofuz
parents:
diff changeset
251
anatofuz
parents:
diff changeset
252 } // namespace __cxxabiv1