Skip to content

Commit 9894e8d

Browse files
committed
Refactor JSMallocFunctions to simplify the implementation
Rather than having the user take care of JSMallocState, take care of the bookkeeping internally (and make JSMallocState non-public since it's no longer necessary) and keep the allocation functions to the bare minimum. This has the advantage that using a different allocator is just a few lines of code, and there is no need to copy the default implementation just to moficy the call to the allocation function. Fixes: #285
1 parent fb70e09 commit 9894e8d

File tree

3 files changed

+109
-154
lines changed

3 files changed

+109
-154
lines changed

qjs.c

Lines changed: 12 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -165,12 +165,6 @@ static JSContext *JS_NewCustomContext(JSRuntime *rt)
165165
return ctx;
166166
}
167167

168-
#if defined(__APPLE__)
169-
#define MALLOC_OVERHEAD 0
170-
#else
171-
#define MALLOC_OVERHEAD 8
172-
#endif
173-
174168
struct trace_malloc_data {
175169
uint8_t *base;
176170
};
@@ -188,7 +182,7 @@ __attribute__((format(gnu_printf, 2, 3)))
188182
#else
189183
__attribute__((format(printf, 2, 3)))
190184
#endif
191-
js_trace_malloc_printf(JSMallocState *s, const char *fmt, ...)
185+
js_trace_malloc_printf(void *opaque, const char *fmt, ...)
192186
{
193187
va_list ap;
194188
int c;
@@ -203,7 +197,7 @@ __attribute__((format(printf, 2, 3)))
203197
printf("NULL");
204198
} else {
205199
printf("H%+06lld.%zd",
206-
js_trace_malloc_ptr_offset(ptr, s->opaque),
200+
js_trace_malloc_ptr_offset(ptr, opaque),
207201
js__malloc_usable_size(ptr));
208202
}
209203
fmt++;
@@ -226,87 +220,36 @@ static void js_trace_malloc_init(struct trace_malloc_data *s)
226220
free(s->base = malloc(8));
227221
}
228222

229-
static void *js_trace_calloc(JSMallocState *s, size_t count, size_t size)
223+
static void *js_trace_calloc(void *opaque, size_t count, size_t size)
230224
{
231225
void *ptr;
232-
233-
/* Do not allocate zero bytes: behavior is platform dependent */
234-
assert(count != 0 && size != 0);
235-
236-
if (size > 0)
237-
if (unlikely(count != (count * size) / size))
238-
return NULL;
239-
240-
/* When malloc_limit is 0 (unlimited), malloc_limit - 1 will be SIZE_MAX. */
241-
if (unlikely(s->malloc_size + (count * size) > s->malloc_limit - 1))
242-
return NULL;
243226
ptr = calloc(count, size);
244-
js_trace_malloc_printf(s, "C %zd %zd -> %p\n", count, size, ptr);
245-
if (ptr) {
246-
s->malloc_count++;
247-
s->malloc_size += js__malloc_usable_size(ptr) + MALLOC_OVERHEAD;
248-
}
227+
js_trace_malloc_printf(opaque, "C %zd %zd -> %p\n", count, size, ptr);
249228
return ptr;
250229
}
251230

252-
static void *js_trace_malloc(JSMallocState *s, size_t size)
231+
static void *js_trace_malloc(void *opaque, size_t size)
253232
{
233+
(void) opaque;
254234
void *ptr;
255-
256-
/* Do not allocate zero bytes: behavior is platform dependent */
257-
assert(size != 0);
258-
259-
/* When malloc_limit is 0 (unlimited), malloc_limit - 1 will be SIZE_MAX. */
260-
if (unlikely(s->malloc_size + size > s->malloc_limit - 1))
261-
return NULL;
262235
ptr = malloc(size);
263-
js_trace_malloc_printf(s, "A %zd -> %p\n", size, ptr);
264-
if (ptr) {
265-
s->malloc_count++;
266-
s->malloc_size += js__malloc_usable_size(ptr) + MALLOC_OVERHEAD;
267-
}
236+
js_trace_malloc_printf(opaque, "A %zd -> %p\n", size, ptr);
268237
return ptr;
269238
}
270239

