]> git.proxmox.com Git - ceph.git/blob - ceph/src/civetweb/src/third_party/duktape-1.8.0/examples/cmdline/duk_cmdline_ajduk.c
buildsys: switch source download to quincy
[ceph.git] / ceph / src / civetweb / src / third_party / duktape-1.8.0 / examples / cmdline / duk_cmdline_ajduk.c
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"
13 #include "duktape.h"
14
15 extern uint8_t dbgHEAPDUMP;
16
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
33 /*
34 * Helpers
35 */
36
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
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 },
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 }, /* duk_hthread, with heap ptr compression, ROM strings+objects */
102 { 512, 16, AJS_POOL_BORROW, 0 },
103 { 964, 1, AJS_POOL_BORROW, 0 }, /* duk_heap, with heap ptr compression, ROM strings+objects */
104 { 1024, 6, AJS_POOL_BORROW, 0 },
105 { 1344, 1, AJS_POOL_BORROW, 0 }, /* duk_heap, with heap ptr compression, RAM strings+objects */
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;
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 }
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
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
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) {
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);
357 fflush(stderr);
358 abort();
359 }
360 #endif
361 return (duk_uint16_t) ret;
362 }
363
364 void *ajsheap_dec16(void *ud, duk_uint16_t x) {
365 void *ret;
366 char *base = (char *) ajsheap_ram - 4;
367
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
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
896 return (void *) ajduk__lose_const(strdata_duk_builtin_strings[i]);
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
961 free((void *) ajduk__lose_const(ptr));
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 */