Github User Fetcher 1.0.0
C Application with Server and GUI
Loading...
Searching...
No Matches
duktape-1.5.2/src-separate/duk_heap_alloc.c
Go to the documentation of this file.
1/*
2 * duk_heap allocation and freeing.
3 */
4
5#include "duk_internal.h"
6
7/* Constants for built-in string data depacking. */
8#define DUK__BITPACK_LETTER_LIMIT 26
9#define DUK__BITPACK_UNDERSCORE 26
10#define DUK__BITPACK_FF 27
11#define DUK__BITPACK_SWITCH1 29
12#define DUK__BITPACK_SWITCH 30
13#define DUK__BITPACK_SEVENBIT 31
14
15#if defined(DUK_USE_ROM_STRINGS)
16/* Fixed seed value used with ROM strings. */
17#define DUK__FIXED_HASH_SEED 0xabcd1234
18#endif
19
20/*
21 * Free a heap object.
22 *
23 * Free heap object and its internal (non-heap) pointers. Assumes that
24 * caller has removed the object from heap allocated list or the string
25 * intern table, and any weak references (which strings may have) have
26 * been already dealt with.
27 */
28
30 DUK_ASSERT(heap != NULL);
31 DUK_ASSERT(h != NULL);
32
33 DUK_FREE(heap, DUK_HOBJECT_GET_PROPS(heap, h));
34
37 DUK_UNREF(f);
38 /* Currently nothing to free; 'data' is a heap object */
39 } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
41 DUK_UNREF(f);
42 /* Currently nothing to free */
43 } else if (DUK_HOBJECT_IS_THREAD(h)) {
44 duk_hthread *t = (duk_hthread *) h;
45 DUK_FREE(heap, t->valstack);
46 DUK_FREE(heap, t->callstack);
47 DUK_FREE(heap, t->catchstack);
48 /* Don't free h->resumer because it exists in the heap.
49 * Callstack entries also contain function pointers which
50 * are not freed for the same reason.
51 */
52
53 /* XXX: with 'caller' property the callstack would need
54 * to be unwound to update the 'caller' properties of
55 * functions in the callstack.
56 */
57 }
58}
59
61 DUK_ASSERT(heap != NULL);
62 DUK_ASSERT(h != NULL);
63
66 DUK_DDD(DUK_DDDPRINT("free dynamic buffer %p", (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g)));
68 }
69}
70
72 DUK_ASSERT(heap != NULL);
73 DUK_ASSERT(h != NULL);
74
75 DUK_UNREF(heap);
76 DUK_UNREF(h);
77
78#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_FREE)
80 DUK_DDD(DUK_DDDPRINT("free extstr: hstring %!O, extdata: %p",
81 h, DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h)));
82 DUK_USE_EXTSTR_FREE(heap->heap_udata, (const void *) DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h));
83 }
84#endif
85}
86
88 DUK_ASSERT(heap);
89 DUK_ASSERT(hdr);
90
91 DUK_DDD(DUK_DDDPRINT("free heaphdr %p, htype %ld", (void *) hdr, (long) DUK_HEAPHDR_GET_TYPE(hdr)));
92
93 switch ((int) DUK_HEAPHDR_GET_TYPE(hdr)) {
96 break;
99 break;
100 case DUK_HTYPE_BUFFER:
101 duk_free_hbuffer_inner(heap, (duk_hbuffer *) hdr);
102 break;
103 default:
105 }
106
107 DUK_FREE(heap, hdr);
108}
109
110/*
111 * Free the heap.
112 *
113 * Frees heap-related non-heap-tracked allocations such as the
114 * string intern table; then frees the heap allocated objects;
115 * and finally frees the heap structure itself. Reference counts
116 * and GC markers are ignored (and not updated) in this process,
117 * and finalizers won't be called.
118 *
119 * The heap pointer and heap object pointers must not be used
120 * after this call.
121 */
122
124 duk_heaphdr *curr;
126
127 curr = heap->heap_allocated;
128 while (curr) {
129 /* We don't log or warn about freeing zero refcount objects
130 * because they may happen with finalizer processing.
131 */
132
133 DUK_DDD(DUK_DDDPRINT("FINALFREE (allocated): %!iO",
134 (duk_heaphdr *) curr));
135 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
136 duk_heap_free_heaphdr_raw(heap, curr);
137 curr = next;
138 }
139}
140
141#if defined(DUK_USE_REFERENCE_COUNTING)
143 duk_heaphdr *curr;
145
146 curr = heap->refzero_list;
147 while (curr) {
148 DUK_DDD(DUK_DDDPRINT("FINALFREE (refzero_list): %!iO",
149 (duk_heaphdr *) curr));
150 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
151 duk_heap_free_heaphdr_raw(heap, curr);
152 curr = next;
153 }
154}
155#endif
156
157#if defined(DUK_USE_MARK_AND_SWEEP)
159 duk_heaphdr *curr;
161
162 curr = heap->finalize_list;
163 while (curr) {
164 DUK_DDD(DUK_DDDPRINT("FINALFREE (finalize_list): %!iO",
165 (duk_heaphdr *) curr));
166 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
167 duk_heap_free_heaphdr_raw(heap, curr);
168 curr = next;
169 }
170}
171#endif
172
174 /* strings are only tracked by stringtable */
176}
177
179 duk_hthread *thr;
180 duk_heaphdr *curr;
181 duk_uint_t round_no;
182 duk_size_t count_all;
183 duk_size_t count_finalized;
184 duk_size_t curr_limit;
185
186 DUK_ASSERT(heap != NULL);
187 DUK_ASSERT(heap->heap_thread != NULL);
188
189#if defined(DUK_USE_REFERENCE_COUNTING)
190 DUK_ASSERT(heap->refzero_list == NULL); /* refzero not running -> must be empty */
191#endif
192#if defined(DUK_USE_MARK_AND_SWEEP)
193 DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep not running -> must be empty */
194#endif
195
196 /* XXX: here again finalizer thread is the heap_thread which needs
197 * to be coordinated with finalizer thread fixes.
198 */
199 thr = heap->heap_thread;
200 DUK_ASSERT(thr != NULL);
201
202 /* Prevent mark-and-sweep for the pending finalizers, also prevents
203 * refzero handling from moving objects away from the heap_allocated
204 * list. (The flag meaning is slightly abused here.)
205 */
208
209 curr_limit = 0; /* suppress warning, not used */
210 for (round_no = 0; ; round_no++) {
211 curr = heap->heap_allocated;
212 count_all = 0;
213 count_finalized = 0;
214 while (curr) {
215 count_all++;
217 /* Only objects in heap_allocated may have finalizers. Check that
218 * the object itself has a _Finalizer property (own or inherited)
219 * so that we don't execute finalizers for e.g. Proxy objects.
220 */
221 DUK_ASSERT(thr != NULL);
222 DUK_ASSERT(curr != NULL);
223
225 if (!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) curr)) {
226 DUK_ASSERT(DUK_HEAP_HAS_FINALIZER_NORESCUE(heap)); /* maps to finalizer 2nd argument */
228 count_finalized++;
229 }
230 }
231 }
232 curr = DUK_HEAPHDR_GET_NEXT(heap, curr);
233 }
234
235 /* Each round of finalizer execution may spawn new finalizable objects
236 * which is normal behavior for some applications. Allow multiple
237 * rounds of finalization, but use a shrinking limit based on the
238 * first round to detect the case where a runaway finalizer creates
239 * an unbounded amount of new finalizable objects. Finalizer rescue
240 * is not supported: the semantics are unclear because most of the
241 * objects being finalized here are already reachable. The finalizer
242 * is given a boolean to indicate that rescue is not possible.
243 *
244 * See discussion in: https://github.com/svaarala/duktape/pull/473
245 */
246
247 if (round_no == 0) {
248 /* Cannot wrap: each object is at least 8 bytes so count is
249 * at most 1/8 of that.
250 */
251 curr_limit = count_all * 2;
252 } else {
253 curr_limit = (curr_limit * 3) / 4; /* Decrease by 25% every round */
254 }
255 DUK_D(DUK_DPRINT("finalizer round %ld complete, %ld objects, tried to execute %ld finalizers, current limit is %ld",
256 (long) round_no, (long) count_all, (long) count_finalized, (long) curr_limit));
257
258 if (count_finalized == 0) {
259 DUK_D(DUK_DPRINT("no more finalizable objects, forced finalization finished"));
260 break;
261 }
262 if (count_finalized >= curr_limit) {
263 DUK_D(DUK_DPRINT("finalizer count above limit, potentially runaway finalizer; skip remaining finalizers"));
264 break;
265 }
266 }
267
270}
271
273 DUK_D(DUK_DPRINT("free heap: %p", (void *) heap));
274
275#if defined(DUK_USE_DEBUG)
276 duk_heap_dump_strtab(heap);
277#endif
278
279#if defined(DUK_USE_DEBUGGER_SUPPORT)
280 /* Detach a debugger if attached (can be called multiple times)
281 * safely.
282 */
283 /* XXX: Add a flag to reject an attempt to re-attach? Otherwise
284 * the detached callback may immediately reattach.
285 */
286 duk_debug_do_detach(heap);
287#endif
288
289 /* Execute finalizers before freeing the heap, even for reachable
290 * objects, and regardless of whether or not mark-and-sweep is
291 * enabled. This gives finalizers the chance to free any native
292 * resources like file handles, allocations made outside Duktape,
293 * etc. This is quite tricky to get right, so that all finalizer
294 * guarantees are honored.
295 *
296 * XXX: this perhaps requires an execution time limit.
297 */
298 DUK_D(DUK_DPRINT("execute finalizers before freeing heap"));
299#if defined(DUK_USE_MARK_AND_SWEEP)
300 /* Run mark-and-sweep a few times just in case (unreachable object
301 * finalizers run already here). The last round must rescue objects
302 * from the previous round without running any more finalizers. This
303 * ensures rescued objects get their FINALIZED flag cleared so that
304 * their finalizer is called once more in forced finalization to
305 * satisfy finalizer guarantees. However, we don't want to run any
306 * more finalizer because that'd required one more loop, and so on.
307 */
308 DUK_D(DUK_DPRINT("forced gc #1 in heap destruction"));
310 DUK_D(DUK_DPRINT("forced gc #2 in heap destruction"));
312 DUK_D(DUK_DPRINT("forced gc #3 in heap destruction (don't run finalizers)"));
313 duk_heap_mark_and_sweep(heap, DUK_MS_FLAG_SKIP_FINALIZERS); /* skip finalizers; queue finalizable objects to heap_allocated */
314#endif
315
316 DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* rescue no longer supported */
318
319 /* Note: heap->heap_thread, heap->curr_thread, and heap->heap_object
320 * are on the heap allocated list.
321 */
322
323 DUK_D(DUK_DPRINT("freeing heap objects of heap: %p", (void *) heap));
325
326#if defined(DUK_USE_REFERENCE_COUNTING)
327 DUK_D(DUK_DPRINT("freeing refzero list of heap: %p", (void *) heap));
329#endif
330
331#if defined(DUK_USE_MARK_AND_SWEEP)
332 DUK_D(DUK_DPRINT("freeing mark-and-sweep finalize list of heap: %p", (void *) heap));
334#endif
335
336 DUK_D(DUK_DPRINT("freeing string table of heap: %p", (void *) heap));
338
339 DUK_D(DUK_DPRINT("freeing heap structure: %p", (void *) heap));
340 heap->free_func(heap->heap_udata, heap);
341}
342
343/*
344 * Allocate a heap.
345 *
346 * String table is initialized with built-in strings from genbuiltins.py,
347 * either by dynamically creating the strings or by referring to ROM strings.
348 */
349
350#if defined(DUK_USE_ROM_STRINGS)
352#if defined(DUK_USE_ASSERTIONS)
354#endif
355
356 /* With ROM-based strings, heap->strs[] and thr->strs[] are omitted
357 * so nothing to initialize for strs[].
358 */
359
360#if defined(DUK_USE_ASSERTIONS)
361 for (i = 0; i < sizeof(duk_rom_strings) / sizeof(const duk_hstring *); i++) {
362 duk_uint32_t hash;
363 const duk_hstring *h;
364 h = duk_rom_strings[i];
365 DUK_ASSERT(h != NULL);
366 hash = duk_heap_hashstring(heap, (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
367 DUK_DD(DUK_DDPRINT("duk_rom_strings[%d] -> hash 0x%08lx, computed 0x%08lx",
368 (int) i, (unsigned long) DUK_HSTRING_GET_HASH(h), (unsigned long) hash));
369 DUK_ASSERT(hash == (duk_uint32_t) DUK_HSTRING_GET_HASH(h));
370 }
371#endif
372 return 1;
373}
374#else /* DUK_USE_ROM_STRINGS */
376 duk_bitdecoder_ctx bd_ctx;
377 duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */
378 duk_small_uint_t i, j;
379
380 DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
381 bd->data = (const duk_uint8_t *) duk_strings_data;
383
384 for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
385 duk_uint8_t tmp[DUK_STRDATA_MAX_STRLEN];
386 duk_hstring *h;
388 duk_small_uint_t mode;
390
391 len = duk_bd_decode(bd, 5);
392 mode = 32; /* 0 = uppercase, 32 = lowercase (= 'a' - 'A') */
393 for (j = 0; j < len; j++) {
394 t = duk_bd_decode(bd, 5);
396 t = t + DUK_ASC_UC_A + mode;
397 } else if (t == DUK__BITPACK_UNDERSCORE) {
399 } else if (t == DUK__BITPACK_FF) {
400 /* Internal keys are prefixed with 0xFF in the stringtable
401 * (which makes them invalid UTF-8 on purpose).
402 */
403 t = 0xff;
404 } else if (t == DUK__BITPACK_SWITCH1) {
405 t = duk_bd_decode(bd, 5);
406 DUK_ASSERT_DISABLE(t >= 0); /* unsigned */
407 DUK_ASSERT(t <= 25);
408 t = t + DUK_ASC_UC_A + (mode ^ 32);
409 } else if (t == DUK__BITPACK_SWITCH) {
410 mode = mode ^ 32;
411 t = duk_bd_decode(bd, 5);
412 DUK_ASSERT_DISABLE(t >= 0);
413 DUK_ASSERT(t <= 25);
414 t = t + DUK_ASC_UC_A + mode;
415 } else if (t == DUK__BITPACK_SEVENBIT) {
416 t = duk_bd_decode(bd, 7);
417 }
418 tmp[j] = (duk_uint8_t) t;
419 }
420
421 /* No need to length check string: it will never exceed even
422 * the 16-bit length maximum.
423 */
424 DUK_ASSERT(len <= 0xffffUL);
425 DUK_DDD(DUK_DDDPRINT("intern built-in string %ld", (long) i));
426 h = duk_heap_string_intern(heap, tmp, len);
427 if (!h) {
428 goto error;
429 }
431
432 /* Special flags checks. Since these strings are always
433 * reachable and a string cannot appear twice in the string
434 * table, there's no need to check/set these flags elsewhere.
435 * The 'internal' flag is set by string intern code.
436 */
437 if (i == DUK_STRIDX_EVAL || i == DUK_STRIDX_LC_ARGUMENTS) {
439 }
444 }
445 }
446
447 DUK_DDD(DUK_DDDPRINT("interned: %!O", (duk_heaphdr *) h));
448
449 /* XXX: The incref macro takes a thread pointer but doesn't
450 * use it right now.
451 */
452 DUK_HSTRING_INCREF(_never_referenced_, h);
453
454#if defined(DUK_USE_HEAPPTR16)
455 heap->strs16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
456#else
457 heap->strs[i] = h;
458#endif
459 }
460
461 return 1;
462
463 error:
464 return 0;
465}
466#endif /* DUK_USE_ROM_STRINGS */
467
469 duk_hthread *thr;
470
471 DUK_DD(DUK_DDPRINT("heap init: alloc heap thread"));
472 thr = duk_hthread_alloc(heap,
476 if (!thr) {
477 DUK_D(DUK_DPRINT("failed to alloc heap_thread"));
478 return 0;
479 }
481#if defined(DUK_USE_ROM_STRINGS)
482 /* No strs[] pointer. */
483#else /* DUK_USE_ROM_STRINGS */
484#if defined(DUK_USE_HEAPPTR16)
485 thr->strs16 = heap->strs16;
486#else
487 thr->strs = heap->strs;
488#endif
489#endif /* DUK_USE_ROM_STRINGS */
490
491 heap->heap_thread = thr;
492 DUK_HTHREAD_INCREF(thr, thr); /* Note: first argument not really used */
493
494 /* 'thr' is now reachable */
495
496 if (!duk_hthread_init_stacks(heap, thr)) {
497 return 0;
498 }
499
500 /* XXX: this may now fail, and is not handled correctly */
502
503 /* default prototype (Note: 'thr' must be reachable) */
505
506 return 1;
507}
508
509#if defined(DUK_USE_DEBUG)
510#define DUK__DUMPSZ(t) do { \
511 DUK_D(DUK_DPRINT("" #t "=%ld", (long) sizeof(t))); \
512 } while (0)
513
514/* These is not 100% because format would need to be non-portable "long long".
515 * Also print out as doubles to catch cases where the "long" type is not wide
516 * enough; the limits will then not be printed accurately but the magnitude
517 * will be correct.
518 */
519#define DUK__DUMPLM_SIGNED_RAW(t,a,b) do { \
520 DUK_D(DUK_DPRINT(t "=[%ld,%ld]=[%lf,%lf]", \
521 (long) (a), (long) (b), \
522 (double) (a), (double) (b))); \
523 } while (0)
524#define DUK__DUMPLM_UNSIGNED_RAW(t,a,b) do { \
525 DUK_D(DUK_DPRINT(t "=[%lu,%lu]=[%lf,%lf]", \
526 (unsigned long) (a), (unsigned long) (b), \
527 (double) (a), (double) (b))); \
528 } while (0)
529#define DUK__DUMPLM_SIGNED(t) do { \
530 DUK__DUMPLM_SIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \
531 } while (0)
532#define DUK__DUMPLM_UNSIGNED(t) do { \
533 DUK__DUMPLM_UNSIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \
534 } while (0)
535
536DUK_LOCAL void duk__dump_type_sizes(void) {
537 DUK_D(DUK_DPRINT("sizeof()"));
538
539 /* basic platform types */
540 DUK__DUMPSZ(char);
541 DUK__DUMPSZ(short);
542 DUK__DUMPSZ(int);
543 DUK__DUMPSZ(long);
544 DUK__DUMPSZ(double);
545 DUK__DUMPSZ(void *);
546 DUK__DUMPSZ(size_t);
547
548 /* basic types from duk_features.h */
549 DUK__DUMPSZ(duk_uint8_t);
550 DUK__DUMPSZ(duk_int8_t);
551 DUK__DUMPSZ(duk_uint16_t);
552 DUK__DUMPSZ(duk_int16_t);
553 DUK__DUMPSZ(duk_uint32_t);
554 DUK__DUMPSZ(duk_int32_t);
555 DUK__DUMPSZ(duk_uint64_t);
556 DUK__DUMPSZ(duk_int64_t);
557 DUK__DUMPSZ(duk_uint_least8_t);
558 DUK__DUMPSZ(duk_int_least8_t);
559 DUK__DUMPSZ(duk_uint_least16_t);
560 DUK__DUMPSZ(duk_int_least16_t);
561 DUK__DUMPSZ(duk_uint_least32_t);
562 DUK__DUMPSZ(duk_int_least32_t);
563#if defined(DUK_USE_64BIT_OPS)
564 DUK__DUMPSZ(duk_uint_least64_t);
565 DUK__DUMPSZ(duk_int_least64_t);
566#endif
567 DUK__DUMPSZ(duk_uint_fast8_t);
568 DUK__DUMPSZ(duk_int_fast8_t);
569 DUK__DUMPSZ(duk_uint_fast16_t);
570 DUK__DUMPSZ(duk_int_fast16_t);
571 DUK__DUMPSZ(duk_uint_fast32_t);
572 DUK__DUMPSZ(duk_int_fast32_t);
573#if defined(DUK_USE_64BIT_OPS)
574 DUK__DUMPSZ(duk_uint_fast64_t);
575 DUK__DUMPSZ(duk_int_fast64_t);
576#endif
577 DUK__DUMPSZ(duk_uintptr_t);
578 DUK__DUMPSZ(duk_intptr_t);
579 DUK__DUMPSZ(duk_uintmax_t);
580 DUK__DUMPSZ(duk_intmax_t);
581 DUK__DUMPSZ(duk_double_t);
582
583 /* important chosen base types */
584 DUK__DUMPSZ(duk_int_t);
585 DUK__DUMPSZ(duk_uint_t);
586 DUK__DUMPSZ(duk_int_fast_t);
587 DUK__DUMPSZ(duk_uint_fast_t);
588 DUK__DUMPSZ(duk_small_int_t);
589 DUK__DUMPSZ(duk_small_uint_t);
590 DUK__DUMPSZ(duk_small_int_fast_t);
591 DUK__DUMPSZ(duk_small_uint_fast_t);
592
593 /* some derived types */
594 DUK__DUMPSZ(duk_codepoint_t);
595 DUK__DUMPSZ(duk_ucodepoint_t);
596 DUK__DUMPSZ(duk_idx_t);
597 DUK__DUMPSZ(duk_errcode_t);
598 DUK__DUMPSZ(duk_uarridx_t);
599
600 /* tval */
601 DUK__DUMPSZ(duk_double_union);
602 DUK__DUMPSZ(duk_tval);
603
604 /* structs from duk_forwdecl.h */
605 DUK__DUMPSZ(duk_jmpbuf); /* just one 'int' for C++ exceptions */
606 DUK__DUMPSZ(duk_heaphdr);
607 DUK__DUMPSZ(duk_heaphdr_string);
608 DUK__DUMPSZ(duk_hstring);
609 DUK__DUMPSZ(duk_hstring_external);
610 DUK__DUMPSZ(duk_hobject);
611 DUK__DUMPSZ(duk_hcompiledfunction);
612 DUK__DUMPSZ(duk_hnativefunction);
613 DUK__DUMPSZ(duk_hthread);
614 DUK__DUMPSZ(duk_hbuffer);
615 DUK__DUMPSZ(duk_hbuffer_fixed);
616 DUK__DUMPSZ(duk_hbuffer_dynamic);
617 DUK__DUMPSZ(duk_hbuffer_external);
618 DUK__DUMPSZ(duk_propaccessor);
619 DUK__DUMPSZ(duk_propvalue);
620 DUK__DUMPSZ(duk_propdesc);
621 DUK__DUMPSZ(duk_heap);
622#if defined(DUK_USE_STRTAB_CHAIN)
623 DUK__DUMPSZ(duk_strtab_entry);
624#endif
625 DUK__DUMPSZ(duk_activation);
626 DUK__DUMPSZ(duk_catcher);
627 DUK__DUMPSZ(duk_strcache);
628 DUK__DUMPSZ(duk_ljstate);
629 DUK__DUMPSZ(duk_fixedbuffer);
630 DUK__DUMPSZ(duk_bitdecoder_ctx);
631 DUK__DUMPSZ(duk_bitencoder_ctx);
632 DUK__DUMPSZ(duk_token);
633 DUK__DUMPSZ(duk_re_token);
634 DUK__DUMPSZ(duk_lexer_point);
635 DUK__DUMPSZ(duk_lexer_ctx);
636 DUK__DUMPSZ(duk_compiler_instr);
637 DUK__DUMPSZ(duk_compiler_func);
638 DUK__DUMPSZ(duk_compiler_ctx);
639 DUK__DUMPSZ(duk_re_matcher_ctx);
640 DUK__DUMPSZ(duk_re_compiler_ctx);
641}
642DUK_LOCAL void duk__dump_type_limits(void) {
643 DUK_D(DUK_DPRINT("limits"));
644
645 /* basic types */
646 DUK__DUMPLM_SIGNED(INT8);
647 DUK__DUMPLM_UNSIGNED(UINT8);
648 DUK__DUMPLM_SIGNED(INT_FAST8);
649 DUK__DUMPLM_UNSIGNED(UINT_FAST8);
650 DUK__DUMPLM_SIGNED(INT_LEAST8);
651 DUK__DUMPLM_UNSIGNED(UINT_LEAST8);
652 DUK__DUMPLM_SIGNED(INT16);
653 DUK__DUMPLM_UNSIGNED(UINT16);
654 DUK__DUMPLM_SIGNED(INT_FAST16);
655 DUK__DUMPLM_UNSIGNED(UINT_FAST16);
656 DUK__DUMPLM_SIGNED(INT_LEAST16);
657 DUK__DUMPLM_UNSIGNED(UINT_LEAST16);
658 DUK__DUMPLM_SIGNED(INT32);
659 DUK__DUMPLM_UNSIGNED(UINT32);
660 DUK__DUMPLM_SIGNED(INT_FAST32);
661 DUK__DUMPLM_UNSIGNED(UINT_FAST32);
662 DUK__DUMPLM_SIGNED(INT_LEAST32);
663 DUK__DUMPLM_UNSIGNED(UINT_LEAST32);
664#if defined(DUK_USE_64BIT_OPS)
665 DUK__DUMPLM_SIGNED(INT64);
666 DUK__DUMPLM_UNSIGNED(UINT64);
667 DUK__DUMPLM_SIGNED(INT_FAST64);
668 DUK__DUMPLM_UNSIGNED(UINT_FAST64);
669 DUK__DUMPLM_SIGNED(INT_LEAST64);
670 DUK__DUMPLM_UNSIGNED(UINT_LEAST64);
671#endif
672 DUK__DUMPLM_SIGNED(INTPTR);
673 DUK__DUMPLM_UNSIGNED(UINTPTR);
674 DUK__DUMPLM_SIGNED(INTMAX);
675 DUK__DUMPLM_UNSIGNED(UINTMAX);
676
677 /* derived types */
678 DUK__DUMPLM_SIGNED(INT);
679 DUK__DUMPLM_UNSIGNED(UINT);
680 DUK__DUMPLM_SIGNED(INT_FAST);
681 DUK__DUMPLM_UNSIGNED(UINT_FAST);
682 DUK__DUMPLM_SIGNED(SMALL_INT);
683 DUK__DUMPLM_UNSIGNED(SMALL_UINT);
684 DUK__DUMPLM_SIGNED(SMALL_INT_FAST);
685 DUK__DUMPLM_UNSIGNED(SMALL_UINT_FAST);
686}
687#undef DUK__DUMPSZ
688#undef DUK__DUMPLM_SIGNED_RAW
689#undef DUK__DUMPLM_UNSIGNED_RAW
690#undef DUK__DUMPLM_SIGNED
691#undef DUK__DUMPLM_UNSIGNED
692
693DUK_LOCAL void duk__dump_misc_options(void) {
694 DUK_D(DUK_DPRINT("DUK_VERSION: %ld", (long) DUK_VERSION));
695 DUK_D(DUK_DPRINT("DUK_GIT_DESCRIBE: %s", DUK_GIT_DESCRIBE));
696 DUK_D(DUK_DPRINT("OS string: %s", DUK_USE_OS_STRING));
697 DUK_D(DUK_DPRINT("architecture string: %s", DUK_USE_ARCH_STRING));
698 DUK_D(DUK_DPRINT("compiler string: %s", DUK_USE_COMPILER_STRING));
699#if defined(DUK_USE_PACKED_TVAL)
700 DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: yes"));
701#else
702 DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: no"));
703#endif
704#if defined(DUK_USE_VARIADIC_MACROS)
705 DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: yes"));
706#else
707 DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: no"));
708#endif
709#if defined(DUK_USE_INTEGER_LE)
710 DUK_D(DUK_DPRINT("integer endianness: little"));
711#elif defined(DUK_USE_INTEGER_ME)
712 DUK_D(DUK_DPRINT("integer endianness: mixed"));
713#elif defined(DUK_USE_INTEGER_BE)
714 DUK_D(DUK_DPRINT("integer endianness: big"));
715#else
716 DUK_D(DUK_DPRINT("integer endianness: ???"));
717#endif
718#if defined(DUK_USE_DOUBLE_LE)
719 DUK_D(DUK_DPRINT("IEEE double endianness: little"));
720#elif defined(DUK_USE_DOUBLE_ME)
721 DUK_D(DUK_DPRINT("IEEE double endianness: mixed"));
722#elif defined(DUK_USE_DOUBLE_BE)
723 DUK_D(DUK_DPRINT("IEEE double endianness: big"));
724#else
725 DUK_D(DUK_DPRINT("IEEE double endianness: ???"));
726#endif
727}
728#endif /* DUK_USE_DEBUG */
729
732 duk_realloc_function realloc_func,
733 duk_free_function free_func,
734 void *heap_udata,
735 duk_fatal_function fatal_func) {
736 duk_heap *res = NULL;
737
738 /* Silence a few global unused warnings here. */
740
741 DUK_D(DUK_DPRINT("allocate heap"));
742
743 /*
744 * Debug dump type sizes
745 */
746
747#if defined(DUK_USE_DEBUG)
748 duk__dump_misc_options();
749 duk__dump_type_sizes();
750 duk__dump_type_limits();
751#endif
752
753 /*
754 * If selftests enabled, run them as early as possible
755 */
756#if defined(DUK_USE_SELF_TESTS)
757 DUK_D(DUK_DPRINT("running self tests"));
758 duk_selftest_run_tests();
759 DUK_D(DUK_DPRINT("self tests passed"));
760#endif
761
762 /*
763 * Computed values (e.g. INFINITY)
764 */
765
766#if defined(DUK_USE_COMPUTED_NAN)
767 do {
768 /* Workaround for some exotic platforms where NAN is missing
769 * and the expression (0.0 / 0.0) does NOT result in a NaN.
770 * Such platforms use the global 'duk_computed_nan' which must
771 * be initialized at runtime. Use 'volatile' to ensure that
772 * the compiler will actually do the computation and not try
773 * to do constant folding which might result in the original
774 * problem.
775 */
776 volatile double dbl1 = 0.0;
777 volatile double dbl2 = 0.0;
778 duk_computed_nan = dbl1 / dbl2;
779 } while (0);
780#endif
781
782#if defined(DUK_USE_COMPUTED_INFINITY)
783 do {
784 /* Similar workaround for INFINITY. */
785 volatile double dbl1 = 1.0;
786 volatile double dbl2 = 0.0;
787 duk_computed_infinity = dbl1 / dbl2;
788 } while (0);
789#endif
790
791 /*
792 * Allocate heap struct
793 *
794 * Use a raw call, all macros expect the heap to be initialized
795 */
796
797 res = (duk_heap *) alloc_func(heap_udata, sizeof(duk_heap));
798 if (!res) {
799 goto error;
800 }
801
802 /*
803 * Zero the struct, and start initializing roughly in order
804 */
805
806 DUK_MEMZERO(res, sizeof(*res));
807
808 /* explicit NULL inits */
809#if defined(DUK_USE_EXPLICIT_NULL_INIT)
810 res->heap_udata = NULL;
811 res->heap_allocated = NULL;
812#if defined(DUK_USE_REFERENCE_COUNTING)
813 res->refzero_list = NULL;
814 res->refzero_list_tail = NULL;
815#endif
816#if defined(DUK_USE_MARK_AND_SWEEP)
817 res->finalize_list = NULL;
818#endif
819 res->heap_thread = NULL;
820 res->curr_thread = NULL;
821 res->heap_object = NULL;
822#if defined(DUK_USE_STRTAB_CHAIN)
823 /* nothing to NULL */
824#elif defined(DUK_USE_STRTAB_PROBE)
825#if defined(DUK_USE_HEAPPTR16)
826 res->strtable16 = (duk_uint16_t *) NULL;
827#else
828 res->strtable = (duk_hstring **) NULL;
829#endif
830#endif
831#if defined(DUK_USE_ROM_STRINGS)
832 /* no res->strs[] */
833#else /* DUK_USE_ROM_STRINGS */
834#if defined(DUK_USE_HEAPPTR16)
835 /* res->strs16[] is zeroed and zero decodes to NULL, so no NULL inits. */
836#else
837 {
839 for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
840 res->strs[i] = NULL;
841 }
842 }
843#endif
844#endif /* DUK_USE_ROM_STRINGS */
845#if defined(DUK_USE_DEBUGGER_SUPPORT)
846 res->dbg_read_cb = NULL;
847 res->dbg_write_cb = NULL;
848 res->dbg_peek_cb = NULL;
849 res->dbg_read_flush_cb = NULL;
850 res->dbg_write_flush_cb = NULL;
851 res->dbg_request_cb = NULL;
852 res->dbg_udata = NULL;
853 res->dbg_step_thread = NULL;
854#endif
855#endif /* DUK_USE_EXPLICIT_NULL_INIT */
856
857 res->alloc_func = alloc_func;
858 res->realloc_func = realloc_func;
859 res->free_func = free_func;
860 res->heap_udata = heap_udata;
861 res->fatal_func = fatal_func;
862
863#if defined(DUK_USE_HEAPPTR16)
864 /* XXX: zero assumption */
865 res->heapptr_null16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) NULL);
866 res->heapptr_deleted16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) DUK_STRTAB_DELETED_MARKER(res));
867#endif
868
869 /* res->mark_and_sweep_trigger_counter == 0 -> now causes immediate GC; which is OK */
870
871 res->call_recursion_depth = 0;
873
874 /* XXX: use the pointer as a seed for now: mix in time at least */
875
876 /* The casts through duk_intr_pt is to avoid the following GCC warning:
877 *
878 * warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
879 *
880 * This still generates a /Wp64 warning on VS2010 when compiling for x86.
881 */
882#if defined(DUK_USE_ROM_STRINGS)
883 /* XXX: make a common DUK_USE_ option, and allow custom fixed seed? */
884 DUK_D(DUK_DPRINT("using rom strings, force heap hash_seed to fixed value 0x%08lx", (long) DUK__FIXED_HASH_SEED));
885 res->hash_seed = (duk_uint32_t) DUK__FIXED_HASH_SEED;
886#else /* DUK_USE_ROM_STRINGS */
887 res->hash_seed = (duk_uint32_t) (duk_intptr_t) res;
888 res->rnd_state = (duk_uint32_t) (duk_intptr_t) res;
889#if !defined(DUK_USE_STRHASH_DENSE)
890 res->hash_seed ^= 5381; /* Bernstein hash init value is normally 5381; XOR it in in case pointer low bits are 0 */
891#endif
892#endif /* DUK_USE_ROM_STRINGS */
893
894#if defined(DUK_USE_EXPLICIT_NULL_INIT)
895 res->lj.jmpbuf_ptr = NULL;
896#endif
897 DUK_ASSERT(res->lj.type == DUK_LJ_TYPE_UNKNOWN); /* zero */
898
901
902#if (DUK_STRTAB_INITIAL_SIZE < DUK_UTIL_MIN_HASH_PRIME)
903#error initial heap stringtable size is defined incorrectly
904#endif
905
906 /*
907 * Init stringtable: fixed variant
908 */
909
910#if defined(DUK_USE_STRTAB_CHAIN)
912#if defined(DUK_USE_EXPLICIT_NULL_INIT)
913 {
915 for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
916#if defined(DUK_USE_HEAPPTR16)
917 res->strtable[i].u.str16 = res->heapptr_null16;
918#else
919 res->strtable[i].u.str = NULL;
920#endif
921 }
922 }
923#endif /* DUK_USE_EXPLICIT_NULL_INIT */
924#endif /* DUK_USE_STRTAB_CHAIN */
925
926 /*
927 * Init stringtable: probe variant
928 */
929
930#if defined(DUK_USE_STRTAB_PROBE)
931#if defined(DUK_USE_HEAPPTR16)
932 res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE);
933 if (!res->strtable16) {
934 goto error;
935 }
936#else /* DUK_USE_HEAPPTR16 */
937 res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE);
938 if (!res->strtable) {
939 goto error;
940 }
941#endif /* DUK_USE_HEAPPTR16 */
943#if defined(DUK_USE_EXPLICIT_NULL_INIT)
944 {
947 for (i = 0; i < DUK_STRTAB_INITIAL_SIZE; i++) {
948#if defined(DUK_USE_HEAPPTR16)
949 res->strtable16[i] = res->heapptr_null16;
950#else
951 res->strtable[i] = NULL;
952#endif
953 }
954 }
955#else /* DUK_USE_EXPLICIT_NULL_INIT */
956#if defined(DUK_USE_HEAPPTR16)
957 DUK_MEMZERO(res->strtable16, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE);
958#else
960#endif
961#endif /* DUK_USE_EXPLICIT_NULL_INIT */
962#endif /* DUK_USE_STRTAB_PROBE */
963
964 /*
965 * Init stringcache
966 */
967
968#if defined(DUK_USE_EXPLICIT_NULL_INIT)
969 {
971 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
972 res->strcache[i].h = NULL;
973 }
974 }
975#endif
976
977 /* XXX: error handling is incomplete. It would be cleanest if
978 * there was a setjmp catchpoint, so that all init code could
979 * freely throw errors. If that were the case, the return code
980 * passing here could be removed.
981 */
982
983 /*
984 * Init built-in strings
985 */
986
987 DUK_DD(DUK_DDPRINT("HEAP: INIT STRINGS"));
988 if (!duk__init_heap_strings(res)) {
989 goto error;
990 }
991
992 /*
993 * Init the heap thread
994 */
995
996 DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP THREAD"));
997 if (!duk__init_heap_thread(res)) {
998 goto error;
999 }
1000
1001 /*
1002 * Init the heap object
1003 */
1004
1005 DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP OBJECT"));
1006 DUK_ASSERT(res->heap_thread != NULL);
1009 if (!res->heap_object) {
1010 goto error;
1011 }
1013
1014 /*
1015 * All done
1016 */
1017
1018 DUK_D(DUK_DPRINT("allocated heap: %p", (void *) res));
1019 return res;
1020
1021 error:
1022 DUK_D(DUK_DPRINT("heap allocation failed"));
1023
1024 if (res) {
1025 /* assumes that allocated pointers and alloc funcs are valid
1026 * if res exists
1027 */
1028 DUK_ASSERT(res->alloc_func != NULL);
1029 DUK_ASSERT(res->realloc_func != NULL);
1030 DUK_ASSERT(res->free_func != NULL);
1031 duk_heap_free(res);
1032 }
1033 return NULL;
1034}
1035
1036#undef DUK__BITPACK_LETTER_LIMIT
1037#undef DUK__BITPACK_UNDERSCORE
1038#undef DUK__BITPACK_FF
1039#undef DUK__BITPACK_SWITCH1
1040#undef DUK__BITPACK_SWITCH
1041#undef DUK__BITPACK_SEVENBIT
1042#undef DUK__FIXED_HASH_SEED
duk_uint16_t duk_uint_least16_t
duk_int32_t duk_int_fast32_t
unsigned int duk_small_uint_t
duk_uint32_t duk_uint_least32_t
duk_uint_fast32_t duk_uint_fast_t
duk_int_fast32_t duk_int_fast_t
duk_uint_fast16_t duk_small_uint_fast_t
#define DUK_USE_NATIVE_CALL_RECLIMIT
duk_uint8_t duk_uint_fast8_t
duk_int_fast32_t duk_int_t
duk_int_fast16_t duk_small_int_fast_t
duk_int32_t duk_int_least32_t
duk_int16_t duk_int_fast16_t
duk_uint8_t duk_uint_least8_t
duk_uint_fast32_t duk_uint_t
duk_int16_t duk_int_least16_t
duk_uint32_t duk_uintmax_t
#define DUK_MEMZERO(p, n)
duk_small_int_t duk_bool_t
duk_uint32_t duk_uint_fast32_t
duk_uint16_t duk_uint_fast16_t
#define DUK_HEAP_HAS_FINALIZER_NORESCUE(heap)
DUK_INTERNAL const char * duk_str_unsupported
#define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, x)
#define DUK_STRTAB_DELETED_MARKER(heap)
#define DUK_HSTRING_GET_DATA(x)
#define DUK_HEAPHDR_GET_TYPE(h)
#define DUK_HEAP_SET_FINALIZER_NORESCUE(heap)
#define DUK_STRIDX_LC_ARGUMENTS
#define DUK_STRDATA_MAX_STRLEN
#define DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap)
#define DUK_HOBJECT_GET_PROPS(heap, h)
#define DUK_HOBJECT_CLASS_OBJECT
DUK_INTERNAL const duk_uint8_t duk_strings_data[1049]
#define DUK_STRIDX_START_RESERVED
#define DUK_HOBJECT_IS_COMPILEDFUNCTION(h)
#define DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap)
#define DUK_STRDATA_DATA_LENGTH
DUK_INTERNAL_DECL void duk_hthread_create_builtin_objects(duk_hthread *thr)
#define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, p)
#define DUK_HSTRING_GET_HASH(x)
#define DUK_FREE(heap, ptr)
#define DUK_ASSERT_DISABLE(x)
DUK_INTERNAL_DECL duk_hthread * duk_hthread_alloc(duk_heap *heap, duk_uint_t hobject_flags)
#define DUK_HOBJECT_CLASS_AS_FLAGS(v)
DUK_INTERNAL_DECL duk_hstring * duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen)
#define DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(x)
#define DUK_HSTRING_HAS_EXTDATA(x)
#define DUK_HTHREAD_STATE_INACTIVE
#define DUK_HOBJECT_IS_THREAD(h)
#define DUK_HSTRING_INCREF(thr, h)
#define DUK_HOBJECT_IS_NATIVEFUNCTION(h)
#define DUK_HTHREAD_INCREF(thr, h)
DUK_INTERNAL_DECL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags)
#define DUK_HEAPHDR_HAS_READONLY(h)
#define DUK_HSTRING_GET_BYTELEN(x)
DUK_INTERNAL_DECL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr)
#define DUK_STRTAB_CHAIN_SIZE
DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key)
#define DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)
#define DUK_STRTAB_INITIAL_SIZE
#define DUK_HOBJECT_CLASS_THREAD
#define DUK_STRIDX_START_STRICT_RESERVED
#define DUK_HSTRING_SET_STRICT_RESERVED_WORD(x)
#define DUK_HOBJECT_FLAG_THREAD
#define DUK_HEAPHDR_HAS_FINALIZED(h)
#define DUK_HSTRING_SET_RESERVED_WORD(x)
#define DUK_BIDX_THREAD_PROTOTYPE
#define DUK_HEAP_STRCACHE_SIZE
#define DUK_HOBJECT_FLAG_EXTENSIBLE
DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len)
#define DUK_HOBJECT_INCREF(thr, h)
#define DUK_STRIDX_END_RESERVED
DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap)
#define DUK_TVAL_SET_UNDEFINED(tv)
#define DUK_HTHREAD_STRING_INT_FINALIZER(thr)
#define DUK_HEAPHDR_GET_NEXT(heap, h)
#define DUK_HBUFFER_HAS_EXTERNAL(x)
#define DUK_HBUFFER_HAS_DYNAMIC(x)
DUK_INTERNAL_DECL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj)
DUK_INTERNAL_DECL duk_int32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits)
#define DUK_MS_FLAG_SKIP_FINALIZERS
DUK_INTERNAL_DECL duk_hobject * duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags)
void *(* duk_alloc_function)(void *udata, duk_size_t size)
void(* duk_fatal_function)(duk_context *ctx, duk_errcode_t code, const char *msg)
void(* duk_free_function)(void *udata, void *ptr)
void *(* duk_realloc_function)(void *udata, void *ptr, duk_size_t size)
DUK_INTERNAL void duk_heap_free(duk_heap *heap)
DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap)
DUK_INTERNAL void duk_free_hobject_inner(duk_heap *heap, duk_hobject *h)
DUK_LOCAL void duk__free_stringtable(duk_heap *heap)
DUK_INTERNAL void duk_free_hstring_inner(duk_heap *heap, duk_hstring *h)
DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap)
DUK_LOCAL void duk__free_markandsweep_finalize_list(duk_heap *heap)
DUK_LOCAL void duk__free_refzero_list(duk_heap *heap)
DUK_LOCAL void duk__free_allocated(duk_heap *heap)
DUK_INTERNAL void duk_free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h)
DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap)
DUK_INTERNAL duk_heap * duk_heap_alloc(duk_alloc_function alloc_func, duk_realloc_function realloc_func, duk_free_function free_func, void *heap_udata, duk_fatal_function fatal_func)
DUK_INTERNAL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr)
#define NULL
Definition gmacros.h:924
#define next(ls)
static void error(LoadState *S, const char *why)
duk_strcache strcache[DUK_HEAP_STRCACHE_SIZE]
duk_fatal_function fatal_func
duk_realloc_function realloc_func
duk_hstring * strs[DUK_HEAP_NUM_STRINGS]
duk_alloc_function alloc_func
duk_hobject * builtins[DUK_NUM_BUILTINS]