271-
static void js_trace_free(JSMallocState *s, void *ptr)
240+
static void js_trace_free(void *opaque, void *ptr)
272241
{
273242
if (!ptr)
274243
return;
275-
276-
js_trace_malloc_printf(s, "F %p\n", ptr);
277-
s->malloc_count--;
278-
s->malloc_size -= js__malloc_usable_size(ptr) + MALLOC_OVERHEAD;
244+
js_trace_malloc_printf(opaque, "F %p\n", ptr);
279245
free(ptr);
280246
}
281247

282-
static void *js_trace_realloc(JSMallocState *s, void *ptr, size_t size)
248+
static void *js_trace_realloc(void *opaque, void *ptr, size_t size)
283249
{
284-
size_t old_size;
285-
286-
if (!ptr) {
287-
if (size == 0)
288-
return NULL;
289-
return js_trace_malloc(s, size);
290-
}
291-
292-
if (unlikely(size == 0)) {
293-
js_trace_free(s, ptr);
294-
return NULL;
295-
}
296-
297-
old_size = js__malloc_usable_size(ptr);
298-
299-
/* When malloc_limit is 0 (unlimited), malloc_limit - 1 will be SIZE_MAX. */
300-
if (s->malloc_size + size - old_size > s->malloc_limit - 1)
301-
return NULL;
302-
303-
js_trace_malloc_printf(s, "R %zd %p", size, ptr);
304-
250+
js_trace_malloc_printf(opaque, "R %zd %p", size, ptr);
305251
ptr = realloc(ptr, size);
306-
js_trace_malloc_printf(s, " -> %p\n", ptr);
307-
if (ptr) {
308-
s->malloc_size += js__malloc_usable_size(ptr) - old_size;
309-
}
252+
js_trace_malloc_printf(opaque, " -> %p\n", ptr);
310253
return ptr;
311254
}
312255

quickjs.c

Lines changed: 93 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,13 @@ typedef enum {
213213
JS_GC_PHASE_REMOVE_CYCLES,
214214
} JSGCPhaseEnum;
215215

216+
typedef struct JSMallocState {
217+
size_t malloc_count;
218+
size_t malloc_size;
219+
size_t malloc_limit;
220+
void *opaque; /* user opaque */
221+
} JSMallocState;
222+
216223
struct JSRuntime {
217224
JSMallocFunctions mf;
218225
JSMallocState malloc_state;
@@ -1380,22 +1387,91 @@ static size_t js_malloc_usable_size_unknown(const void *ptr)
13801387

13811388
void *js_calloc_rt(JSRuntime *rt, size_t count, size_t size)
13821389
{
1383-
return rt->mf.js_calloc(&rt->malloc_state, count, size);
1390+
void *ptr;
1391+
JSMallocState *s;
1392+
1393+
/* Do not allocate zero bytes: behavior is platform dependent */
1394+
assert(count != 0 && size != 0);
1395+
1396+
if (size > 0)
1397+
if (unlikely(count != (count * size) / size))
1398+
return NULL;
1399+
1400+
s = &rt->malloc_state;
1401+
/* When malloc_limit is 0 (unlimited), malloc_limit - 1 will be SIZE_MAX. */
1402+
if (unlikely(s->malloc_size + (count * size) > s->malloc_limit - 1))
1403+
return NULL;
1404+
1405+
ptr = rt->mf.js_calloc(s->opaque, count, size);
1406+
if (!ptr)
1407+
return NULL;
1408+
1409+
s->malloc_count++;
1410+
s->malloc_size += js__malloc_usable_size(ptr) + MALLOC_OVERHEAD;
1411+
return ptr;
13841412
}
13851413

13861414
void *js_malloc_rt(JSRuntime *rt, size_t size)
13871415
{
1388-
return rt->mf.js_malloc(&rt->malloc_state, size);
1416+
void *ptr;
1417+
JSMallocState *s;
1418+
1419+
/* Do not allocate zero bytes: behavior is platform dependent */
1420+
assert(size != 0);
1421+
1422+
s = &rt->malloc_state;
1423+
/* When malloc_limit is 0 (unlimited), malloc_limit - 1 will be SIZE_MAX. */
1424+
if (unlikely(s->malloc_size + size > s->malloc_limit - 1))
1425+
return NULL;
1426+
1427+
ptr = rt->mf.js_malloc(s->opaque, size);
1428+
if (!ptr)
1429+
return NULL;
1430+
1431+
s->malloc_count++;
1432+
s->malloc_size += js__malloc_usable_size(ptr) + MALLOC_OVERHEAD;
1433+
return ptr;
13891434
}
13901435

13911436
void js_free_rt(JSRuntime *rt, void *ptr)
13921437
{
1393-
rt->mf.js_free(&rt->malloc_state, ptr);
1438+
JSMallocState *s;
1439+
1440+
if (!ptr)
1441+
return;
1442+
1443+
s = &rt->malloc_state;
1444+
s->malloc_count--;
1445+
s->malloc_size -= js__malloc_usable_size(ptr) + MALLOC_OVERHEAD;
1446+
rt->mf.js_free(s->opaque, ptr);
13941447
}
13951448

13961449
void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size)
13971450
{
1398-
return rt->mf.js_realloc(&rt->malloc_state, ptr, size);
1451+
size_t old_size;
1452+
JSMallocState *s;
1453+
1454+
if (!ptr) {
1455+
if (size == 0)
1456+
return NULL;
1457+
return js_malloc_rt(rt, size);
1458+
}
1459+
if (unlikely(size == 0)) {
1460+
js_free_rt(rt, ptr);
1461+
return NULL;
1462+
}
1463+
old_size = js__malloc_usable_size(ptr);
1464+
s = &rt->malloc_state;
1465+
/* When malloc_limit is 0 (unlimited), malloc_limit - 1 will be SIZE_MAX. */
1466+
if (s->malloc_size + size - old_size > s->malloc_limit - 1)
1467+
return NULL;
1468+
1469+
ptr = rt->mf.js_realloc(s->opaque, ptr, size);
1470+
if (!ptr)
1471+
return NULL;
1472+
1473+
s->malloc_size += js__malloc_usable_size(ptr) - old_size;
1474+
return ptr;
13991475
}
14001476

