5#ifdef DUK_CMDLINE_AJSHEAP
15extern uint8_t dbgHEAPDUMP;
17#if defined(DUK_USE_ROM_OBJECTS) && defined(DUK_USE_HEAPPTR16)
25extern const void *
const duk_rom_compressed_pointers[];
27static const void *duk__romptr_low =
NULL;
28static const void *duk__romptr_high =
NULL;
29#define DUK__ROMPTR_COMPRESSION
30#define DUK__ROMPTR_FIRST DUK_USE_ROM_PTRCOMP_FIRST
37static void *ajduk__lose_const(
const void *ptr) {
50static void safe_print_chars(
const char *p,
duk_size_t len,
int until_nul) {
54 for (i = 0; i < len; i++) {
55 unsigned char x = (
unsigned char) p[i];
56 if (until_nul && x == 0U) {
59 if (x < 0x20 || x >= 0x7e || x ==
'"' || x ==
'\'' || x ==
'\\') {
60 printf(
"\\x%02x", (
int) x);
84static const AJS_HeapConfig ajsheap_config[] = {
85 { 8, 10, AJS_POOL_BORROW, 0 },
86 { 12, 600, AJS_POOL_BORROW, 0 },
87 { 16, 300, AJS_POOL_BORROW, 0 },
88 { 20, 300, AJS_POOL_BORROW, 0 },
89 { 24, 300, AJS_POOL_BORROW, 0 },
90 { 28, 150, AJS_POOL_BORROW, 0 },
91 { 32, 150, AJS_POOL_BORROW, 0 },
92 { 40, 150, AJS_POOL_BORROW, 0 },
93 { 48, 50, AJS_POOL_BORROW, 0 },
94 { 52, 50, AJS_POOL_BORROW, 0 },
95 { 56, 50, AJS_POOL_BORROW, 0 },
96 { 60, 50, AJS_POOL_BORROW, 0 },
97 { 64, 50, AJS_POOL_BORROW, 0 },
98 { 128, 80, AJS_POOL_BORROW, 0 },
99 { 256, 16, AJS_POOL_BORROW, 0 },
100 { 320, 1, AJS_POOL_BORROW, 0 },
101 { 392, 1, AJS_POOL_BORROW, 0 },
102 { 512, 16, AJS_POOL_BORROW, 0 },
103 { 964, 1, AJS_POOL_BORROW, 0 },
104 { 1024, 6, AJS_POOL_BORROW, 0 },
105 { 1344, 1, AJS_POOL_BORROW, 0 },
106 { 2048, 5, AJS_POOL_BORROW, 0 },
113uint8_t *ajsheap_ram =
NULL;
115void ajsheap_init(
void) {
117 uint8_t *heap_array[1];
118 uint8_t num_pools, i;
121 num_pools = (uint8_t) (
sizeof(ajsheap_config) /
sizeof(AJS_HeapConfig));
122 heap_sz[0] = AJS_HeapRequired(ajsheap_config,
125 ajsheap_ram = (uint8_t *)
malloc(heap_sz[0]);
126 if (ajsheap_ram ==
NULL) {
127 fprintf(stderr,
"Failed to allocate AJS heap\n");
131 heap_array[0] = ajsheap_ram;
133 fprintf(stderr,
"Allocated AJS heap of %ld bytes, pools:", (
long) heap_sz[0]);
134 for (i = 0; i < num_pools; i++) {
135 fprintf(stderr,
" (sz:%ld,num:%ld,brw:%ld,idx:%ld)",
136 (
long) ajsheap_config[i].size, (
long) ajsheap_config[i].entries,
137 (
long) ajsheap_config[i].borrow, (
long) ajsheap_config[i].heapIndex);
139 fprintf(stderr,
"\n");
142 ret = AJS_HeapInit((
void **) heap_array,
147 fprintf(stderr,
"AJS_HeapInit() -> %ld\n", (
long) ret);
153#if defined(DUK__ROMPTR_COMPRESSION)
158 const void *
const * ptrs = (
const void *
const *) duk_rom_compressed_pointers;
159 duk__romptr_low = duk__romptr_high = (
const void *) *ptrs;
161 if (*ptrs > duk__romptr_high) {
162 duk__romptr_high = (
const void *) *ptrs;
164 if (*ptrs < duk__romptr_low) {
165 duk__romptr_low = (
const void *) *ptrs;
169 fprintf(stderr,
"romptrs: low=%p high=%p\n",
170 (
const void *) duk__romptr_low, (
const void *) duk__romptr_high);
176void ajsheap_free(
void) {
177 if (ajsheap_ram !=
NULL) {
192void ajsheap_dump(
void) {
210static FILE *ajsheap_alloc_log =
NULL;
212static void ajsheap_write_alloc_log(
const char *fmt, ...) {
217 vsnprintf(buf,
sizeof(buf), fmt, ap);
218 buf[
sizeof(buf) - 1] = (
char) 0;
221 if (ajsheap_alloc_log ==
NULL) {
222 ajsheap_alloc_log = fopen(
"/tmp/ajduk-alloc-log.txt",
"wb");
223 if (ajsheap_alloc_log ==
NULL) {
224 fprintf(stderr,
"WARNING: failed to write alloc log, ignoring\n");
230 (void)
fwrite((
const void *) buf, 1, strlen(buf), ajsheap_alloc_log);
231 (void) fflush(ajsheap_alloc_log);
234void *ajsheap_alloc_wrapped(
void *udata,
duk_size_t size) {
235 void *ret = AJS_Alloc(udata, size);
236 if (size > 0 && ret ==
NULL) {
237 ajsheap_write_alloc_log(
"A FAIL %ld\n", (
long) size);
238 }
else if (ret ==
NULL) {
239 ajsheap_write_alloc_log(
"A NULL %ld\n", (
long) size);
241 ajsheap_write_alloc_log(
"A %p %ld\n", ret, (
long) size);
246void *ajsheap_realloc_wrapped(
void *udata,
void *ptr,
duk_size_t size) {
247 void *ret = AJS_Realloc(udata, ptr, size);
248 if (size > 0 && ret ==
NULL) {
250 ajsheap_write_alloc_log(
"R NULL -1 FAIL %ld\n", (
long) size);
252 ajsheap_write_alloc_log(
"R %p -1 FAIL %ld\n", ptr, (
long) size);
254 }
else if (ret ==
NULL) {
256 ajsheap_write_alloc_log(
"R NULL -1 NULL %ld\n", (
long) size);
258 ajsheap_write_alloc_log(
"R %p -1 NULL %ld\n", ptr, (
long) size);
262 ajsheap_write_alloc_log(
"R NULL -1 %p %ld\n", ret, (
long) size);
264 ajsheap_write_alloc_log(
"R %p -1 %p %ld\n", ptr, ret, (
long) size);
270void ajsheap_free_wrapped(
void *udata,
void *ptr) {
271 AJS_Free(udata, ptr);
274 ajsheap_write_alloc_log(
"F %p -1\n", ptr);
285duk_uint16_t ajsheap_enc16(
void *ud,
void *p) {
287 char *base = (
char *) ajsheap_ram - 4;
289#if defined(DUK__ROMPTR_COMPRESSION)
290 if (p >= duk__romptr_low && p <= duk__romptr_high) {
297 const void *
const * ptrs = duk_rom_compressed_pointers;
300 ret = DUK__ROMPTR_FIRST + (ptrs - duk_rom_compressed_pointers);
302 fprintf(stderr,
"ajsheap_enc16: rom pointer: %p -> 0x%04lx\n", (
void *) p, (
long) ret);
305 return (duk_uint16_t) ret;
315 fprintf(stderr,
"ajsheap_enc16: rom pointer: %p could not be compressed, should never happen\n", (
void *) p);
335 if (ud != (
void *) 0xdeadbeef) {
336 fprintf(stderr,
"invalid udata for ajsheap_enc16: %p\n", ud);
344 ret = (duk_uint32_t) (((
char *) p - base) >> 2);
347 printf(
"ajsheap_enc16: %p -> %u\n", p, (
unsigned int) ret);
349 if (ret > 0xffffUL) {
350 fprintf(stderr,
"Failed to compress pointer: %p (ret was %ld)\n", (
void *) p, (
long) ret);
354#if defined(DUK__ROMPTR_COMPRESSION)
355 if (ret >= DUK__ROMPTR_FIRST) {
356 fprintf(stderr,
"Failed to compress pointer, in 16-bit range but matches romptr range: %p (ret was %ld)\n", (
void *) p, (
long) ret);
361 return (duk_uint16_t) ret;
364void *ajsheap_dec16(
void *ud, duk_uint16_t x) {
366 char *base = (
char *) ajsheap_ram - 4;
368#if defined(DUK__ROMPTR_COMPRESSION)
369 if (x >= DUK__ROMPTR_FIRST) {
374 ret = (
void *) ajduk__lose_const(duk_rom_compressed_pointers[x - DUK__ROMPTR_FIRST]);
376 fprintf(stderr,
"ajsheap_dec16: rom pointer: 0x%04lx -> %p\n", (
long) x, ret);
387 if (ud != (
void *) 0xdeadbeef) {
388 fprintf(stderr,
"invalid udata for ajsheap_dec16: %p\n", ud);
396 ret = (
void *) (base + (((duk_uint32_t) x) << 2));
399 printf(
"ajsheap_dec16: %u -> %p\n", (
unsigned int) x, ret);
418static uint8_t ajsheap_strdata[65536];
419static size_t ajsheap_strdata_used = 0;
421const void *ajsheap_extstr_check_1(
const void *ptr,
duk_size_t len) {
427 (void) safe_print_chars;
443 initial = ((
const uint8_t *) ptr)[0];
444 for (p = ajsheap_strdata, p_end = p + ajsheap_strdata_used; p != p_end; p++) {
448 left = (size_t) (p_end - p);
449 if (
left >= len + 1 &&
450 memcmp(p, ptr, len) == 0 &&
454 printf(
"ajsheap_extstr_check_1: ptr=%p, len=%ld ",
455 (
void *) ptr, (
long) len);
456 safe_print_chars((
const char *) ptr, len, 0 );
457 printf(
" -> existing %p (used=%ld)\n",
458 (
void *) ret, (
long) ajsheap_strdata_used);
469 if (ajsheap_strdata_used + len + 1 >
sizeof(ajsheap_strdata)) {
471 printf(
"ajsheap_extstr_check_1: ptr=%p, len=%ld ", (
void *) ptr, (
long) len);
472 safe_print_chars((
const char *) ptr, len, 0 );
473 printf(
" -> no space (used=%ld)\n", (
long) ajsheap_strdata_used);
483 ret = ajsheap_strdata + ajsheap_strdata_used;
484 memcpy(ret, ptr, len);
485 ret[len] = (uint8_t) 0;
486 ajsheap_strdata_used += len + 1;
489 printf(
"ajsheap_extstr_check_1: ptr=%p, len=%ld -> ", (
void *) ptr, (
long) len);
490 safe_print_chars((
const char *) ptr, len, 0 );
491 printf(
" -> %p (used=%ld)\n", (
void *) ret, (
long) ajsheap_strdata_used);
493 return (
const void *) ret;
496void ajsheap_extstr_free_1(
const void *ptr) {
499 printf(
"ajsheap_extstr_free_1: freeing extstr %p -> ", ptr);
516static const char *strdata_duk_builtin_strings[] = {
544 "{\x22" "_func\x22" ":true}",
545 "{\x22" "_ninf\x22" ":true}",
546 "{\x22" "_inf\x22" ":true}",
547 "{\x22" "_nan\x22" ":true}",
548 "{\x22" "_undef\x22" ":true}",
689 "setUTCMilliseconds",
693 "getUTCMilliseconds",
710 "toLocaleTimeString",
711 "toLocaleDateString",
765 "propertyIsEnumerable",
788 "getOwnPropertyNames",
789 "getOwnPropertyDescriptor",
797 "encodeURIComponent",
799 "decodeURIComponent",
871const void *ajsheap_extstr_check_2(
const void *ptr,
duk_size_t len) {
874 (void) safe_print_chars;
884 n = (int) (
sizeof(strdata_duk_builtin_strings) /
sizeof(
const char *));
885 for (i = 0; i < n; i++) {
888 str = strdata_duk_builtin_strings[i];
889 if (strlen(str) == len && memcmp(ptr, (
const void *) str, len) == 0) {
891 printf(
"ajsheap_extstr_check_2: ptr=%p, len=%ld ",
892 (
void *) ptr, (
long) len);
893 safe_print_chars((
const char *) ptr, len, 0 );
894 printf(
" -> constant string index %ld\n", (
long) i);
896 return (
void *) ajduk__lose_const(strdata_duk_builtin_strings[i]);
901 printf(
"ajsheap_extstr_check_2: ptr=%p, len=%ld ",
902 (
void *) ptr, (
long) len);
903 safe_print_chars((
const char *) ptr, len, 0 );
904 printf(
" -> not found\n");
909void ajsheap_extstr_free_2(
const void *ptr) {
912 printf(
"ajsheap_extstr_free_2: freeing extstr %p -> ", ptr);
924const void *ajsheap_extstr_check_3(
const void *ptr,
duk_size_t len) {
927 (void) safe_print_chars;
929 ret =
malloc((
size_t) len + 1);
932 printf(
"ajsheap_extstr_check_3: ptr=%p, len=%ld ",
933 (
void *) ptr, (
long) len);
934 safe_print_chars((
const char *) ptr, len, 0 );
935 printf(
" -> malloc failed, return NULL\n");
937 return (
const void *)
NULL;
941 memcpy((
void *) ret, ptr, (
size_t) len);
943 ret[len] = (duk_uint8_t) 0;
946 printf(
"ajsheap_extstr_check_3: ptr=%p, len=%ld ",
947 (
void *) ptr, (
long) len);
948 safe_print_chars((
const char *) ptr, len, 0 );
949 printf(
" -> %p\n", (
void *) ret);
951 return (
const void *) ret;
954void ajsheap_extstr_free_3(
const void *ptr) {
957 printf(
"ajsheap_extstr_free_3: freeing extstr %p -> ", ptr);
961 free((
void *) ajduk__lose_const(ptr));
968#define AJSHEAP_EXEC_TIMEOUT 5
970static time_t curr_pcall_start = 0;
971static long exec_timeout_check_counter = 0;
973void ajsheap_start_exec_timeout(
void) {
974 curr_pcall_start = time(
NULL);
977void ajsheap_clear_exec_timeout(
void) {
978 curr_pcall_start = 0;
981duk_bool_t ajsheap_exec_timeout_check(
void *udata) {
982 time_t now = time(
NULL);
983 time_t diff = now - curr_pcall_start;
987 exec_timeout_check_counter++;
989 printf(
"exec timeout check %ld: now=%ld, start=%ld, diff=%ld\n",
990 (
long) exec_timeout_check_counter, (
long) now, (
long) curr_pcall_start, (
long) diff);
994 if (curr_pcall_start == 0) {
998 if (diff > AJSHEAP_EXEC_TIMEOUT) {
duk_small_int_t duk_ret_t
duk_small_int_t duk_bool_t
DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key)
DUK_EXTERNAL duk_idx_t duk_push_c_function(duk_context *ctx, duk_c_function func, duk_int_t nargs)
DUK_EXTERNAL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key)
DUK_EXTERNAL duk_idx_t duk_push_object(duk_context *ctx)