]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /* |
2 | * 'ajduk' specific functionality, examples for low memory techniques | |
3 | */ | |
4 | ||
5 | #ifdef DUK_CMDLINE_AJSHEAP | |
6 | ||
7 | #include <stdio.h> | |
8 | #include <stdlib.h> | |
9 | #include <string.h> | |
10 | #include <time.h> | |
11 | #include "ajs.h" | |
12 | #include "ajs_heap.h" | |
11fdf7f2 | 13 | #include "duktape.h" |
7c673cae FG |
14 | |
15 | extern uint8_t dbgHEAPDUMP; | |
16 | ||
11fdf7f2 TL |
17 | #if defined(DUK_USE_ROM_OBJECTS) && defined(DUK_USE_HEAPPTR16) |
18 | /* Pointer compression with ROM strings/objects: | |
19 | * | |
20 | * For now, use DUK_USE_ROM_OBJECTS to signal the need for compressed ROM | |
21 | * pointers. DUK_USE_ROM_PTRCOMP_FIRST is provided for the ROM pointer | |
22 | * compression range minimum to avoid duplication in user code. | |
23 | */ | |
24 | #if 0 /* This extern declaration is provided by duktape.h, array provided by duktape.c. */ | |
25 | extern const void * const duk_rom_compressed_pointers[]; | |
26 | #endif | |
27 | static const void *duk__romptr_low = NULL; | |
28 | static const void *duk__romptr_high = NULL; | |
29 | #define DUK__ROMPTR_COMPRESSION | |
30 | #define DUK__ROMPTR_FIRST DUK_USE_ROM_PTRCOMP_FIRST | |
31 | #endif | |
32 | ||
7c673cae FG |
33 | /* |
34 | * Helpers | |
35 | */ | |
36 | ||
11fdf7f2 TL |
37 | static void *ajduk__lose_const(const void *ptr) { |
38 | /* Somewhat portable way of losing a const without warnings. | |
39 | * Another approach is to cast through intptr_t, but that | |
40 | * type is not always available. | |
41 | */ | |
42 | union { | |
43 | const void *p; | |
44 | void *q; | |
45 | } u; | |
46 | u.p = ptr; | |
47 | return u.q; | |
48 | } | |
49 | ||
7c673cae FG |
50 | static void safe_print_chars(const char *p, duk_size_t len, int until_nul) { |
51 | duk_size_t i; | |
52 | ||
53 | printf("\""); | |
54 | for (i = 0; i < len; i++) { | |
55 | unsigned char x = (unsigned char) p[i]; | |
56 | if (until_nul && x == 0U) { | |
57 | break; | |
58 | } | |
59 | if (x < 0x20 || x >= 0x7e || x == '"' || x == '\'' || x == '\\') { | |
60 | printf("\\x%02x", (int) x); | |
61 | } else { | |
62 | printf("%c", (char) x); | |
63 | } | |
64 | } | |
65 | printf("\""); | |
66 | } | |
67 | ||
68 | /* | |
69 | * Heap initialization when using AllJoyn.js pool allocator (without any | |
70 | * other AllJoyn.js integration). This serves as an example of how to | |
71 | * integrate Duktape with a pool allocator and is useful for low memory | |
72 | * testing. | |
73 | * | |
74 | * The pool sizes are not optimized here. The sizes are chosen so that | |
75 | * you can look at the high water mark (hwm) and use counts (use) and see | |
76 | * how much allocations are needed for each pool size. To optimize pool | |
77 | * sizes more accurately, you can use --alloc-logging and inspect the memory | |
78 | * allocation log which provides exact byte counts etc. | |
79 | * | |
80 | * https://git.allseenalliance.org/cgit/core/alljoyn-js.git | |
81 | * https://git.allseenalliance.org/cgit/core/alljoyn-js.git/tree/ajs.c | |
82 | */ | |
83 | ||
84 | static const AJS_HeapConfig ajsheap_config[] = { | |
85 | { 8, 10, AJS_POOL_BORROW, 0 }, | |
11fdf7f2 TL |
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 }, | |
7c673cae FG |
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 }, | |
11fdf7f2 TL |
100 | { 320, 1, AJS_POOL_BORROW, 0 }, |
101 | { 392, 1, AJS_POOL_BORROW, 0 }, /* duk_hthread, with heap ptr compression, ROM strings+objects */ | |
7c673cae | 102 | { 512, 16, AJS_POOL_BORROW, 0 }, |
11fdf7f2 | 103 | { 964, 1, AJS_POOL_BORROW, 0 }, /* duk_heap, with heap ptr compression, ROM strings+objects */ |
7c673cae | 104 | { 1024, 6, AJS_POOL_BORROW, 0 }, |
11fdf7f2 | 105 | { 1344, 1, AJS_POOL_BORROW, 0 }, /* duk_heap, with heap ptr compression, RAM strings+objects */ |
7c673cae FG |
106 | { 2048, 5, AJS_POOL_BORROW, 0 }, |
107 | { 4096, 3, 0, 0 }, | |
108 | { 8192, 3, 0, 0 }, | |
109 | { 16384, 1, 0, 0 }, | |
110 | { 32768, 1, 0, 0 } | |
111 | }; | |
112 | ||
113 | uint8_t *ajsheap_ram = NULL; | |
114 | ||
115 | void ajsheap_init(void) { | |
116 | size_t heap_sz[1]; | |
117 | uint8_t *heap_array[1]; | |
118 | uint8_t num_pools, i; | |
119 | AJ_Status ret; | |
120 | ||
121 | num_pools = (uint8_t) (sizeof(ajsheap_config) / sizeof(AJS_HeapConfig)); | |
122 | heap_sz[0] = AJS_HeapRequired(ajsheap_config, /* heapConfig */ | |
123 | num_pools, /* numPools */ | |
124 | 0); /* heapNum */ | |
125 | ajsheap_ram = (uint8_t *) malloc(heap_sz[0]); | |
126 | if (ajsheap_ram == NULL) { | |
127 | fprintf(stderr, "Failed to allocate AJS heap\n"); | |
128 | fflush(stderr); | |
129 | exit(1); | |
130 | } | |
131 | heap_array[0] = ajsheap_ram; | |
132 | ||
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); | |
138 | } | |
139 | fprintf(stderr, "\n"); | |
140 | fflush(stderr); | |
141 | ||
142 | ret = AJS_HeapInit((void **) heap_array, /* heap */ | |
143 | (size_t *) heap_sz, /* heapSz */ | |
144 | ajsheap_config, /* heapConfig */ | |
145 | num_pools, /* numPools */ | |
146 | 1); /* numHeaps */ | |
147 | fprintf(stderr, "AJS_HeapInit() -> %ld\n", (long) ret); | |
148 | fflush(stderr); | |
149 | ||
150 | /* Enable heap dumps */ | |
151 | dbgHEAPDUMP = 1; | |
11fdf7f2 TL |
152 | |
153 | #if defined(DUK__ROMPTR_COMPRESSION) | |
154 | /* Scan ROM pointer range for faster detection of "is 'p' a ROM pointer" | |
155 | * later on. | |
156 | */ | |
157 | if (1) { | |
158 | const void * const * ptrs = (const void * const *) duk_rom_compressed_pointers; | |
159 | duk__romptr_low = duk__romptr_high = (const void *) *ptrs; | |
160 | while (*ptrs) { | |
161 | if (*ptrs > duk__romptr_high) { | |
162 | duk__romptr_high = (const void *) *ptrs; | |
163 | } | |
164 | if (*ptrs < duk__romptr_low) { | |
165 | duk__romptr_low = (const void *) *ptrs; | |
166 | } | |
167 | ptrs++; | |
168 | } | |
169 | fprintf(stderr, "romptrs: low=%p high=%p\n", | |
170 | (const void *) duk__romptr_low, (const void *) duk__romptr_high); | |
171 | fflush(stderr); | |
172 | } | |
173 | #endif | |
174 | } | |
175 | ||
176 | void ajsheap_free(void) { | |
177 | if (ajsheap_ram != NULL) { | |
178 | free(ajsheap_ram); | |
179 | ajsheap_ram = NULL; | |
180 | } | |
7c673cae FG |
181 | } |
182 | ||
183 | /* AjsHeap.dump(), allows Ecmascript code to dump heap status at suitable | |
184 | * points. | |
185 | */ | |
186 | duk_ret_t ajsheap_dump_binding(duk_context *ctx) { | |
187 | AJS_HeapDump(); | |
188 | fflush(stdout); | |
189 | return 0; | |
190 | } | |
191 | ||
192 | void ajsheap_dump(void) { | |
193 | AJS_HeapDump(); | |
194 | fflush(stdout); | |
195 | } | |
196 | ||
197 | void ajsheap_register(duk_context *ctx) { | |
198 | duk_push_object(ctx); | |
199 | duk_push_c_function(ctx, ajsheap_dump_binding, 0); | |
200 | duk_put_prop_string(ctx, -2, "dump"); | |
201 | duk_put_global_string(ctx, "AjsHeap"); | |
202 | } | |
203 | ||
204 | /* | |
205 | * Wrapped ajs_heap.c alloc functions | |
206 | * | |
207 | * Used to write an alloc log. | |
208 | */ | |
209 | ||
210 | static FILE *ajsheap_alloc_log = NULL; | |
211 | ||
212 | static void ajsheap_write_alloc_log(const char *fmt, ...) { | |
213 | va_list ap; | |
214 | char buf[256]; | |
215 | ||
216 | va_start(ap, fmt); | |
217 | vsnprintf(buf, sizeof(buf), fmt, ap); | |
218 | buf[sizeof(buf) - 1] = (char) 0; | |
219 | va_end(ap); | |
220 | ||
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"); | |
225 | fflush(stderr); | |
226 | return; | |
227 | } | |
228 | } | |
229 | ||
230 | (void) fwrite((const void *) buf, 1, strlen(buf), ajsheap_alloc_log); | |
231 | (void) fflush(ajsheap_alloc_log); | |
232 | } | |
233 | ||
234 | void *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); | |
240 | } else { | |
241 | ajsheap_write_alloc_log("A %p %ld\n", ret, (long) size); | |
242 | } | |
243 | return ret; | |
244 | } | |
245 | ||
246 | void *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) { | |
249 | if (ptr == NULL) { | |
250 | ajsheap_write_alloc_log("R NULL -1 FAIL %ld\n", (long) size); | |
251 | } else { | |
252 | ajsheap_write_alloc_log("R %p -1 FAIL %ld\n", ptr, (long) size); | |
253 | } | |
254 | } else if (ret == NULL) { | |
255 | if (ptr == NULL) { | |
256 | ajsheap_write_alloc_log("R NULL -1 NULL %ld\n", (long) size); | |
257 | } else { | |
258 | ajsheap_write_alloc_log("R %p -1 NULL %ld\n", ptr, (long) size); | |
259 | } | |
260 | } else { | |
261 | if (ptr == NULL) { | |
262 | ajsheap_write_alloc_log("R NULL -1 %p %ld\n", ret, (long) size); | |
263 | } else { | |
264 | ajsheap_write_alloc_log("R %p -1 %p %ld\n", ptr, ret, (long) size); | |
265 | } | |
266 | } | |
267 | return ret; | |
268 | } | |
269 | ||
270 | void ajsheap_free_wrapped(void *udata, void *ptr) { | |
271 | AJS_Free(udata, ptr); | |
272 | if (ptr == NULL) { | |
273 | } else { | |
274 | ajsheap_write_alloc_log("F %p -1\n", ptr); | |
275 | } | |
276 | } | |
277 | ||
278 | /* | |
279 | * Example pointer compression functions. | |
280 | * | |
281 | * 'base' is chosen so that no non-NULL pointer results in a zero result | |
282 | * which is reserved for NULL pointers. | |
283 | */ | |
284 | ||
285 | duk_uint16_t ajsheap_enc16(void *ud, void *p) { | |
286 | duk_uint32_t ret; | |
287 | char *base = (char *) ajsheap_ram - 4; | |
288 | ||
11fdf7f2 TL |
289 | #if defined(DUK__ROMPTR_COMPRESSION) |
290 | if (p >= duk__romptr_low && p <= duk__romptr_high) { | |
291 | /* The if-condition should be the fastest possible check | |
292 | * for "is 'p' in ROM?". If pointer is in ROM, we'd like | |
293 | * to compress it quickly. Here we just scan a ~1K array | |
294 | * which is very bad for performance and for illustration | |
295 | * only. | |
296 | */ | |
297 | const void * const * ptrs = duk_rom_compressed_pointers; | |
298 | while (*ptrs) { | |
299 | if (*ptrs == p) { | |
300 | ret = DUK__ROMPTR_FIRST + (ptrs - duk_rom_compressed_pointers); | |
301 | #if 0 | |
302 | fprintf(stderr, "ajsheap_enc16: rom pointer: %p -> 0x%04lx\n", (void *) p, (long) ret); | |
303 | fflush(stderr); | |
304 | #endif | |
305 | return (duk_uint16_t) ret; | |
306 | } | |
307 | ptrs++; | |
308 | } | |
309 | ||
310 | /* We should really never be here: Duktape should only be | |
311 | * compressing pointers which are in the ROM compressed | |
312 | * pointers list, which are known at 'make dist' time. | |
313 | * We go on, causing a pointer compression error. | |
314 | */ | |
315 | fprintf(stderr, "ajsheap_enc16: rom pointer: %p could not be compressed, should never happen\n", (void *) p); | |
316 | fflush(stderr); | |
317 | } | |
318 | #endif | |
319 | ||
7c673cae FG |
320 | /* Userdata is not needed in this case but would be useful if heap |
321 | * pointer compression were used for multiple heaps. The userdata | |
322 | * allows the callback to distinguish between heaps and their base | |
323 | * pointers. | |
324 | * | |
325 | * If not needed, the userdata can be left out during compilation | |
326 | * by simply ignoring the userdata argument of the pointer encode | |
327 | * and decode macros. It is kept here so that any bugs in actually | |
328 | * providing the value inside Duktape are revealed during compilation. | |
329 | */ | |
330 | (void) ud; | |
331 | #if 1 | |
332 | /* Ensure that we always get the heap_udata given in heap creation. | |
333 | * (Useful for Duktape development, not needed for user programs.) | |
334 | */ | |
335 | if (ud != (void *) 0xdeadbeef) { | |
336 | fprintf(stderr, "invalid udata for ajsheap_enc16: %p\n", ud); | |
337 | fflush(stderr); | |
338 | } | |
339 | #endif | |
340 | ||
341 | if (p == NULL) { | |
342 | ret = 0; | |
343 | } else { | |
344 | ret = (duk_uint32_t) (((char *) p - base) >> 2); | |
345 | } | |
346 | #if 0 | |
347 | printf("ajsheap_enc16: %p -> %u\n", p, (unsigned int) ret); | |
348 | #endif | |
349 | if (ret > 0xffffUL) { | |
11fdf7f2 TL |
350 | fprintf(stderr, "Failed to compress pointer: %p (ret was %ld)\n", (void *) p, (long) ret); |
351 | fflush(stderr); | |
352 | abort(); | |
353 | } | |
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); | |
7c673cae FG |
357 | fflush(stderr); |
358 | abort(); | |
359 | } | |
11fdf7f2 | 360 | #endif |
7c673cae FG |
361 | return (duk_uint16_t) ret; |
362 | } | |
11fdf7f2 | 363 | |
7c673cae FG |
364 | void *ajsheap_dec16(void *ud, duk_uint16_t x) { |
365 | void *ret; | |
366 | char *base = (char *) ajsheap_ram - 4; | |
367 | ||
11fdf7f2 TL |
368 | #if defined(DUK__ROMPTR_COMPRESSION) |
369 | if (x >= DUK__ROMPTR_FIRST) { | |
370 | /* This is a blind lookup, could check index validity. | |
371 | * Duktape should never decompress a pointer which would | |
372 | * be out-of-bounds here. | |
373 | */ | |
374 | ret = (void *) ajduk__lose_const(duk_rom_compressed_pointers[x - DUK__ROMPTR_FIRST]); | |
375 | #if 0 | |
376 | fprintf(stderr, "ajsheap_dec16: rom pointer: 0x%04lx -> %p\n", (long) x, ret); | |
377 | fflush(stderr); | |
378 | #endif | |
379 | return ret; | |
380 | } | |
381 | #endif | |
382 | ||
7c673cae FG |
383 | /* See userdata discussion in ajsheap_enc16(). */ |
384 | (void) ud; | |
385 | #if 1 | |
386 | /* Ensure that we always get the heap_udata given in heap creation. */ | |
387 | if (ud != (void *) 0xdeadbeef) { | |
388 | fprintf(stderr, "invalid udata for ajsheap_dec16: %p\n", ud); | |
389 | fflush(stderr); | |
390 | } | |
391 | #endif | |
392 | ||
393 | if (x == 0) { | |
394 | ret = NULL; | |
395 | } else { | |
396 | ret = (void *) (base + (((duk_uint32_t) x) << 2)); | |
397 | } | |
398 | #if 0 | |
399 | printf("ajsheap_dec16: %u -> %p\n", (unsigned int) x, ret); | |
400 | #endif | |
401 | return ret; | |
402 | } | |
403 | ||
404 | /* | |
405 | * Simplified example of an external strings strategy where incoming strings | |
406 | * are written sequentially into a fixed, memory mapped flash area. | |
407 | * | |
408 | * The example first scans if the string is already in the flash (which may | |
409 | * happen if the same string is interned multiple times), then adds it to | |
410 | * flash if there is space. | |
411 | * | |
412 | * This example is too slow to be used in a real world application: there | |
413 | * should be e.g. a hash table to quickly check for strings that are already | |
414 | * present in the string data (similarly to how string interning works in | |
415 | * Duktape itself). | |
416 | */ | |
417 | ||
418 | static uint8_t ajsheap_strdata[65536]; | |
419 | static size_t ajsheap_strdata_used = 0; | |
420 | ||
421 | const void *ajsheap_extstr_check_1(const void *ptr, duk_size_t len) { | |
422 | uint8_t *p, *p_end; | |
423 | uint8_t initial; | |
424 | uint8_t *ret; | |
425 | size_t left; | |
426 | ||
427 | (void) safe_print_chars; /* potentially unused */ | |
428 | ||
429 | if (len <= 3) { | |
430 | /* It's not worth it to make very small strings external, as | |
431 | * they would take the same space anyway. Also avoids zero | |
432 | * length degenerate case. | |
433 | */ | |
434 | return NULL; | |
435 | } | |
436 | ||
437 | /* | |
438 | * Check if we already have the string. Be careful to compare for | |
439 | * NUL terminator too, it is NOT present in 'ptr'. This algorithm | |
440 | * is too simplistic and way too slow for actual use. | |
441 | */ | |
442 | ||
443 | initial = ((const uint8_t *) ptr)[0]; | |
444 | for (p = ajsheap_strdata, p_end = p + ajsheap_strdata_used; p != p_end; p++) { | |
445 | if (*p != initial) { | |
446 | continue; | |
447 | } | |
448 | left = (size_t) (p_end - p); | |
449 | if (left >= len + 1 && | |
450 | memcmp(p, ptr, len) == 0 && | |
451 | p[len] == 0) { | |
452 | ret = p; | |
453 | #if 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 /*until_nul*/); | |
457 | printf(" -> existing %p (used=%ld)\n", | |
458 | (void *) ret, (long) ajsheap_strdata_used); | |
459 | #endif | |
460 | return ret; | |
461 | } | |
462 | } | |
463 | ||
464 | /* | |
465 | * Not present yet, check if we have space. Again, be careful to | |
466 | * ensure there is space for a NUL following the input data. | |
467 | */ | |
468 | ||
469 | if (ajsheap_strdata_used + len + 1 > sizeof(ajsheap_strdata)) { | |
470 | #if 0 | |
471 | printf("ajsheap_extstr_check_1: ptr=%p, len=%ld ", (void *) ptr, (long) len); | |
472 | safe_print_chars((const char *) ptr, len, 0 /*until_nul*/); | |
473 | printf(" -> no space (used=%ld)\n", (long) ajsheap_strdata_used); | |
474 | #endif | |
475 | return NULL; | |
476 | } | |
477 | ||
478 | /* | |
479 | * There is space, add the string to our collection, being careful | |
480 | * to append the NUL. | |
481 | */ | |
482 | ||
483 | ret = ajsheap_strdata + ajsheap_strdata_used; | |
484 | memcpy(ret, ptr, len); | |
485 | ret[len] = (uint8_t) 0; | |
486 | ajsheap_strdata_used += len + 1; | |
487 | ||
488 | #if 0 | |
489 | printf("ajsheap_extstr_check_1: ptr=%p, len=%ld -> ", (void *) ptr, (long) len); | |
490 | safe_print_chars((const char *) ptr, len, 0 /*until_nul*/); | |
491 | printf(" -> %p (used=%ld)\n", (void *) ret, (long) ajsheap_strdata_used); | |
492 | #endif | |
493 | return (const void *) ret; | |
494 | } | |
495 | ||
496 | void ajsheap_extstr_free_1(const void *ptr) { | |
497 | (void) ptr; | |
498 | #if 0 | |
499 | printf("ajsheap_extstr_free_1: freeing extstr %p -> ", ptr); | |
500 | safe_print_chars((const char *) ptr, DUK_SIZE_MAX, 1 /*until_nul*/); | |
501 | printf("\n"); | |
502 | #endif | |
503 | } | |
504 | ||
505 | /* | |
506 | * Simplified example of an external strings strategy where a set of strings | |
507 | * is gathered during application compile time and baked into the application | |
508 | * binary. | |
509 | * | |
510 | * Duktape built-in strings are available from duk_build_meta.json, see | |
511 | * util/duk_meta_to_strarray.py. There may also be a lot of application | |
512 | * specific strings, e.g. those used by application specific APIs. These | |
513 | * must be gathered through some other means, see e.g. util/scan_strings.py. | |
514 | */ | |
515 | ||
516 | static const char *strdata_duk_builtin_strings[] = { | |
517 | /* | |
518 | * These strings are from util/duk_meta_to_strarray.py | |
519 | */ | |
520 | ||
521 | "Logger", | |
522 | "Thread", | |
523 | "Pointer", | |
524 | "Buffer", | |
525 | "DecEnv", | |
526 | "ObjEnv", | |
527 | "", | |
528 | "global", | |
529 | "Arguments", | |
530 | "JSON", | |
531 | "Math", | |
532 | "Error", | |
533 | "RegExp", | |
534 | "Date", | |
535 | "Number", | |
536 | "Boolean", | |
537 | "String", | |
538 | "Array", | |
539 | "Function", | |
540 | "Object", | |
541 | "Null", | |
542 | "Undefined", | |
543 | "{_func:true}", | |
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}", | |
549 | "toLogString", | |
550 | "clog", | |
551 | "l", | |
552 | "n", | |
553 | "fatal", | |
554 | "error", | |
555 | "warn", | |
556 | "debug", | |
557 | "trace", | |
558 | "raw", | |
559 | "fmt", | |
560 | "current", | |
561 | "resume", | |
562 | "compact", | |
563 | "jc", | |
564 | "jx", | |
565 | "base64", | |
566 | "hex", | |
567 | "dec", | |
568 | "enc", | |
569 | "fin", | |
570 | "gc", | |
571 | "act", | |
572 | "info", | |
573 | "version", | |
574 | "env", | |
575 | "modLoaded", | |
576 | "modSearch", | |
577 | "errThrow", | |
578 | "errCreate", | |
579 | "compile", | |
580 | "\xff" "Regbase", | |
581 | "\xff" "Thread", | |
582 | "\xff" "Handler", | |
583 | "\xff" "Finalizer", | |
584 | "\xff" "Callee", | |
585 | "\xff" "Map", | |
586 | "\xff" "Args", | |
587 | "\xff" "This", | |
588 | "\xff" "Pc2line", | |
589 | "\xff" "Source", | |
590 | "\xff" "Varenv", | |
591 | "\xff" "Lexenv", | |
592 | "\xff" "Varmap", | |
593 | "\xff" "Formals", | |
594 | "\xff" "Bytecode", | |
595 | "\xff" "Next", | |
596 | "\xff" "Target", | |
597 | "\xff" "Value", | |
598 | "pointer", | |
599 | "buffer", | |
600 | "\xff" "Tracedata", | |
601 | "lineNumber", | |
602 | "fileName", | |
603 | "pc", | |
604 | "stack", | |
605 | "ThrowTypeError", | |
606 | "Duktape", | |
607 | "id", | |
608 | "require", | |
609 | "__proto__", | |
610 | "setPrototypeOf", | |
611 | "ownKeys", | |
612 | "enumerate", | |
613 | "deleteProperty", | |
614 | "has", | |
615 | "Proxy", | |
616 | "callee", | |
617 | "Invalid Date", | |
618 | "[...]", | |
619 | "\x0a" "\x09", | |
620 | " ", | |
621 | ",", | |
622 | "-0", | |
623 | "+0", | |
624 | "0", | |
625 | "-Infinity", | |
626 | "+Infinity", | |
627 | "Infinity", | |
628 | "object", | |
629 | "string", | |
630 | "number", | |
631 | "boolean", | |
632 | "undefined", | |
633 | "stringify", | |
634 | "tan", | |
635 | "sqrt", | |
636 | "sin", | |
637 | "round", | |
638 | "random", | |
639 | "pow", | |
640 | "min", | |
641 | "max", | |
642 | "log", | |
643 | "floor", | |
644 | "exp", | |
645 | "cos", | |
646 | "ceil", | |
647 | "atan2", | |
648 | "atan", | |
649 | "asin", | |
650 | "acos", | |
651 | "abs", | |
652 | "SQRT2", | |
653 | "SQRT1_2", | |
654 | "PI", | |
655 | "LOG10E", | |
656 | "LOG2E", | |
657 | "LN2", | |
658 | "LN10", | |
659 | "E", | |
660 | "message", | |
661 | "name", | |
662 | "input", | |
663 | "index", | |
664 | "(?:)", | |
665 | "lastIndex", | |
666 | "multiline", | |
667 | "ignoreCase", | |
668 | "source", | |
669 | "test", | |
670 | "exec", | |
671 | "toGMTString", | |
672 | "setYear", | |
673 | "getYear", | |
674 | "toJSON", | |
675 | "toISOString", | |
676 | "toUTCString", | |
677 | "setUTCFullYear", | |
678 | "setFullYear", | |
679 | "setUTCMonth", | |
680 | "setMonth", | |
681 | "setUTCDate", | |
682 | "setDate", | |
683 | "setUTCHours", | |
684 | "setHours", | |
685 | "setUTCMinutes", | |
686 | "setMinutes", | |
687 | "setUTCSeconds", | |
688 | "setSeconds", | |
689 | "setUTCMilliseconds", | |
690 | "setMilliseconds", | |
691 | "setTime", | |
692 | "getTimezoneOffset", | |
693 | "getUTCMilliseconds", | |
694 | "getMilliseconds", | |
695 | "getUTCSeconds", | |
696 | "getSeconds", | |
697 | "getUTCMinutes", | |
698 | "getMinutes", | |
699 | "getUTCHours", | |
700 | "getHours", | |
701 | "getUTCDay", | |
702 | "getDay", | |
703 | "getUTCDate", | |
704 | "getDate", | |
705 | "getUTCMonth", | |
706 | "getMonth", | |
707 | "getUTCFullYear", | |
708 | "getFullYear", | |
709 | "getTime", | |
710 | "toLocaleTimeString", | |
711 | "toLocaleDateString", | |
712 | "toTimeString", | |
713 | "toDateString", | |
714 | "now", | |
715 | "UTC", | |
716 | "parse", | |
717 | "toPrecision", | |
718 | "toExponential", | |
719 | "toFixed", | |
720 | "POSITIVE_INFINITY", | |
721 | "NEGATIVE_INFINITY", | |
722 | "NaN", | |
723 | "MIN_VALUE", | |
724 | "MAX_VALUE", | |
725 | "substr", | |
726 | "trim", | |
727 | "toLocaleUpperCase", | |
728 | "toUpperCase", | |
729 | "toLocaleLowerCase", | |
730 | "toLowerCase", | |
731 | "substring", | |
732 | "split", | |
733 | "search", | |
734 | "replace", | |
735 | "match", | |
736 | "localeCompare", | |
737 | "charCodeAt", | |
738 | "charAt", | |
739 | "fromCharCode", | |
740 | "reduceRight", | |
741 | "reduce", | |
742 | "filter", | |
743 | "map", | |
744 | "forEach", | |
745 | "some", | |
746 | "every", | |
747 | "lastIndexOf", | |
748 | "indexOf", | |
749 | "unshift", | |
750 | "splice", | |
751 | "sort", | |
752 | "slice", | |
753 | "shift", | |
754 | "reverse", | |
755 | "push", | |
756 | "pop", | |
757 | "join", | |
758 | "concat", | |
759 | "isArray", | |
760 | "arguments", | |
761 | "caller", | |
762 | "bind", | |
763 | "call", | |
764 | "apply", | |
765 | "propertyIsEnumerable", | |
766 | "isPrototypeOf", | |
767 | "hasOwnProperty", | |
768 | "valueOf", | |
769 | "toLocaleString", | |
770 | "toString", | |
771 | "constructor", | |
772 | "set", | |
773 | "get", | |
774 | "enumerable", | |
775 | "configurable", | |
776 | "writable", | |
777 | "value", | |
778 | "keys", | |
779 | "isExtensible", | |
780 | "isFrozen", | |
781 | "isSealed", | |
782 | "preventExtensions", | |
783 | "freeze", | |
784 | "seal", | |
785 | "defineProperties", | |
786 | "defineProperty", | |
787 | "create", | |
788 | "getOwnPropertyNames", | |
789 | "getOwnPropertyDescriptor", | |
790 | "getPrototypeOf", | |
791 | "prototype", | |
792 | "length", | |
793 | "alert", | |
794 | "print", | |
795 | "unescape", | |
796 | "escape", | |
797 | "encodeURIComponent", | |
798 | "encodeURI", | |
799 | "decodeURIComponent", | |
800 | "decodeURI", | |
801 | "isFinite", | |
802 | "isNaN", | |
803 | "parseFloat", | |
804 | "parseInt", | |
805 | "eval", | |
806 | "URIError", | |
807 | "TypeError", | |
808 | "SyntaxError", | |
809 | "ReferenceError", | |
810 | "RangeError", | |
811 | "EvalError", | |
812 | "break", | |
813 | "case", | |
814 | "catch", | |
815 | "continue", | |
816 | "debugger", | |
817 | "default", | |
818 | "delete", | |
819 | "do", | |
820 | "else", | |
821 | "finally", | |
822 | "for", | |
823 | "function", | |
824 | "if", | |
825 | "in", | |
826 | "instanceof", | |
827 | "new", | |
828 | "return", | |
829 | "switch", | |
830 | "this", | |
831 | "throw", | |
832 | "try", | |
833 | "typeof", | |
834 | "var", | |
835 | "void", | |
836 | "while", | |
837 | "with", | |
838 | "class", | |
839 | "const", | |
840 | "enum", | |
841 | "export", | |
842 | "extends", | |
843 | "import", | |
844 | "super", | |
845 | "null", | |
846 | "true", | |
847 | "false", | |
848 | "implements", | |
849 | "interface", | |
850 | "let", | |
851 | "package", | |
852 | "private", | |
853 | "protected", | |
854 | "public", | |
855 | "static", | |
856 | "yield", | |
857 | ||
858 | /* | |
859 | * These strings are manually added, and would be gathered in some | |
860 | * application specific manner. | |
861 | */ | |
862 | ||
863 | "foo", | |
864 | "bar", | |
865 | "quux", | |
866 | "enableFrob", | |
867 | "disableFrob" | |
868 | /* ... */ | |
869 | }; | |
870 | ||
871 | const void *ajsheap_extstr_check_2(const void *ptr, duk_size_t len) { | |
872 | int i, n; | |
873 | ||
874 | (void) safe_print_chars; /* potentially unused */ | |
875 | ||
876 | /* Linear scan. An actual implementation would need some acceleration | |
877 | * structure, e.g. select a sublist based on first character. | |
878 | * | |
879 | * NOTE: input string (behind 'ptr' with 'len' bytes) DOES NOT have a | |
880 | * trailing NUL character. Any strings returned from this function | |
881 | * MUST have a trailing NUL character. | |
882 | */ | |
883 | ||
884 | n = (int) (sizeof(strdata_duk_builtin_strings) / sizeof(const char *)); | |
885 | for (i = 0; i < n; i++) { | |
886 | const char *str; | |
887 | ||
888 | str = strdata_duk_builtin_strings[i]; | |
889 | if (strlen(str) == len && memcmp(ptr, (const void *) str, len) == 0) { | |
890 | #if 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 /*until_nul*/); | |
894 | printf(" -> constant string index %ld\n", (long) i); | |
895 | #endif | |
11fdf7f2 | 896 | return (void *) ajduk__lose_const(strdata_duk_builtin_strings[i]); |
7c673cae FG |
897 | } |
898 | } | |
899 | ||
900 | #if 0 | |
901 | printf("ajsheap_extstr_check_2: ptr=%p, len=%ld ", | |
902 | (void *) ptr, (long) len); | |
903 | safe_print_chars((const char *) ptr, len, 0 /*until_nul*/); | |
904 | printf(" -> not found\n"); | |
905 | #endif | |
906 | return NULL; | |
907 | } | |
908 | ||
909 | void ajsheap_extstr_free_2(const void *ptr) { | |
910 | (void) ptr; | |
911 | #if 0 | |
912 | printf("ajsheap_extstr_free_2: freeing extstr %p -> ", ptr); | |
913 | safe_print_chars((const char *) ptr, DUK_SIZE_MAX, 1 /*until_nul*/); | |
914 | printf("\n"); | |
915 | #endif | |
916 | } | |
917 | ||
918 | /* | |
919 | * External strings strategy intended for valgrind testing: external strings | |
920 | * are allocated using malloc()/free() so that valgrind can be used to ensure | |
921 | * that strings are e.g. freed exactly once. | |
922 | */ | |
923 | ||
924 | const void *ajsheap_extstr_check_3(const void *ptr, duk_size_t len) { | |
925 | duk_uint8_t *ret; | |
926 | ||
927 | (void) safe_print_chars; /* potentially unused */ | |
928 | ||
929 | ret = malloc((size_t) len + 1); | |
930 | if (ret == NULL) { | |
931 | #if 0 | |
932 | printf("ajsheap_extstr_check_3: ptr=%p, len=%ld ", | |
933 | (void *) ptr, (long) len); | |
934 | safe_print_chars((const char *) ptr, len, 0 /*until_nul*/); | |
935 | printf(" -> malloc failed, return NULL\n"); | |
936 | #endif | |
937 | return (const void *) NULL; | |
938 | } | |
939 | ||
940 | if (len > 0) { | |
941 | memcpy((void *) ret, ptr, (size_t) len); | |
942 | } | |
943 | ret[len] = (duk_uint8_t) 0; | |
944 | ||
945 | #if 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 /*until_nul*/); | |
949 | printf(" -> %p\n", (void *) ret); | |
950 | #endif | |
951 | return (const void *) ret; | |
952 | } | |
953 | ||
954 | void ajsheap_extstr_free_3(const void *ptr) { | |
955 | (void) ptr; | |
956 | #if 0 | |
957 | printf("ajsheap_extstr_free_3: freeing extstr %p -> ", ptr); | |
958 | safe_print_chars((const char *) ptr, DUK_SIZE_MAX, 1 /*until_nul*/); | |
959 | printf("\n"); | |
960 | #endif | |
11fdf7f2 | 961 | free((void *) ajduk__lose_const(ptr)); |
7c673cae FG |
962 | } |
963 | ||
964 | /* | |
965 | * Execution timeout example | |
966 | */ | |
967 | ||
968 | #define AJSHEAP_EXEC_TIMEOUT 5 /* seconds */ | |
969 | ||
970 | static time_t curr_pcall_start = 0; | |
971 | static long exec_timeout_check_counter = 0; | |
972 | ||
973 | void ajsheap_start_exec_timeout(void) { | |
974 | curr_pcall_start = time(NULL); | |
975 | } | |
976 | ||
977 | void ajsheap_clear_exec_timeout(void) { | |
978 | curr_pcall_start = 0; | |
979 | } | |
980 | ||
981 | duk_bool_t ajsheap_exec_timeout_check(void *udata) { | |
982 | time_t now = time(NULL); | |
983 | time_t diff = now - curr_pcall_start; | |
984 | ||
985 | (void) udata; /* not needed */ | |
986 | ||
987 | exec_timeout_check_counter++; | |
988 | #if 0 | |
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); | |
991 | fflush(stdout); | |
992 | #endif | |
993 | ||
994 | if (curr_pcall_start == 0) { | |
995 | /* protected call not yet running */ | |
996 | return 0; | |
997 | } | |
998 | if (diff > AJSHEAP_EXEC_TIMEOUT) { | |
999 | return 1; | |
1000 | } | |
1001 | return 0; | |
1002 | } | |
1003 | ||
1004 | #else /* DUK_CMDLINE_AJSHEAP */ | |
1005 | ||
1006 | int ajs_dummy = 0; /* to avoid empty source file */ | |
1007 | ||
1008 | #endif /* DUK_CMDLINE_AJSHEAP */ |