14011477
static void *js_dbuf_realloc(void *opaque, void *ptr, size_t size)
@@ -1651,9 +1727,12 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
16511727
ms.opaque = opaque;
16521728
ms.malloc_limit = 0;
16531729

1654-
rt = mf->js_calloc(&ms, 1, sizeof(JSRuntime));
1730+
rt = mf->js_calloc(opaque, 1, sizeof(JSRuntime));
16551731
if (!rt)
16561732
return NULL;
1733+
/* Inline what js_malloc_rt does since we cannot use it here. */
1734+
ms.malloc_count++;
1735+
ms.malloc_size += js__malloc_usable_size(rt) + MALLOC_OVERHEAD;
16571736
rt->mf = *mf;
16581737
if (!rt->mf.js_malloc_usable_size) {
16591738
/* use dummy function if none provided */
@@ -1718,84 +1797,24 @@ void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque)
17181797
rt->user_opaque = opaque;
17191798
}
17201799

1721-
static void *js_def_calloc(JSMallocState *s, size_t count, size_t size)
1800+
static void *js_def_calloc(void *opaque, size_t count, size_t size)
17221801
{
1723-
void *ptr;
1724-
1725-
/* Do not allocate zero bytes: behavior is platform dependent */
1726-
assert(count != 0 && size != 0);
1727-
1728-
if (size > 0)
1729-
if (unlikely(count != (count * size) / size))
1730-
return NULL;
1731-
1732-
/* When malloc_limit is 0 (unlimited), malloc_limit - 1 will be SIZE_MAX. */
1733-
if (unlikely(s->malloc_size + (count * size) > s->malloc_limit - 1))
1734-
return NULL;
1735-
1736-
ptr = calloc(count, size);
1737-
if (!ptr)
1738-
return NULL;
1739-
1740-
s->malloc_count++;
1741-
s->malloc_size += js__malloc_usable_size(ptr) + MALLOC_OVERHEAD;
1742-
return ptr;
1802+
return calloc(count, size);
17431803
}
17441804

