Skip to content

Commit 885e398

Browse files
authored
chore: Introduce allocation wrappers around spidermonkeys allocator api (#378)
Introduce a strong symbol for cabi_realloc to ensure that we're always calling JS_realloc, and some convenience functions for helping to identify when memory is managed by wit-bindgen-generated code.
1 parent 4f1288c commit 885e398

File tree

4 files changed

+101
-64
lines changed

4 files changed

+101
-64
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
#pragma clang diagnostic push
3+
#pragma clang diagnostic ignored "-Winvalid-offsetof"
4+
#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"
5+
#include "jsapi.h"
6+
#pragma clang diagnostic pop
7+
8+
JSContext *CONTEXT = nullptr;
9+
10+
extern "C" {
11+
12+
__attribute__((export_name("cabi_realloc"))) void *cabi_realloc(void *ptr, size_t orig_size,
13+
size_t align, size_t new_size) {
14+
return JS_realloc(CONTEXT, ptr, orig_size, new_size);
15+
}
16+
17+
void cabi_free(void *ptr) { JS_free(CONTEXT, ptr); }
18+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#ifndef JS_COMPUTE_RUNTIME_ALLOCATOR_H
2+
#define JS_COMPUTE_RUNTIME_ALLOCATOR_H
3+
4+
#include <cstddef>
5+
6+
struct JSContext;
7+
8+
/// We need a handle to the JSContext in order to use JS_realloc in the implementation of
9+
/// cabi_realloc. Unfortunately way that we can do this now is to keep the context pointer in a
10+
/// global that can be used there. This global is initialized in js-compute-runtime.cpp.
11+
extern JSContext *CONTEXT;
12+
13+
extern "C" {
14+
15+
/// A strong symbol to override the cabi_realloc defined by wit-bindgen. This version of
16+
/// cabi_realloc uses JS_malloc under the hood.
17+
void *cabi_realloc(void *ptr, size_t orig_size, size_t align, size_t new_size);
18+
19+
/// A more ergonomic version of cabi_realloc for fresh allocations.
20+
inline void *cabi_malloc(size_t bytes, size_t align) { return cabi_realloc(NULL, 0, align, bytes); }
21+
22+
/// Not required by wit-bindgen generated code, but a usefully named version of JS_free that can
23+
/// help with identifying where memory allocated by the c-abi.
24+
void cabi_free(void *ptr);
25+
}
26+
27+
#endif

c-dependencies/js-compute-runtime/xqd-world/xqd_world_adapter.cpp

Lines changed: 53 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,6 @@ static_assert(DICTIONARY_ENTRY_MAX_LEN < HOSTCALL_BUFFER_LEN);
99
static_assert(METHOD_MAX_LEN < HOSTCALL_BUFFER_LEN);
1010
static_assert(URI_MAX_LEN < HOSTCALL_BUFFER_LEN);
1111

12-
extern "C" {
13-
14-
__attribute__((weak, export_name("cabi_realloc"))) void *
15-
cabi_realloc(void *ptr, size_t orig_size, size_t align, size_t new_size) {
16-
return JS_realloc(CONTEXT, ptr, orig_size, new_size);
17-
}
18-
}
19-
2012
#define LIST_ALLOC_SIZE 50
2113

2214
static bool convert_result(int res, fastly_error_t *err) {
@@ -98,7 +90,7 @@ bool xqd_fastly_http_body_append(fastly_body_handle_t src, fastly_body_handle_t
9890

9991
bool xqd_fastly_http_body_read(fastly_body_handle_t h, uint32_t chunk_size, fastly_list_u8_t *ret,
10092
fastly_error_t *err) {
101-
ret->ptr = static_cast<uint8_t *>(JS_malloc(CONTEXT, chunk_size));
93+
ret->ptr = static_cast<uint8_t *>(cabi_malloc(chunk_size, 1));
10294
return convert_result(xqd_body_read(h, reinterpret_cast<char *>(ret->ptr),
10395
static_cast<size_t>(chunk_size), &ret->len),
10496
err);
@@ -172,7 +164,7 @@ bool xqd_fastly_http_req_cache_override_set(fastly_request_handle_t h,
172164
}
173165

174166
bool xqd_fastly_http_req_downstream_client_ip_addr(fastly_list_u8_t *ret, fastly_error_t *err) {
175-
ret->ptr = static_cast<uint8_t *>(JS_malloc(CONTEXT, 16));
167+
ret->ptr = static_cast<uint8_t *>(cabi_malloc(16, 1));
176168
return convert_result(
177169
xqd_req_downstream_client_ip_addr_get(reinterpret_cast<char *>(ret->ptr), &ret->len), err);
178170
}
@@ -184,19 +176,20 @@ bool xqd_fastly_http_req_new(fastly_request_handle_t *ret, fastly_error_t *err)
184176
bool xqd_fastly_http_req_header_names_get(fastly_request_handle_t h, fastly_list_string_t *ret,
185177
fastly_error_t *err) {
186178
size_t str_max = LIST_ALLOC_SIZE;
179+
187180
xqd_world_string_t *strs =
188-
static_cast<xqd_world_string_t *>(JS_malloc(CONTEXT, str_max * sizeof(xqd_world_string_t)));
181+
static_cast<xqd_world_string_t *>(cabi_malloc(str_max * sizeof(xqd_world_string_t), 1));
189182
size_t str_cnt = 0;
190183
size_t nwritten;
191-
char *buf = static_cast<char *>(JS_malloc(CONTEXT, HOSTCALL_BUFFER_LEN));
184+
char *buf = static_cast<char *>(cabi_malloc(HOSTCALL_BUFFER_LEN, 1));
192185
uint32_t cursor = 0;
193186
int64_t next_cursor = 0;
194187
while (true) {
195188
if (!convert_result(
196189
xqd_req_header_names_get(h, buf, HEADER_MAX_LEN, cursor, &next_cursor, &nwritten),
197190
err)) {
198-
JS_free(CONTEXT, strs);
199-
JS_free(CONTEXT, buf);
191+
cabi_free(strs);
192+
cabi_free(buf);
200193
return false;
201194
}
202195
if (nwritten == 0)
@@ -207,11 +200,11 @@ bool xqd_fastly_http_req_header_names_get(fastly_request_handle_t h, fastly_list
207200
continue;
208201
if (str_cnt == str_max) {
209202
strs = static_cast<xqd_world_string_t *>(
210-
JS_realloc(CONTEXT, strs, str_max * sizeof(xqd_world_string_t),
211-
(str_max + LIST_ALLOC_SIZE) * sizeof(xqd_world_string_t)));
203+
cabi_realloc(strs, str_max * sizeof(xqd_world_string_t), 1,
204+
(str_max + LIST_ALLOC_SIZE) * sizeof(xqd_world_string_t)));
212205
str_max += LIST_ALLOC_SIZE;
213206
}
214-
strs[str_cnt].ptr = static_cast<char *>(JS_malloc(CONTEXT, i - offset + 1));
207+
strs[str_cnt].ptr = static_cast<char *>(cabi_malloc(i - offset + 1, 1));
215208
strs[str_cnt].len = i - offset;
216209
memcpy(strs[str_cnt].ptr, buf + offset, i - offset + 1);
217210
offset = i + 1;
@@ -221,9 +214,9 @@ bool xqd_fastly_http_req_header_names_get(fastly_request_handle_t h, fastly_list
221214
break;
222215
cursor = (uint32_t)next_cursor;
223216
}
224-
JS_free(CONTEXT, buf);
225-
strs = static_cast<xqd_world_string_t *>(JS_realloc(
226-
CONTEXT, strs, str_max * sizeof(xqd_world_string_t), str_cnt * sizeof(xqd_world_string_t)));
217+
cabi_free(buf);
218+
strs = static_cast<xqd_world_string_t *>(cabi_realloc(strs, str_max * sizeof(xqd_world_string_t),
219+
1, str_cnt * sizeof(xqd_world_string_t)));
227220
ret->ptr = strs;
228221
ret->len = str_cnt;
229222
return true;
@@ -233,17 +226,17 @@ bool xqd_fastly_http_req_header_values_get(fastly_request_handle_t h, xqd_world_
233226
fastly_option_list_string_t *ret, fastly_error_t *err) {
234227
size_t str_max = LIST_ALLOC_SIZE;
235228
xqd_world_string_t *strs =
236-
static_cast<xqd_world_string_t *>(JS_malloc(CONTEXT, str_max * sizeof(xqd_world_string_t)));
229+
static_cast<xqd_world_string_t *>(cabi_malloc(str_max * sizeof(xqd_world_string_t), 1));
237230
size_t str_cnt = 0;
238231
size_t nwritten;
239-
char *buf = static_cast<char *>(JS_malloc(CONTEXT, HOSTCALL_BUFFER_LEN));
232+
char *buf = static_cast<char *>(cabi_malloc(HOSTCALL_BUFFER_LEN, 1));
240233
uint32_t cursor = 0;
241234
int64_t next_cursor = 0;
242235
while (true) {
243236
if (!convert_result(xqd_req_header_values_get(h, name->ptr, name->len, buf, HEADER_MAX_LEN,
244237
cursor, &next_cursor, &nwritten),
245238
err)) {
246-
JS_free(CONTEXT, buf);
239+
cabi_free(buf);
247240
return false;
248241
}
249242
if (nwritten == 0)
@@ -254,11 +247,11 @@ bool xqd_fastly_http_req_header_values_get(fastly_request_handle_t h, xqd_world_
254247
continue;
255248
if (str_cnt == str_max) {
256249
strs = static_cast<xqd_world_string_t *>(
257-
JS_realloc(CONTEXT, strs, str_max * sizeof(xqd_world_string_t),
258-
(str_max + LIST_ALLOC_SIZE) * sizeof(xqd_world_string_t)));
250+
cabi_realloc(strs, str_max * sizeof(xqd_world_string_t), 1,
251+
(str_max + LIST_ALLOC_SIZE) * sizeof(xqd_world_string_t)));
259252
str_max += LIST_ALLOC_SIZE;
260253
}
261-
strs[str_cnt].ptr = static_cast<char *>(JS_malloc(CONTEXT, i - offset + 1));
254+
strs[str_cnt].ptr = static_cast<char *>(cabi_malloc(i - offset + 1, 1));
262255
strs[str_cnt].len = i - offset;
263256
memcpy(strs[str_cnt].ptr, buf + offset, i - offset + 1);
264257
offset = i + 1;
@@ -268,16 +261,16 @@ bool xqd_fastly_http_req_header_values_get(fastly_request_handle_t h, xqd_world_
268261
break;
269262
cursor = (uint32_t)next_cursor;
270263
}
271-
JS_free(CONTEXT, buf);
264+
cabi_free(buf);
272265
if (str_cnt > 0) {
273266
ret->is_some = true;
274267
ret->val.ptr = strs;
275268
ret->val.len = str_cnt;
276-
strs = static_cast<xqd_world_string_t *>(JS_realloc(
277-
CONTEXT, strs, str_max * sizeof(xqd_world_string_t), str_cnt * sizeof(xqd_world_string_t)));
269+
strs = static_cast<xqd_world_string_t *>(cabi_realloc(
270+
strs, str_max * sizeof(xqd_world_string_t), 1, str_cnt * sizeof(xqd_world_string_t)));
278271
} else {
279272
ret->is_some = false;
280-
JS_free(CONTEXT, strs);
273+
cabi_free(strs);
281274
}
282275
return true;
283276
}
@@ -301,7 +294,7 @@ bool xqd_fastly_http_req_header_remove(fastly_request_handle_t h, xqd_world_stri
301294

302295
bool xqd_fastly_http_req_method_get(fastly_request_handle_t h, xqd_world_string_t *ret,
303296
fastly_error_t *err) {
304-
ret->ptr = static_cast<char *>(JS_malloc(CONTEXT, METHOD_MAX_LEN));
297+
ret->ptr = static_cast<char *>(cabi_malloc(METHOD_MAX_LEN, 1));
305298
return convert_result(
306299
xqd_req_method_get(h, reinterpret_cast<char *>(ret->ptr), METHOD_MAX_LEN, &ret->len), err);
307300
}
@@ -314,12 +307,12 @@ bool xqd_fastly_http_req_method_set(fastly_request_handle_t h, xqd_world_string_
314307

315308
bool xqd_fastly_http_req_uri_get(fastly_request_handle_t h, xqd_world_string_t *ret,
316309
fastly_error_t *err) {
317-
ret->ptr = static_cast<char *>(JS_malloc(CONTEXT, URI_MAX_LEN));
310+
ret->ptr = static_cast<char *>(cabi_malloc(URI_MAX_LEN, 1));
318311
if (!convert_result(xqd_req_uri_get(h, ret->ptr, URI_MAX_LEN, &ret->len), err)) {
319-
JS_free(CONTEXT, ret->ptr);
312+
cabi_free(ret->ptr);
320313
return false;
321314
}
322-
ret->ptr = static_cast<char *>(JS_realloc(CONTEXT, ret->ptr, URI_MAX_LEN, ret->len));
315+
ret->ptr = static_cast<char *>(cabi_realloc(ret->ptr, URI_MAX_LEN, 1, ret->len));
323316
return true;
324317
}
325318

@@ -410,18 +403,18 @@ bool xqd_fastly_http_resp_new(fastly_response_handle_t *ret, fastly_error_t *err
410403
bool xqd_fastly_http_resp_header_names_get(fastly_response_handle_t h, fastly_list_string_t *ret,
411404
fastly_error_t *err) {
412405
xqd_world_string_t *strs = static_cast<xqd_world_string_t *>(
413-
JS_malloc(CONTEXT, LIST_ALLOC_SIZE * sizeof(xqd_world_string_t)));
406+
cabi_malloc(LIST_ALLOC_SIZE * sizeof(xqd_world_string_t), 1));
414407
size_t str_max = LIST_ALLOC_SIZE;
415408
size_t str_cnt = 0;
416409
size_t nwritten;
417-
char *buf = static_cast<char *>(JS_malloc(CONTEXT, HOSTCALL_BUFFER_LEN));
410+
char *buf = static_cast<char *>(cabi_malloc(HOSTCALL_BUFFER_LEN, 1));
418411
uint32_t cursor = 0;
419412
int64_t next_cursor = 0;
420413
while (true) {
421414
if (!convert_result(
422415
xqd_resp_header_names_get(h, buf, HEADER_MAX_LEN, cursor, &next_cursor, &nwritten),
423416
err)) {
424-
JS_free(CONTEXT, buf);
417+
cabi_free(buf);
425418
return false;
426419
}
427420
if (nwritten == 0) {
@@ -433,11 +426,11 @@ bool xqd_fastly_http_resp_header_names_get(fastly_response_handle_t h, fastly_li
433426
continue;
434427
if (str_cnt == str_max) {
435428
strs = static_cast<xqd_world_string_t *>(
436-
JS_realloc(CONTEXT, strs, str_max * sizeof(xqd_world_string_t),
437-
(str_max + LIST_ALLOC_SIZE) * sizeof(xqd_world_string_t)));
429+
cabi_realloc(strs, str_max * sizeof(xqd_world_string_t), 1,
430+
(str_max + LIST_ALLOC_SIZE) * sizeof(xqd_world_string_t)));
438431
str_max += LIST_ALLOC_SIZE;
439432
}
440-
strs[str_cnt].ptr = static_cast<char *>(JS_malloc(CONTEXT, i - offset + 1));
433+
strs[str_cnt].ptr = static_cast<char *>(cabi_malloc(i - offset + 1, 1));
441434
strs[str_cnt].len = i - offset;
442435
memcpy(strs[str_cnt].ptr, buf + offset, i - offset + 1);
443436
offset = i + 1;
@@ -447,9 +440,9 @@ bool xqd_fastly_http_resp_header_names_get(fastly_response_handle_t h, fastly_li
447440
break;
448441
cursor = (uint32_t)next_cursor;
449442
}
450-
JS_free(CONTEXT, buf);
451-
strs = static_cast<xqd_world_string_t *>(JS_realloc(
452-
CONTEXT, strs, str_max * sizeof(xqd_world_string_t), str_cnt * sizeof(xqd_world_string_t)));
443+
cabi_free(buf);
444+
strs = static_cast<xqd_world_string_t *>(cabi_realloc(strs, str_max * sizeof(xqd_world_string_t),
445+
1, str_cnt * sizeof(xqd_world_string_t)));
453446
ret->ptr = strs;
454447
ret->len = str_cnt;
455448
return true;
@@ -458,17 +451,17 @@ bool xqd_fastly_http_resp_header_names_get(fastly_response_handle_t h, fastly_li
458451
bool xqd_fastly_http_resp_header_values_get(fastly_response_handle_t h, xqd_world_string_t *name,
459452
fastly_option_list_string_t *ret, fastly_error_t *err) {
460453
size_t str_max = LIST_ALLOC_SIZE;
461-
xqd_world_string_t *strs = static_cast<xqd_world_string_t *>(JS_malloc(CONTEXT, str_max));
454+
xqd_world_string_t *strs = static_cast<xqd_world_string_t *>(cabi_malloc(str_max, 1));
462455
size_t str_cnt = 0;
463456
size_t nwritten;
464-
char *buf = static_cast<char *>(JS_malloc(CONTEXT, HOSTCALL_BUFFER_LEN));
457+
char *buf = static_cast<char *>(cabi_malloc(HOSTCALL_BUFFER_LEN, 1));
465458
uint32_t cursor = 0;
466459
int64_t next_cursor = 0;
467460
while (true) {
468461
if (!convert_result(xqd_resp_header_values_get(h, name->ptr, name->len, buf, HEADER_MAX_LEN,
469462
cursor, &next_cursor, &nwritten),
470463
err)) {
471-
JS_free(CONTEXT, buf);
464+
cabi_free(buf);
472465
return false;
473466
}
474467
if (nwritten == 0)
@@ -479,11 +472,11 @@ bool xqd_fastly_http_resp_header_values_get(fastly_response_handle_t h, xqd_worl
479472
continue;
480473
if (str_cnt == str_max) {
481474
strs = static_cast<xqd_world_string_t *>(
482-
JS_realloc(CONTEXT, strs, str_max * sizeof(xqd_world_string_t),
483-
(str_max + LIST_ALLOC_SIZE) * sizeof(xqd_world_string_t)));
475+
cabi_realloc(strs, str_max * sizeof(xqd_world_string_t), 1,
476+
(str_max + LIST_ALLOC_SIZE) * sizeof(xqd_world_string_t)));
484477
str_max += LIST_ALLOC_SIZE;
485478
}
486-
strs[str_cnt].ptr = static_cast<char *>(JS_malloc(CONTEXT, i - offset + 1));
479+
strs[str_cnt].ptr = static_cast<char *>(cabi_malloc(i - offset + 1, 1));
487480
strs[str_cnt].len = i - offset;
488481
memcpy(strs[str_cnt].ptr, buf + offset, i - offset + 1);
489482
offset = i + 1;
@@ -493,16 +486,16 @@ bool xqd_fastly_http_resp_header_values_get(fastly_response_handle_t h, xqd_worl
493486
break;
494487
cursor = (uint32_t)next_cursor;
495488
}
496-
JS_free(CONTEXT, buf);
489+
cabi_free(buf);
497490
if (str_cnt > 0) {
498491
ret->is_some = true;
499492
ret->val.ptr = strs;
500493
ret->val.len = str_cnt;
501-
strs = static_cast<xqd_world_string_t *>(JS_realloc(
502-
CONTEXT, strs, str_max * sizeof(xqd_world_string_t), str_cnt * sizeof(xqd_world_string_t)));
494+
strs = static_cast<xqd_world_string_t *>(cabi_realloc(
495+
strs, str_max * sizeof(xqd_world_string_t), 1, str_cnt * sizeof(xqd_world_string_t)));
503496
} else {
504497
ret->is_some = false;
505-
JS_free(CONTEXT, strs);
498+
cabi_free(strs);
506499
}
507500
return true;
508501
}
@@ -556,34 +549,34 @@ bool xqd_fastly_dictionary_open(xqd_world_string_t *name, fastly_dictionary_hand
556549

557550
bool xqd_fastly_dictionary_get(fastly_dictionary_handle_t h, xqd_world_string_t *key,
558551
fastly_option_string_t *ret, fastly_error_t *err) {
559-
ret->val.ptr = static_cast<char *>(JS_malloc(CONTEXT, DICTIONARY_ENTRY_MAX_LEN));
552+
ret->val.ptr = static_cast<char *>(cabi_malloc(DICTIONARY_ENTRY_MAX_LEN, 1));
560553
if (!convert_result(xqd_dictionary_get(h, key->ptr, key->len, ret->val.ptr,
561554
DICTIONARY_ENTRY_MAX_LEN, &ret->val.len),
562555
err)) {
563556
if (*err == FASTLY_ERROR_OPTIONAL_NONE) {
564557
ret->is_some = false;
565558
return true;
566559
} else {
567-
JS_free(CONTEXT, ret->val.ptr);
560+
cabi_free(ret->val.ptr);
568561
return false;
569562
}
570563
}
571564
ret->is_some = true;
572-
ret->val.ptr = static_cast<char *>(
573-
JS_realloc(CONTEXT, ret->val.ptr, DICTIONARY_ENTRY_MAX_LEN, ret->val.len));
565+
ret->val.ptr =
566+
static_cast<char *>(cabi_realloc(ret->val.ptr, DICTIONARY_ENTRY_MAX_LEN, 1, ret->val.len));
574567
return true;
575568
}
576569

577570
bool xqd_fastly_geo_lookup(fastly_list_u8_t *addr_octets, xqd_world_string_t *ret,
578571
fastly_error_t *err) {
579-
ret->ptr = static_cast<char *>(JS_malloc(CONTEXT, HOSTCALL_BUFFER_LEN));
572+
ret->ptr = static_cast<char *>(cabi_malloc(HOSTCALL_BUFFER_LEN, 1));
580573
if (!convert_result(xqd_geo_lookup(reinterpret_cast<char *>(addr_octets->ptr), addr_octets->len,
581574
ret->ptr, HOSTCALL_BUFFER_LEN, &ret->len),
582575
err)) {
583-
JS_free(CONTEXT, ret->ptr);
576+
cabi_free(ret->ptr);
584577
return false;
585578
}
586-
ret->ptr = static_cast<char *>(JS_realloc(CONTEXT, ret->ptr, HOSTCALL_BUFFER_LEN, ret->len));
579+
ret->ptr = static_cast<char *>(cabi_realloc(ret->ptr, HOSTCALL_BUFFER_LEN, 1, ret->len));
587580
return true;
588581
}
589582

c-dependencies/js-compute-runtime/xqd-world/xqd_world_adapter.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
#ifndef xqd_world_adapter_h
22
#define xqd_world_adapter_h
33

4-
#include "../host_call.h"
5-
#include "../xqd.h"
4+
#include "allocator.h"
5+
#include "host_call.h"
66
#include "js/JSON.h"
7+
#include "xqd.h"
78
#include "xqd_world.h"
89

9-
static JSContext *CONTEXT = nullptr;
10-
1110
// TODO: remove these once the warnings are fixed
1211
#pragma clang diagnostic push
1312
#pragma clang diagnostic ignored "-Winvalid-offsetof"

0 commit comments

Comments
 (0)