2 * duk_heap allocation and freeing.
5 #include "duk_internal.h"
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
18 * Free heap object and its internal (non-heap) pointers. Assumes that
19 * caller has removed the object from heap allocated list or the string
20 * intern table, and any weak references (which strings may have) have
21 * been already dealt with.
24 DUK_INTERNAL
void duk_free_hobject_inner(duk_heap
*heap
, duk_hobject
*h
) {
25 DUK_ASSERT(heap
!= NULL
);
26 DUK_ASSERT(h
!= NULL
);
28 DUK_FREE(heap
, DUK_HOBJECT_GET_PROPS(heap
, h
));
30 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h
)) {
31 duk_hcompiledfunction
*f
= (duk_hcompiledfunction
*) h
;
33 /* Currently nothing to free; 'data' is a heap object */
34 } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h
)) {
35 duk_hnativefunction
*f
= (duk_hnativefunction
*) h
;
37 /* Currently nothing to free */
38 } else if (DUK_HOBJECT_IS_THREAD(h
)) {
39 duk_hthread
*t
= (duk_hthread
*) h
;
40 DUK_FREE(heap
, t
->valstack
);
41 DUK_FREE(heap
, t
->callstack
);
42 DUK_FREE(heap
, t
->catchstack
);
43 /* Don't free h->resumer because it exists in the heap.
44 * Callstack entries also contain function pointers which
45 * are not freed for the same reason.
48 /* XXX: with 'caller' property the callstack would need
49 * to be unwound to update the 'caller' properties of
50 * functions in the callstack.
55 DUK_INTERNAL
void duk_free_hbuffer_inner(duk_heap
*heap
, duk_hbuffer
*h
) {
56 DUK_ASSERT(heap
!= NULL
);
57 DUK_ASSERT(h
!= NULL
);
59 if (DUK_HBUFFER_HAS_DYNAMIC(h
) && !DUK_HBUFFER_HAS_EXTERNAL(h
)) {
60 duk_hbuffer_dynamic
*g
= (duk_hbuffer_dynamic
*) h
;
61 DUK_DDD(DUK_DDDPRINT("free dynamic buffer %p", (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap
, g
)));
62 DUK_FREE(heap
, DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap
, g
));
66 DUK_INTERNAL
void duk_free_hstring_inner(duk_heap
*heap
, duk_hstring
*h
) {
67 DUK_ASSERT(heap
!= NULL
);
68 DUK_ASSERT(h
!= NULL
);
73 #if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_FREE)
74 if (DUK_HSTRING_HAS_EXTDATA(h
)) {
75 DUK_DDD(DUK_DDDPRINT("free extstr: hstring %!O, extdata: %p",
76 h
, DUK_HSTRING_GET_EXTDATA((duk_hstring_external
*) h
)));
77 DUK_USE_EXTSTR_FREE(heap
->heap_udata
, (const void *) DUK_HSTRING_GET_EXTDATA((duk_hstring_external
*) h
));
82 DUK_INTERNAL
void duk_heap_free_heaphdr_raw(duk_heap
*heap
, duk_heaphdr
*hdr
) {
86 DUK_DDD(DUK_DDDPRINT("free heaphdr %p, htype %ld", (void *) hdr
, (long) DUK_HEAPHDR_GET_TYPE(hdr
)));
88 switch ((int) DUK_HEAPHDR_GET_TYPE(hdr
)) {
89 case DUK_HTYPE_STRING
:
90 duk_free_hstring_inner(heap
, (duk_hstring
*) hdr
);
92 case DUK_HTYPE_OBJECT
:
93 duk_free_hobject_inner(heap
, (duk_hobject
*) hdr
);
95 case DUK_HTYPE_BUFFER
:
96 duk_free_hbuffer_inner(heap
, (duk_hbuffer
*) hdr
);
108 * Frees heap-related non-heap-tracked allocations such as the
109 * string intern table; then frees the heap allocated objects;
110 * and finally frees the heap structure itself. Reference counts
111 * and GC markers are ignored (and not updated) in this process,
112 * and finalizers won't be called.
114 * The heap pointer and heap object pointers must not be used
118 DUK_LOCAL
void duk__free_allocated(duk_heap
*heap
) {
122 curr
= heap
->heap_allocated
;
124 /* We don't log or warn about freeing zero refcount objects
125 * because they may happen with finalizer processing.
128 DUK_DDD(DUK_DDDPRINT("FINALFREE (allocated): %!iO",
129 (duk_heaphdr
*) curr
));
130 next
= DUK_HEAPHDR_GET_NEXT(heap
, curr
);
131 duk_heap_free_heaphdr_raw(heap
, curr
);
136 #ifdef DUK_USE_REFERENCE_COUNTING
137 DUK_LOCAL
void duk__free_refzero_list(duk_heap
*heap
) {
141 curr
= heap
->refzero_list
;
143 DUK_DDD(DUK_DDDPRINT("FINALFREE (refzero_list): %!iO",
144 (duk_heaphdr
*) curr
));
145 next
= DUK_HEAPHDR_GET_NEXT(heap
, curr
);
146 duk_heap_free_heaphdr_raw(heap
, curr
);
152 #ifdef DUK_USE_MARK_AND_SWEEP
153 DUK_LOCAL
void duk__free_markandsweep_finalize_list(duk_heap
*heap
) {
157 curr
= heap
->finalize_list
;
159 DUK_DDD(DUK_DDDPRINT("FINALFREE (finalize_list): %!iO",
160 (duk_heaphdr
*) curr
));
161 next
= DUK_HEAPHDR_GET_NEXT(heap
, curr
);
162 duk_heap_free_heaphdr_raw(heap
, curr
);
168 DUK_LOCAL
void duk__free_stringtable(duk_heap
*heap
) {
169 /* strings are only tracked by stringtable */
170 duk_heap_free_strtab(heap
);
173 DUK_LOCAL
void duk__free_run_finalizers(duk_heap
*heap
) {
177 duk_size_t count_obj
= 0;
180 DUK_ASSERT(heap
!= NULL
);
181 DUK_ASSERT(heap
->heap_thread
!= NULL
);
182 #ifdef DUK_USE_REFERENCE_COUNTING
183 DUK_ASSERT(heap
->refzero_list
== NULL
); /* refzero not running -> must be empty */
185 #ifdef DUK_USE_MARK_AND_SWEEP
186 DUK_ASSERT(heap
->finalize_list
== NULL
); /* mark-and-sweep not running -> must be empty */
189 /* XXX: here again finalizer thread is the heap_thread which needs
190 * to be coordinated with finalizer thread fixes.
192 thr
= heap
->heap_thread
;
193 DUK_ASSERT(thr
!= NULL
);
195 curr
= heap
->heap_allocated
;
197 if (DUK_HEAPHDR_GET_TYPE(curr
) == DUK_HTYPE_OBJECT
) {
198 /* Only objects in heap_allocated may have finalizers. Check that
199 * the object itself has a _Finalizer property so that we don't
200 * execute finalizers for e.g. Proxy objects.
202 DUK_ASSERT(thr
!= NULL
);
203 DUK_ASSERT(curr
!= NULL
);
205 if (duk_hobject_hasprop_raw(thr
, (duk_hobject
*) curr
, DUK_HTHREAD_STRING_INT_FINALIZER(thr
))) {
206 duk_hobject_run_finalizer(thr
, (duk_hobject
*) curr
);
212 curr
= DUK_HEAPHDR_GET_NEXT(heap
, curr
);
215 /* Note: count includes all objects, not only those with an actual finalizer. */
217 DUK_D(DUK_DPRINT("checked %ld objects for finalizers before freeing heap", (long) count_obj
));
221 DUK_INTERNAL
void duk_heap_free(duk_heap
*heap
) {
222 DUK_D(DUK_DPRINT("free heap: %p", (void *) heap
));
224 #if defined(DUK_USE_DEBUG)
225 duk_heap_dump_strtab(heap
);
228 #if defined(DUK_USE_DEBUGGER_SUPPORT)
229 /* Detach a debugger if attached (can be called multiple times)
232 duk_debug_do_detach(heap
);
235 /* Execute finalizers before freeing the heap, even for reachable
236 * objects, and regardless of whether or not mark-and-sweep is
237 * enabled. This gives finalizers the chance to free any native
238 * resources like file handles, allocations made outside Duktape,
241 * XXX: this perhaps requires an execution time limit.
243 DUK_D(DUK_DPRINT("execute finalizers before freeing heap"));
244 #ifdef DUK_USE_MARK_AND_SWEEP
245 /* run mark-and-sweep a few times just in case (unreachable
246 * object finalizers run already here)
248 duk_heap_mark_and_sweep(heap
, 0);
249 duk_heap_mark_and_sweep(heap
, 0);
251 duk__free_run_finalizers(heap
);
253 /* Note: heap->heap_thread, heap->curr_thread, and heap->heap_object
254 * are on the heap allocated list.
257 DUK_D(DUK_DPRINT("freeing heap objects of heap: %p", (void *) heap
));
258 duk__free_allocated(heap
);
260 #ifdef DUK_USE_REFERENCE_COUNTING
261 DUK_D(DUK_DPRINT("freeing refzero list of heap: %p", (void *) heap
));
262 duk__free_refzero_list(heap
);
265 #ifdef DUK_USE_MARK_AND_SWEEP
266 DUK_D(DUK_DPRINT("freeing mark-and-sweep finalize list of heap: %p", (void *) heap
));
267 duk__free_markandsweep_finalize_list(heap
);
270 DUK_D(DUK_DPRINT("freeing string table of heap: %p", (void *) heap
));
271 duk__free_stringtable(heap
);
273 DUK_D(DUK_DPRINT("freeing heap structure: %p", (void *) heap
));
274 heap
->free_func(heap
->heap_udata
, heap
);
280 * String table is initialized with built-in strings from genstrings.py.
283 /* intern built-in strings from precooked data (genstrings.py) */
284 DUK_LOCAL duk_bool_t
duk__init_heap_strings(duk_heap
*heap
) {
285 duk_bitdecoder_ctx bd_ctx
;
286 duk_bitdecoder_ctx
*bd
= &bd_ctx
; /* convenience */
287 duk_small_uint_t i
, j
;
289 DUK_MEMZERO(&bd_ctx
, sizeof(bd_ctx
));
290 bd
->data
= (const duk_uint8_t
*) duk_strings_data
;
291 bd
->length
= (duk_size_t
) DUK_STRDATA_DATA_LENGTH
;
293 for (i
= 0; i
< DUK_HEAP_NUM_STRINGS
; i
++) {
294 duk_uint8_t tmp
[DUK_STRDATA_MAX_STRLEN
];
296 duk_small_uint_t len
;
297 duk_small_uint_t mode
;
300 len
= duk_bd_decode(bd
, 5);
301 mode
= 32; /* 0 = uppercase, 32 = lowercase (= 'a' - 'A') */
302 for (j
= 0; j
< len
; j
++) {
303 t
= duk_bd_decode(bd
, 5);
304 if (t
< DUK__BITPACK_LETTER_LIMIT
) {
305 t
= t
+ DUK_ASC_UC_A
+ mode
;
306 } else if (t
== DUK__BITPACK_UNDERSCORE
) {
307 t
= DUK_ASC_UNDERSCORE
;
308 } else if (t
== DUK__BITPACK_FF
) {
309 /* Internal keys are prefixed with 0xFF in the stringtable
310 * (which makes them invalid UTF-8 on purpose).
313 } else if (t
== DUK__BITPACK_SWITCH1
) {
314 t
= duk_bd_decode(bd
, 5);
315 DUK_ASSERT_DISABLE(t
>= 0); /* unsigned */
317 t
= t
+ DUK_ASC_UC_A
+ (mode
^ 32);
318 } else if (t
== DUK__BITPACK_SWITCH
) {
320 t
= duk_bd_decode(bd
, 5);
321 DUK_ASSERT_DISABLE(t
>= 0);
323 t
= t
+ DUK_ASC_UC_A
+ mode
;
324 } else if (t
== DUK__BITPACK_SEVENBIT
) {
325 t
= duk_bd_decode(bd
, 7);
327 tmp
[j
] = (duk_uint8_t
) t
;
330 /* No need to length check string: it will never exceed even
331 * the 16-bit length maximum.
333 DUK_ASSERT(len
<= 0xffffUL
);
334 DUK_DDD(DUK_DDDPRINT("intern built-in string %ld", (long) i
));
335 h
= duk_heap_string_intern(heap
, tmp
, len
);
340 /* Special flags checks. Since these strings are always
341 * reachable and a string cannot appear twice in the string
342 * table, there's no need to check/set these flags elsewhere.
343 * The 'internal' flag is set by string intern code.
345 if (i
== DUK_STRIDX_EVAL
|| i
== DUK_STRIDX_LC_ARGUMENTS
) {
346 DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(h
);
348 if (i
>= DUK_STRIDX_START_RESERVED
&& i
< DUK_STRIDX_END_RESERVED
) {
349 DUK_HSTRING_SET_RESERVED_WORD(h
);
350 if (i
>= DUK_STRIDX_START_STRICT_RESERVED
) {
351 DUK_HSTRING_SET_STRICT_RESERVED_WORD(h
);
355 DUK_DDD(DUK_DDDPRINT("interned: %!O", (duk_heaphdr
*) h
));
357 /* XXX: The incref macro takes a thread pointer but doesn't
360 DUK_HSTRING_INCREF(_never_referenced_
, h
);
362 #if defined(DUK_USE_HEAPPTR16)
363 heap
->strs16
[i
] = DUK_USE_HEAPPTR_ENC16(heap
->heap_udata
, (void *) h
);
375 DUK_LOCAL duk_bool_t
duk__init_heap_thread(duk_heap
*heap
) {
378 DUK_DD(DUK_DDPRINT("heap init: alloc heap thread"));
379 thr
= duk_hthread_alloc(heap
,
380 DUK_HOBJECT_FLAG_EXTENSIBLE
|
381 DUK_HOBJECT_FLAG_THREAD
|
382 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD
));
384 DUK_D(DUK_DPRINT("failed to alloc heap_thread"));
387 thr
->state
= DUK_HTHREAD_STATE_INACTIVE
;
388 #if defined(DUK_USE_HEAPPTR16)
389 thr
->strs16
= heap
->strs16
;
391 thr
->strs
= heap
->strs
;
394 heap
->heap_thread
= thr
;
395 DUK_HTHREAD_INCREF(thr
, thr
); /* Note: first argument not really used */
397 /* 'thr' is now reachable */
399 if (!duk_hthread_init_stacks(heap
, thr
)) {
403 /* XXX: this may now fail, and is not handled correctly */
404 duk_hthread_create_builtin_objects(thr
);
406 /* default prototype (Note: 'thr' must be reachable) */
407 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr
, (duk_hobject
*) thr
, thr
->builtins
[DUK_BIDX_THREAD_PROTOTYPE
]);
413 #define DUK__DUMPSZ(t) do { \
414 DUK_D(DUK_DPRINT("" #t "=%ld", (long) sizeof(t))); \
417 /* These is not 100% because format would need to be non-portable "long long".
418 * Also print out as doubles to catch cases where the "long" type is not wide
419 * enough; the limits will then not be printed accurately but the magnitude
422 #define DUK__DUMPLM_SIGNED_RAW(t,a,b) do { \
423 DUK_D(DUK_DPRINT(t "=[%ld,%ld]=[%lf,%lf]", \
424 (long) (a), (long) (b), \
425 (double) (a), (double) (b))); \
427 #define DUK__DUMPLM_UNSIGNED_RAW(t,a,b) do { \
428 DUK_D(DUK_DPRINT(t "=[%lu,%lu]=[%lf,%lf]", \
429 (unsigned long) (a), (unsigned long) (b), \
430 (double) (a), (double) (b))); \
432 #define DUK__DUMPLM_SIGNED(t) do { \
433 DUK__DUMPLM_SIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \
435 #define DUK__DUMPLM_UNSIGNED(t) do { \
436 DUK__DUMPLM_UNSIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \
439 DUK_LOCAL
void duk__dump_type_sizes(void) {
440 DUK_D(DUK_DPRINT("sizeof()"));
442 /* basic platform types */
451 /* basic types from duk_features.h */
452 DUK__DUMPSZ(duk_uint8_t
);
453 DUK__DUMPSZ(duk_int8_t
);
454 DUK__DUMPSZ(duk_uint16_t
);
455 DUK__DUMPSZ(duk_int16_t
);
456 DUK__DUMPSZ(duk_uint32_t
);
457 DUK__DUMPSZ(duk_int32_t
);
458 DUK__DUMPSZ(duk_uint64_t
);
459 DUK__DUMPSZ(duk_int64_t
);
460 DUK__DUMPSZ(duk_uint_least8_t
);
461 DUK__DUMPSZ(duk_int_least8_t
);
462 DUK__DUMPSZ(duk_uint_least16_t
);
463 DUK__DUMPSZ(duk_int_least16_t
);
464 DUK__DUMPSZ(duk_uint_least32_t
);
465 DUK__DUMPSZ(duk_int_least32_t
);
466 #if defined(DUK_USE_64BIT_OPS)
467 DUK__DUMPSZ(duk_uint_least64_t
);
468 DUK__DUMPSZ(duk_int_least64_t
);
470 DUK__DUMPSZ(duk_uint_fast8_t
);
471 DUK__DUMPSZ(duk_int_fast8_t
);
472 DUK__DUMPSZ(duk_uint_fast16_t
);
473 DUK__DUMPSZ(duk_int_fast16_t
);
474 DUK__DUMPSZ(duk_uint_fast32_t
);
475 DUK__DUMPSZ(duk_int_fast32_t
);
476 #if defined(DUK_USE_64BIT_OPS)
477 DUK__DUMPSZ(duk_uint_fast64_t
);
478 DUK__DUMPSZ(duk_int_fast64_t
);
480 DUK__DUMPSZ(duk_uintptr_t
);
481 DUK__DUMPSZ(duk_intptr_t
);
482 DUK__DUMPSZ(duk_uintmax_t
);
483 DUK__DUMPSZ(duk_intmax_t
);
484 DUK__DUMPSZ(duk_double_t
);
486 /* important chosen base types */
487 DUK__DUMPSZ(duk_int_t
);
488 DUK__DUMPSZ(duk_uint_t
);
489 DUK__DUMPSZ(duk_int_fast_t
);
490 DUK__DUMPSZ(duk_uint_fast_t
);
491 DUK__DUMPSZ(duk_small_int_t
);
492 DUK__DUMPSZ(duk_small_uint_t
);
493 DUK__DUMPSZ(duk_small_int_fast_t
);
494 DUK__DUMPSZ(duk_small_uint_fast_t
);
496 /* some derived types */
497 DUK__DUMPSZ(duk_codepoint_t
);
498 DUK__DUMPSZ(duk_ucodepoint_t
);
499 DUK__DUMPSZ(duk_idx_t
);
500 DUK__DUMPSZ(duk_errcode_t
);
501 DUK__DUMPSZ(duk_uarridx_t
);
504 DUK__DUMPSZ(duk_double_union
);
505 DUK__DUMPSZ(duk_tval
);
507 /* structs from duk_forwdecl.h */
508 DUK__DUMPSZ(duk_jmpbuf
);
509 DUK__DUMPSZ(duk_heaphdr
);
510 DUK__DUMPSZ(duk_heaphdr_string
);
511 DUK__DUMPSZ(duk_hstring
);
512 DUK__DUMPSZ(duk_hstring_external
);
513 DUK__DUMPSZ(duk_hobject
);
514 DUK__DUMPSZ(duk_hcompiledfunction
);
515 DUK__DUMPSZ(duk_hnativefunction
);
516 DUK__DUMPSZ(duk_hthread
);
517 DUK__DUMPSZ(duk_hbuffer
);
518 DUK__DUMPSZ(duk_hbuffer_fixed
);
519 DUK__DUMPSZ(duk_hbuffer_dynamic
);
520 DUK__DUMPSZ(duk_hbuffer_external
);
521 DUK__DUMPSZ(duk_propaccessor
);
522 DUK__DUMPSZ(duk_propvalue
);
523 DUK__DUMPSZ(duk_propdesc
);
524 DUK__DUMPSZ(duk_heap
);
525 #if defined(DUK_USE_STRTAB_CHAIN)
526 DUK__DUMPSZ(duk_strtab_entry
);
528 DUK__DUMPSZ(duk_activation
);
529 DUK__DUMPSZ(duk_catcher
);
530 DUK__DUMPSZ(duk_strcache
);
531 DUK__DUMPSZ(duk_ljstate
);
532 DUK__DUMPSZ(duk_fixedbuffer
);
533 DUK__DUMPSZ(duk_bitdecoder_ctx
);
534 DUK__DUMPSZ(duk_bitencoder_ctx
);
535 DUK__DUMPSZ(duk_token
);
536 DUK__DUMPSZ(duk_re_token
);
537 DUK__DUMPSZ(duk_lexer_point
);
538 DUK__DUMPSZ(duk_lexer_ctx
);
539 DUK__DUMPSZ(duk_compiler_instr
);
540 DUK__DUMPSZ(duk_compiler_func
);
541 DUK__DUMPSZ(duk_compiler_ctx
);
542 DUK__DUMPSZ(duk_re_matcher_ctx
);
543 DUK__DUMPSZ(duk_re_compiler_ctx
);
545 DUK_LOCAL
void duk__dump_type_limits(void) {
546 DUK_D(DUK_DPRINT("limits"));
549 DUK__DUMPLM_SIGNED(INT8
);
550 DUK__DUMPLM_UNSIGNED(UINT8
);
551 DUK__DUMPLM_SIGNED(INT_FAST8
);
552 DUK__DUMPLM_UNSIGNED(UINT_FAST8
);
553 DUK__DUMPLM_SIGNED(INT_LEAST8
);
554 DUK__DUMPLM_UNSIGNED(UINT_LEAST8
);
555 DUK__DUMPLM_SIGNED(INT16
);
556 DUK__DUMPLM_UNSIGNED(UINT16
);
557 DUK__DUMPLM_SIGNED(INT_FAST16
);
558 DUK__DUMPLM_UNSIGNED(UINT_FAST16
);
559 DUK__DUMPLM_SIGNED(INT_LEAST16
);
560 DUK__DUMPLM_UNSIGNED(UINT_LEAST16
);
561 DUK__DUMPLM_SIGNED(INT32
);
562 DUK__DUMPLM_UNSIGNED(UINT32
);
563 DUK__DUMPLM_SIGNED(INT_FAST32
);
564 DUK__DUMPLM_UNSIGNED(UINT_FAST32
);
565 DUK__DUMPLM_SIGNED(INT_LEAST32
);
566 DUK__DUMPLM_UNSIGNED(UINT_LEAST32
);
567 #if defined(DUK_USE_64BIT_OPS)
568 DUK__DUMPLM_SIGNED(INT64
);
569 DUK__DUMPLM_UNSIGNED(UINT64
);
570 DUK__DUMPLM_SIGNED(INT_FAST64
);
571 DUK__DUMPLM_UNSIGNED(UINT_FAST64
);
572 DUK__DUMPLM_SIGNED(INT_LEAST64
);
573 DUK__DUMPLM_UNSIGNED(UINT_LEAST64
);
575 DUK__DUMPLM_SIGNED(INTPTR
);
576 DUK__DUMPLM_UNSIGNED(UINTPTR
);
577 DUK__DUMPLM_SIGNED(INTMAX
);
578 DUK__DUMPLM_UNSIGNED(UINTMAX
);
581 DUK__DUMPLM_SIGNED(INT
);
582 DUK__DUMPLM_UNSIGNED(UINT
);
583 DUK__DUMPLM_SIGNED(INT_FAST
);
584 DUK__DUMPLM_UNSIGNED(UINT_FAST
);
585 DUK__DUMPLM_SIGNED(SMALL_INT
);
586 DUK__DUMPLM_UNSIGNED(SMALL_UINT
);
587 DUK__DUMPLM_SIGNED(SMALL_INT_FAST
);
588 DUK__DUMPLM_UNSIGNED(SMALL_UINT_FAST
);
591 #undef DUK__DUMPLM_SIGNED_RAW
592 #undef DUK__DUMPLM_UNSIGNED_RAW
593 #undef DUK__DUMPLM_SIGNED
594 #undef DUK__DUMPLM_UNSIGNED
596 DUK_LOCAL
void duk__dump_misc_options(void) {
597 DUK_D(DUK_DPRINT("DUK_VERSION: %ld", (long) DUK_VERSION
));
598 DUK_D(DUK_DPRINT("DUK_GIT_DESCRIBE: %s", DUK_GIT_DESCRIBE
));
599 #if defined(DUK_USE_PACKED_TVAL)
600 DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: yes"));
602 DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: no"));
604 #if defined(DUK_USE_INTEGER_LE)
605 DUK_D(DUK_DPRINT("Integer endianness: little"));
606 #elif defined(DUK_USE_INTEGER_ME)
607 DUK_D(DUK_DPRINT("Integer endianness: mixed"));
608 #elif defined(DUK_USE_INTEGER_BE)
609 DUK_D(DUK_DPRINT("Integer endianness: big"));
611 DUK_D(DUK_DPRINT("Integer endianness: ???"));
613 #if defined(DUK_USE_DOUBLE_LE)
614 DUK_D(DUK_DPRINT("IEEE double endianness: little"));
615 #elif defined(DUK_USE_DOUBLE_ME)
616 DUK_D(DUK_DPRINT("IEEE double endianness: mixed"));
617 #elif defined(DUK_USE_DOUBLE_BE)
618 DUK_D(DUK_DPRINT("IEEE double endianness: big"));
620 DUK_D(DUK_DPRINT("IEEE double endianness: ???"));
623 #endif /* DUK_USE_DEBUG */
626 duk_heap
*duk_heap_alloc(duk_alloc_function alloc_func
,
627 duk_realloc_function realloc_func
,
628 duk_free_function free_func
,
630 duk_fatal_function fatal_func
) {
631 duk_heap
*res
= NULL
;
633 /* Silence a few global unused warnings here. */
634 DUK_UNREF(duk_str_unsupported
);
636 DUK_D(DUK_DPRINT("allocate heap"));
639 * Debug dump type sizes
643 duk__dump_misc_options();
644 duk__dump_type_sizes();
645 duk__dump_type_limits();
649 * If selftests enabled, run them as early as possible
651 #ifdef DUK_USE_SELF_TESTS
652 DUK_D(DUK_DPRINT("running self tests"));
653 duk_selftest_run_tests();
654 DUK_D(DUK_DPRINT("self tests passed"));
658 * Computed values (e.g. INFINITY)
661 #ifdef DUK_USE_COMPUTED_NAN
663 /* Workaround for some exotic platforms where NAN is missing
664 * and the expression (0.0 / 0.0) does NOT result in a NaN.
665 * Such platforms use the global 'duk_computed_nan' which must
666 * be initialized at runtime. Use 'volatile' to ensure that
667 * the compiler will actually do the computation and not try
668 * to do constant folding which might result in the original
671 volatile double dbl1
= 0.0;
672 volatile double dbl2
= 0.0;
673 duk_computed_nan
= dbl1
/ dbl2
;
677 #ifdef DUK_USE_COMPUTED_INFINITY
679 /* Similar workaround for INFINITY. */
680 volatile double dbl1
= 1.0;
681 volatile double dbl2
= 0.0;
682 duk_computed_infinity
= dbl1
/ dbl2
;
687 * Allocate heap struct
689 * Use a raw call, all macros expect the heap to be initialized
692 res
= (duk_heap
*) alloc_func(heap_udata
, sizeof(duk_heap
));
698 * Zero the struct, and start initializing roughly in order
701 DUK_MEMZERO(res
, sizeof(*res
));
703 /* explicit NULL inits */
704 #ifdef DUK_USE_EXPLICIT_NULL_INIT
705 res
->heap_udata
= NULL
;
706 res
->heap_allocated
= NULL
;
707 #ifdef DUK_USE_REFERENCE_COUNTING
708 res
->refzero_list
= NULL
;
709 res
->refzero_list_tail
= NULL
;
711 #ifdef DUK_USE_MARK_AND_SWEEP
712 res
->finalize_list
= NULL
;
714 res
->heap_thread
= NULL
;
715 res
->curr_thread
= NULL
;
716 res
->heap_object
= NULL
;
717 #if defined(DUK_USE_STRTAB_CHAIN)
718 /* nothing to NULL */
719 #elif defined(DUK_USE_STRTAB_PROBE)
720 #if defined(DUK_USE_HEAPPTR16)
721 res
->strtable16
= (duk_uint16_t
*) NULL
;
723 res
->strtable
= (duk_hstring
**) NULL
;
726 #if defined(DUK_USE_HEAPPTR16)
727 /* res->strs16[] is zeroed and zero decodes to NULL, so no NULL inits. */
731 for (i
= 0; i
< DUK_HEAP_NUM_STRINGS
; i
++) {
736 #if defined(DUK_USE_DEBUGGER_SUPPORT)
737 res
->dbg_read_cb
= NULL
;
738 res
->dbg_write_cb
= NULL
;
739 res
->dbg_peek_cb
= NULL
;
740 res
->dbg_read_flush_cb
= NULL
;
741 res
->dbg_write_flush_cb
= NULL
;
742 res
->dbg_udata
= NULL
;
743 res
->dbg_step_thread
= NULL
;
745 #endif /* DUK_USE_EXPLICIT_NULL_INIT */
747 res
->alloc_func
= alloc_func
;
748 res
->realloc_func
= realloc_func
;
749 res
->free_func
= free_func
;
750 res
->heap_udata
= heap_udata
;
751 res
->fatal_func
= fatal_func
;
753 #if defined(DUK_USE_HEAPPTR16)
754 /* XXX: zero assumption */
755 res
->heapptr_null16
= DUK_USE_HEAPPTR_ENC16(res
->heap_udata
, (void *) NULL
);
756 res
->heapptr_deleted16
= DUK_USE_HEAPPTR_ENC16(res
->heap_udata
, (void *) DUK_STRTAB_DELETED_MARKER(res
));
759 /* res->mark_and_sweep_trigger_counter == 0 -> now causes immediate GC; which is OK */
761 res
->call_recursion_depth
= 0;
762 res
->call_recursion_limit
= DUK_USE_NATIVE_CALL_RECLIMIT
;
764 /* XXX: use the pointer as a seed for now: mix in time at least */
766 /* The casts through duk_intr_pt is to avoid the following GCC warning:
768 * warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
770 * This still generates a /Wp64 warning on VS2010 when compiling for x86.
772 res
->hash_seed
= (duk_uint32_t
) (duk_intptr_t
) res
;
773 res
->rnd_state
= (duk_uint32_t
) (duk_intptr_t
) res
;
775 #ifdef DUK_USE_EXPLICIT_NULL_INIT
776 res
->lj
.jmpbuf_ptr
= NULL
;
778 DUK_ASSERT(res
->lj
.type
== DUK_LJ_TYPE_UNKNOWN
); /* zero */
780 DUK_TVAL_SET_UNDEFINED_UNUSED(&res
->lj
.value1
);
781 DUK_TVAL_SET_UNDEFINED_UNUSED(&res
->lj
.value2
);
783 #if (DUK_STRTAB_INITIAL_SIZE < DUK_UTIL_MIN_HASH_PRIME)
784 #error initial heap stringtable size is defined incorrectly
788 * Init stringtable: fixed variant
791 #if defined(DUK_USE_STRTAB_CHAIN)
792 DUK_MEMZERO(res
->strtable
, sizeof(duk_strtab_entry
) * DUK_STRTAB_CHAIN_SIZE
);
793 #ifdef DUK_USE_EXPLICIT_NULL_INIT
796 for (i
= 0; i
< DUK_STRTAB_CHAIN_SIZE
; i
++) {
797 #if defined(DUK_USE_HEAPPTR16)
798 res
->strtable
[i
].u
.str16
= res
->heapptr_null16
;
800 res
->strtable
[i
].u
.str
= NULL
;
804 #endif /* DUK_USE_EXPLICIT_NULL_INIT */
805 #endif /* DUK_USE_STRTAB_CHAIN */
808 * Init stringtable: probe variant
811 #if defined(DUK_USE_STRTAB_PROBE)
812 #if defined(DUK_USE_HEAPPTR16)
813 res
->strtable16
= (duk_uint16_t
*) alloc_func(heap_udata
, sizeof(duk_uint16_t
) * DUK_STRTAB_INITIAL_SIZE
);
814 if (!res
->strtable16
) {
817 #else /* DUK_USE_HEAPPTR16 */
818 res
->strtable
= (duk_hstring
**) alloc_func(heap_udata
, sizeof(duk_hstring
*) * DUK_STRTAB_INITIAL_SIZE
);
819 if (!res
->strtable
) {
822 #endif /* DUK_USE_HEAPPTR16 */
823 res
->st_size
= DUK_STRTAB_INITIAL_SIZE
;
824 #ifdef DUK_USE_EXPLICIT_NULL_INIT
827 DUK_ASSERT(res
->st_size
== DUK_STRTAB_INITIAL_SIZE
);
828 for (i
= 0; i
< DUK_STRTAB_INITIAL_SIZE
; i
++) {
829 #if defined(DUK_USE_HEAPPTR16)
830 res
->strtable16
[i
] = res
->heapptr_null16
;
832 res
->strtable
[i
] = NULL
;
836 #else /* DUK_USE_EXPLICIT_NULL_INIT */
837 #if defined(DUK_USE_HEAPPTR16)
838 DUK_MEMZERO(res
->strtable16
, sizeof(duk_uint16_t
) * DUK_STRTAB_INITIAL_SIZE
);
840 DUK_MEMZERO(res
->strtable
, sizeof(duk_hstring
*) * DUK_STRTAB_INITIAL_SIZE
);
842 #endif /* DUK_USE_EXPLICIT_NULL_INIT */
843 #endif /* DUK_USE_STRTAB_PROBE */
849 #ifdef DUK_USE_EXPLICIT_NULL_INIT
852 for (i
= 0; i
< DUK_HEAP_STRCACHE_SIZE
; i
++) {
853 res
->strcache
[i
].h
= NULL
;
858 /* XXX: error handling is incomplete. It would be cleanest if
859 * there was a setjmp catchpoint, so that all init code could
860 * freely throw errors. If that were the case, the return code
861 * passing here could be removed.
865 * Init built-in strings
868 DUK_DD(DUK_DDPRINT("HEAP: INIT STRINGS"));
869 if (!duk__init_heap_strings(res
)) {
874 * Init the heap thread
877 DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP THREAD"));
878 if (!duk__init_heap_thread(res
)) {
883 * Init the heap object
886 DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP OBJECT"));
887 DUK_ASSERT(res
->heap_thread
!= NULL
);
888 res
->heap_object
= duk_hobject_alloc(res
, DUK_HOBJECT_FLAG_EXTENSIBLE
|
889 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT
));
890 if (!res
->heap_object
) {
893 DUK_HOBJECT_INCREF(res
->heap_thread
, res
->heap_object
);
899 DUK_D(DUK_DPRINT("allocated heap: %p", (void *) res
));
903 DUK_D(DUK_DPRINT("heap allocation failed"));
906 /* assumes that allocated pointers and alloc funcs are valid
909 DUK_ASSERT(res
->alloc_func
!= NULL
);
910 DUK_ASSERT(res
->realloc_func
!= NULL
);
911 DUK_ASSERT(res
->free_func
!= NULL
);