1745-
static void *js_def_malloc(JSMallocState *s, size_t size)
1805+
static void *js_def_malloc(void *opaque, size_t size)
17461806
{
1747-
void *ptr;
1748-
1749-
/* Do not allocate zero bytes: behavior is platform dependent */
1750-
assert(size != 0);
1751-
1752-
/* When malloc_limit is 0 (unlimited), malloc_limit - 1 will be SIZE_MAX. */
1753-
if (unlikely(s->malloc_size + size > s->malloc_limit - 1))
1754-
return NULL;
1755-
1756-
ptr = malloc(size);
1757-
if (!ptr)
1758-
return NULL;
1759-
1760-
s->malloc_count++;
1761-
s->malloc_size += js__malloc_usable_size(ptr) + MALLOC_OVERHEAD;
1762-
return ptr;
1807+
return malloc(size);
17631808
}
17641809

1765-
static void js_def_free(JSMallocState *s, void *ptr)
1810+
static void js_def_free(void *opaque, void *ptr)
17661811
{
1767-
if (!ptr)
1768-
return;
1769-
1770-
s->malloc_count--;
1771-
s->malloc_size -= js__malloc_usable_size(ptr) + MALLOC_OVERHEAD;
17721812
free(ptr);
17731813
}
17741814

1775-
static void *js_def_realloc(JSMallocState *s, void *ptr, size_t size)
1815+
static void *js_def_realloc(void *opaque, void *ptr, size_t size)
17761816
{
1777-
size_t old_size;
1778-
1779-
if (!ptr) {
1780-
if (size == 0)
1781-
return NULL;
1782-
return js_def_malloc(s, size);
1783-
}
1784-
if (unlikely(size == 0)) {
1785-
js_def_free(s, ptr);
1786-
return NULL;
1787-
}
1788-
old_size = js__malloc_usable_size(ptr);
1789-
/* When malloc_limit is 0 (unlimited), malloc_limit - 1 will be SIZE_MAX. */
1790-
if (s->malloc_size + size - old_size > s->malloc_limit - 1)
1791-
return NULL;
1792-
1793-
ptr = realloc(ptr, size);
1794-
if (!ptr)
1795-
return NULL;
1796-
1797-
s->malloc_size += js__malloc_usable_size(ptr) - old_size;
1798-
return ptr;
1817+
return realloc(ptr, size);
17991818
}
18001819

18011820
static const JSMallocFunctions def_malloc_funcs = {
@@ -2159,8 +2178,8 @@ void JS_FreeRuntime(JSRuntime *rt)
21592178
#endif
21602179

21612180
{
2162-
JSMallocState ms = rt->malloc_state;
2163-
rt->mf.js_free(&ms, rt);
2181+
JSMallocState *ms = &rt->malloc_state;
2182+
rt->mf.js_free(ms->opaque, rt);
21642183
}
21652184
}
21662185

quickjs.h

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -283,18 +283,11 @@ typedef JSValue JSCFunction(JSContext *ctx, JSValue this_val, int argc, JSValue
283283
typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValue this_val, int argc, JSValue *argv, int magic);
284284
typedef JSValue JSCFunctionData(JSContext *ctx, JSValue this_val, int argc, JSValue *argv, int magic, JSValue *func_data);
285285

286-
typedef struct JSMallocState {
287-
size_t malloc_count;
288-
size_t malloc_size;
289-
size_t malloc_limit;
290-
void *opaque; /* user opaque */
291-
} JSMallocState;
292-
293286
typedef struct JSMallocFunctions {
294-
void *(*js_calloc)(JSMallocState *s, size_t count, size_t size);
295-
void *(*js_malloc)(JSMallocState *s, size_t size);
296-
void (*js_free)(JSMallocState *s, void *ptr);
297-
void *(*js_realloc)(JSMallocState *s, void *ptr, size_t size);
287+
void *(*js_calloc)(void *opaque, size_t count, size_t size);
288+
void *(*js_malloc)(void *opaque, size_t size);
289+
void (*js_free)(void *opaque, void *ptr);
290+
void *(*js_realloc)(void *opaque, void *ptr, size_t size);
298291
size_t (*js_malloc_usable_size)(const void *ptr);
299292
} JSMallocFunctions;
300293

0 commit comments

Comments
 (0)