| /* |
| * Heap structure. |
| * |
| * Heap contains allocated heap objects, interned strings, and built-in |
| * strings for one or more threads. |
| */ |
| |
| #ifndef DUK_HEAP_H_INCLUDED |
| #define DUK_HEAP_H_INCLUDED |
| |
| /* alloc function typedefs in duktape.h */ |
| |
| /* |
| * Heap flags |
| */ |
| |
| #define DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING (1 << 0) /* mark-and-sweep is currently running */ |
| #define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1 << 1) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */ |
| #define DUK_HEAP_FLAG_REFZERO_FREE_RUNNING (1 << 2) /* refcount code is processing refzero list */ |
| #define DUK_HEAP_FLAG_ERRHANDLER_RUNNING (1 << 3) /* an error handler (user callback to augment/replace error) is running */ |
| #define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1 << 4) /* executor interrupt running (used to avoid nested interrupts) */ |
| #define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1 << 5) /* heap destruction ongoing, finalizer rescue no longer possible */ |
| |
| #define DUK__HEAP_HAS_FLAGS(heap,bits) ((heap)->flags & (bits)) |
| #define DUK__HEAP_SET_FLAGS(heap,bits) do { \ |
| (heap)->flags |= (bits); \ |
| } while (0) |
| #define DUK__HEAP_CLEAR_FLAGS(heap,bits) do { \ |
| (heap)->flags &= ~(bits); \ |
| } while (0) |
| |
| #define DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) |
| #define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) |
| #define DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) |
| #define DUK_HEAP_HAS_ERRHANDLER_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) |
| #define DUK_HEAP_HAS_INTERRUPT_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING) |
| #define DUK_HEAP_HAS_FINALIZER_NORESCUE(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE) |
| |
| #define DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) |
| #define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) |
| #define DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) |
| #define DUK_HEAP_SET_ERRHANDLER_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) |
| #define DUK_HEAP_SET_INTERRUPT_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING) |
| #define DUK_HEAP_SET_FINALIZER_NORESCUE(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE) |
| |
| #define DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING) |
| #define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) |
| #define DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING) |
| #define DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING) |
| #define DUK_HEAP_CLEAR_INTERRUPT_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING) |
| #define DUK_HEAP_CLEAR_FINALIZER_NORESCUE(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE) |
| |
| /* |
| * Longjmp types, also double as identifying continuation type for a rethrow (in 'finally') |
| */ |
| |
| #define DUK_LJ_TYPE_UNKNOWN 0 /* unused */ |
| #define DUK_LJ_TYPE_THROW 1 /* value1 -> error object */ |
| #define DUK_LJ_TYPE_YIELD 2 /* value1 -> yield value, iserror -> error / normal */ |
| #define DUK_LJ_TYPE_RESUME 3 /* value1 -> resume value, value2 -> resumee thread, iserror -> error/normal */ |
| #define DUK_LJ_TYPE_BREAK 4 /* value1 -> label number, pseudo-type to indicate a break continuation (for ENDFIN) */ |
| #define DUK_LJ_TYPE_CONTINUE 5 /* value1 -> label number, pseudo-type to indicate a continue continuation (for ENDFIN) */ |
| #define DUK_LJ_TYPE_RETURN 6 /* value1 -> return value, pseudo-type to indicate a return continuation (for ENDFIN) */ |
| #define DUK_LJ_TYPE_NORMAL 7 /* no value, pseudo-type to indicate a normal continuation (for ENDFIN) */ |
| |
| /* |
| * Mark-and-sweep flags |
| * |
| * These are separate from heap level flags now but could be merged. |
| * The heap structure only contains a 'base mark-and-sweep flags' |
| * field and the GC caller can impose further flags. |
| */ |
| |
| #define DUK_MS_FLAG_EMERGENCY (1 << 0) /* emergency mode: try extra hard */ |
| #define DUK_MS_FLAG_NO_STRINGTABLE_RESIZE (1 << 1) /* don't resize stringtable (but may sweep it); needed during stringtable resize */ |
| #define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1 << 2) /* don't compact objects; needed during object property allocation resize */ |
| #define DUK_MS_FLAG_NO_FINALIZERS (1 << 3) /* don't run finalizers; leave finalizable objects in finalize_list for next round */ |
| #define DUK_MS_FLAG_SKIP_FINALIZERS (1 << 4) /* don't run finalizers; queue finalizable objects back to heap_allocated */ |
| |
| /* |
| * Thread switching |
| * |
| * To switch heap->curr_thread, use the macro below so that interrupt counters |
| * get updated correctly. The macro allows a NULL target thread because that |
| * happens e.g. in call handling. |
| */ |
| |
| #if defined(DUK_USE_INTERRUPT_COUNTER) |
| #define DUK_HEAP_SWITCH_THREAD(heap,newthr) duk_heap_switch_thread((heap), (newthr)) |
| #else |
| #define DUK_HEAP_SWITCH_THREAD(heap,newthr) do { \ |
| (heap)->curr_thread = (newthr); \ |
| } while (0) |
| #endif |
| |
| /* |
| * Other heap related defines |
| */ |
| |
| /* Mark-and-sweep interval is relative to combined count of objects and |
| * strings kept in the heap during the latest mark-and-sweep pass. |
| * Fixed point .8 multiplier and .0 adder. Trigger count (interval) is |
| * decreased by each (re)allocation attempt (regardless of size), and each |
| * refzero processed object. |
| * |
| * 'SKIP' indicates how many (re)allocations to wait until a retry if |
| * GC is skipped because there is no thread do it with yet (happens |
| * only during init phases). |
| */ |
| #if defined(DUK_USE_MARK_AND_SWEEP) |
| #if defined(DUK_USE_REFERENCE_COUNTING) |
| #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 12800L /* 50x heap size */ |
| #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L |
| #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L |
| #else |
| #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 256L /* 1x heap size */ |
| #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L |
| #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L |
| #endif |
| #endif |
| |
| /* Stringcache is used for speeding up char-offset-to-byte-offset |
| * translations for non-ASCII strings. |
| */ |
| #define DUK_HEAP_STRCACHE_SIZE 4 |
| #define DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT 16 /* strings up to the this length are not cached */ |
| |
| /* helper to insert a (non-string) heap object into heap allocated list */ |
| #define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr) duk_heap_insert_into_heap_allocated((heap),(hdr)) |
| |
| /* |
| * Stringtable |
| */ |
| |
| /* initial stringtable size, must be prime and higher than DUK_UTIL_MIN_HASH_PRIME */ |
| #define DUK_STRTAB_INITIAL_SIZE 17 |
| |
| /* indicates a deleted string; any fixed non-NULL, non-hstring pointer works */ |
| #define DUK_STRTAB_DELETED_MARKER(heap) ((duk_hstring *) heap) |
| |
| /* resizing parameters */ |
| #define DUK_STRTAB_MIN_FREE_DIVISOR 4 /* load factor max 75% */ |
| #define DUK_STRTAB_MIN_USED_DIVISOR 4 /* load factor min 25% */ |
| #define DUK_STRTAB_GROW_ST_SIZE(n) ((n) + (n)) /* used entries + approx 100% -> reset load to 50% */ |
| |
| #define DUK_STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */ |
| #define DUK_STRTAB_HIGHEST_32BIT_PRIME 0xfffffffbUL |
| |
| /* probe sequence (open addressing) */ |
| #define DUK_STRTAB_HASH_INITIAL(hash,h_size) ((hash) % (h_size)) |
| #define DUK_STRTAB_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash)) |
| |
| /* fixed top level hashtable size (separate chaining) */ |
| #define DUK_STRTAB_CHAIN_SIZE DUK_USE_STRTAB_CHAIN_SIZE |
| |
| /* |
| * Built-in strings |
| */ |
| |
| /* heap string indices are autogenerated in duk_strings.h */ |
| #if defined(DUK_USE_ROM_STRINGS) |
| #define DUK_HEAP_GET_STRING(heap,idx) \ |
| ((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)])) |
| #else /* DUK_USE_ROM_STRINGS */ |
| #if defined(DUK_USE_HEAPPTR16) |
| #define DUK_HEAP_GET_STRING(heap,idx) \ |
| ((duk_hstring *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (heap)->strs16[(idx)])) |
| #else |
| #define DUK_HEAP_GET_STRING(heap,idx) \ |
| ((heap)->strs[(idx)]) |
| #endif |
| #endif /* DUK_USE_ROM_STRINGS */ |
| |
| /* |
| * Raw memory calls: relative to heap, but no GC interaction |
| */ |
| |
| #define DUK_ALLOC_RAW(heap,size) \ |
| ((heap)->alloc_func((heap)->heap_udata, (size))) |
| |
| #define DUK_REALLOC_RAW(heap,ptr,newsize) \ |
| ((heap)->realloc_func((heap)->heap_udata, (void *) (ptr), (newsize))) |
| |
| #define DUK_FREE_RAW(heap,ptr) \ |
| ((heap)->free_func((heap)->heap_udata, (void *) (ptr))) |
| |
| /* |
| * Memory calls: relative to heap, GC interaction, but no error throwing. |
| * |
| * XXX: Currently a mark-and-sweep triggered by memory allocation will run |
| * using the heap->heap_thread. This thread is also used for running |
| * mark-and-sweep finalization; this is not ideal because it breaks the |
| * isolation between multiple global environments. |
| * |
| * Notes: |
| * |
| * - DUK_FREE() is required to ignore NULL and any other possible return |
| * value of a zero-sized alloc/realloc (same as ANSI C free()). |
| * |
| * - There is no DUK_REALLOC_ZEROED because we don't assume to know the |
| * old size. Caller must zero the reallocated memory. |
| * |
| * - DUK_REALLOC_INDIRECT() must be used when a mark-and-sweep triggered |
| * by an allocation failure might invalidate the original 'ptr', thus |
| * causing a realloc retry to use an invalid pointer. Example: we're |
| * reallocating the value stack and a finalizer resizes the same value |
| * stack during mark-and-sweep. The indirect variant requests for the |
| * current location of the pointer being reallocated using a callback |
| * right before every realloc attempt; this circuitous approach is used |
| * to avoid strict aliasing issues in a more straightforward indirect |
| * pointer (void **) approach. Note: the pointer in the storage |
| * location is read but is NOT updated; the caller must do that. |
| */ |
| |
| /* callback for indirect reallocs, request for current pointer */ |
| typedef void *(*duk_mem_getptr)(duk_heap *heap, void *ud); |
| |
| #define DUK_ALLOC(heap,size) duk_heap_mem_alloc((heap), (size)) |
| #define DUK_ALLOC_ZEROED(heap,size) duk_heap_mem_alloc_zeroed((heap), (size)) |
| #define DUK_REALLOC(heap,ptr,newsize) duk_heap_mem_realloc((heap), (ptr), (newsize)) |
| #define DUK_REALLOC_INDIRECT(heap,cb,ud,newsize) duk_heap_mem_realloc_indirect((heap), (cb), (ud), (newsize)) |
| #define DUK_FREE(heap,ptr) duk_heap_mem_free((heap), (ptr)) |
| |
| /* |
| * Memory constants |
| */ |
| |
| #define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT 5 /* Retry allocation after mark-and-sweep for this |
| * many times. A single mark-and-sweep round is |
| * not guaranteed to free all unreferenced memory |
| * because of finalization (in fact, ANY number of |
| * rounds is strictly not enough). |
| */ |
| |
| #define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT 3 /* Starting from this round, use emergency mode |
| * for mark-and-sweep. |
| */ |
| |
| /* |
| * Debugger support |
| */ |
| |
| /* Maximum number of breakpoints. Only breakpoints that are set are |
| * consulted so increasing this has no performance impact. |
| */ |
| #define DUK_HEAP_MAX_BREAKPOINTS 16 |
| |
| /* Opcode interval for a Date-based status/peek rate limit check. Only |
| * relevant when debugger is attached. Requesting a timestamp may be a |
| * slow operation on some platforms so this shouldn't be too low. On the |
| * other hand a high value makes Duktape react to a pause request slowly. |
| */ |
| #define DUK_HEAP_DBG_RATELIMIT_OPCODES 4000 |
| |
| /* Milliseconds between status notify and transport peeks. */ |
| #define DUK_HEAP_DBG_RATELIMIT_MILLISECS 200 |
| |
| /* Step types */ |
| #define DUK_STEP_TYPE_NONE 0 |
| #define DUK_STEP_TYPE_INTO 1 |
| #define DUK_STEP_TYPE_OVER 2 |
| #define DUK_STEP_TYPE_OUT 3 |
| |
| struct duk_breakpoint { |
| duk_hstring *filename; |
| duk_uint32_t line; |
| }; |
| |
| #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| #define DUK_HEAP_IS_DEBUGGER_ATTACHED(heap) ((heap)->dbg_read_cb != NULL) |
| #define DUK_HEAP_CLEAR_STEP_STATE(heap) do { \ |
| (heap)->dbg_step_type = DUK_STEP_TYPE_NONE; \ |
| (heap)->dbg_step_thread = NULL; \ |
| (heap)->dbg_step_csindex = 0; \ |
| (heap)->dbg_step_startline = 0; \ |
| } while (0) |
| #define DUK_HEAP_SET_PAUSED(heap) do { \ |
| (heap)->dbg_paused = 1; \ |
| (heap)->dbg_state_dirty = 1; \ |
| DUK_HEAP_CLEAR_STEP_STATE((heap)); \ |
| } while (0) |
| #define DUK_HEAP_CLEAR_PAUSED(heap) do { \ |
| (heap)->dbg_paused = 0; \ |
| (heap)->dbg_state_dirty = 1; \ |
| DUK_HEAP_CLEAR_STEP_STATE((heap)); \ |
| } while (0) |
| #define DUK_HEAP_IS_PAUSED(heap) ((heap)->dbg_paused) |
| #endif /* DUK_USE_DEBUGGER_SUPPORT */ |
| |
| /* |
| * String cache should ideally be at duk_hthread level, but that would |
| * cause string finalization to slow down relative to the number of |
| * threads; string finalization must check the string cache for "weak" |
| * references to the string being finalized to avoid dead pointers. |
| * |
| * Thus, string caches are now at the heap level now. |
| */ |
| |
| struct duk_strcache { |
| duk_hstring *h; |
| duk_uint32_t bidx; |
| duk_uint32_t cidx; |
| }; |
| |
| /* |
| * Longjmp state, contains the information needed to perform a longjmp. |
| * Longjmp related values are written to value1, value2, and iserror. |
| */ |
| |
| struct duk_ljstate { |
| duk_jmpbuf *jmpbuf_ptr; /* current setjmp() catchpoint */ |
| duk_small_uint_t type; /* longjmp type */ |
| duk_bool_t iserror; /* isError flag for yield */ |
| duk_tval value1; /* 1st related value (type specific) */ |
| duk_tval value2; /* 2nd related value (type specific) */ |
| }; |
| |
| /* |
| * Stringtable entry for fixed size stringtable |
| */ |
| |
| struct duk_strtab_entry { |
| #if defined(DUK_USE_HEAPPTR16) |
| /* A 16-bit listlen makes sense with 16-bit heap pointers: there |
| * won't be space for 64k strings anyway. |
| */ |
| duk_uint16_t listlen; /* if 0, 'str16' used, if > 0, 'strlist16' used */ |
| union { |
| duk_uint16_t strlist16; |
| duk_uint16_t str16; |
| } u; |
| #else |
| duk_size_t listlen; /* if 0, 'str' used, if > 0, 'strlist' used */ |
| union { |
| duk_hstring **strlist; |
| duk_hstring *str; |
| } u; |
| #endif |
| }; |
| |
| /* |
| * Main heap structure |
| */ |
| |
| struct duk_heap { |
| duk_small_uint_t flags; |
| |
| /* Allocator functions. */ |
| duk_alloc_function alloc_func; |
| duk_realloc_function realloc_func; |
| duk_free_function free_func; |
| |
| /* Heap udata, used for allocator functions but also for other heap |
| * level callbacks like pointer compression, etc. |
| */ |
| void *heap_udata; |
| |
| /* Precomputed pointers when using 16-bit heap pointer packing. */ |
| #if defined(DUK_USE_HEAPPTR16) |
| duk_uint16_t heapptr_null16; |
| duk_uint16_t heapptr_deleted16; |
| #endif |
| |
| /* Fatal error handling, called e.g. when a longjmp() is needed but |
| * lj.jmpbuf_ptr is NULL. fatal_func must never return; it's not |
| * declared as "noreturn" because doing that for typedefs is a bit |
| * challenging portability-wise. |
| */ |
| duk_fatal_function fatal_func; |
| |
| /* allocated heap objects */ |
| duk_heaphdr *heap_allocated; |
| |
| /* work list for objects whose refcounts are zero but which have not been |
| * "finalized"; avoids recursive C calls when refcounts go to zero in a |
| * chain of objects. |
| */ |
| #if defined(DUK_USE_REFERENCE_COUNTING) |
| duk_heaphdr *refzero_list; |
| duk_heaphdr *refzero_list_tail; |
| #endif |
| |
| #if defined(DUK_USE_MARK_AND_SWEEP) |
| /* mark-and-sweep control */ |
| #if defined(DUK_USE_VOLUNTARY_GC) |
| duk_int_t mark_and_sweep_trigger_counter; |
| #endif |
| duk_int_t mark_and_sweep_recursion_depth; |
| |
| /* mark-and-sweep flags automatically active (used for critical sections) */ |
| duk_small_uint_t mark_and_sweep_base_flags; |
| |
| /* work list for objects to be finalized (by mark-and-sweep) */ |
| duk_heaphdr *finalize_list; |
| #endif |
| |
| /* longjmp state */ |
| duk_ljstate lj; |
| |
| /* marker for detecting internal "double faults", see duk_error_throw.c */ |
| duk_bool_t handling_error; |
| |
| /* heap thread, used internally and for finalization */ |
| duk_hthread *heap_thread; |
| |
| /* current thread */ |
| duk_hthread *curr_thread; /* currently running thread */ |
| |
| /* heap level "stash" object (e.g., various reachability roots) */ |
| duk_hobject *heap_object; |
| |
| /* duk_handle_call / duk_handle_safe_call recursion depth limiting */ |
| duk_int_t call_recursion_depth; |
| duk_int_t call_recursion_limit; |
| |
| /* mix-in value for computing string hashes; should be reasonably unpredictable */ |
| duk_uint32_t hash_seed; |
| |
| /* rnd_state for duk_util_tinyrandom.c */ |
| duk_uint32_t rnd_state; |
| |
| /* For manual debugging: instruction count based on executor and |
| * interrupt counter book-keeping. Inspect debug logs to see how |
| * they match up. |
| */ |
| #if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) |
| duk_int_t inst_count_exec; |
| duk_int_t inst_count_interrupt; |
| #endif |
| |
| /* debugger */ |
| |
| #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| /* callbacks and udata; dbg_read_cb != NULL is used to indicate attached state */ |
| duk_debug_read_function dbg_read_cb; /* required, NULL implies detached */ |
| duk_debug_write_function dbg_write_cb; /* required */ |
| duk_debug_peek_function dbg_peek_cb; |
| duk_debug_read_flush_function dbg_read_flush_cb; |
| duk_debug_write_flush_function dbg_write_flush_cb; |
| duk_debug_request_function dbg_request_cb; |
| duk_debug_detached_function dbg_detached_cb; |
| void *dbg_udata; |
| |
| /* debugger state, only relevant when attached */ |
| duk_bool_t dbg_processing; /* currently processing messages or breakpoints: don't enter message processing recursively (e.g. no breakpoints when processing debugger eval) */ |
| duk_bool_t dbg_paused; /* currently paused: talk with debug client until step/resume */ |
| duk_bool_t dbg_state_dirty; /* resend state next time executor is about to run */ |
| duk_bool_t dbg_force_restart; /* force executor restart to recheck breakpoints; used to handle function returns (see GH-303) */ |
| duk_bool_t dbg_detaching; /* debugger detaching; used to avoid calling detach handler recursively */ |
| duk_small_uint_t dbg_step_type; /* step type: none, step into, step over, step out */ |
| duk_hthread *dbg_step_thread; /* borrowed; NULL if no step state (NULLed in unwind) */ |
| duk_size_t dbg_step_csindex; /* callstack index */ |
| duk_uint32_t dbg_step_startline; /* starting line number */ |
| duk_breakpoint dbg_breakpoints[DUK_HEAP_MAX_BREAKPOINTS]; /* breakpoints: [0,breakpoint_count[ gc reachable */ |
| duk_small_uint_t dbg_breakpoint_count; |
| duk_breakpoint *dbg_breakpoints_active[DUK_HEAP_MAX_BREAKPOINTS + 1]; /* currently active breakpoints: NULL term, borrowed pointers */ |
| /* XXX: make active breakpoints actual copies instead of pointers? */ |
| |
| /* These are for rate limiting Status notifications and transport peeking. */ |
| duk_uint32_t dbg_exec_counter; /* cumulative opcode execution count (overflows are OK) */ |
| duk_uint32_t dbg_last_counter; /* value of dbg_exec_counter when we last did a Date-based check */ |
| duk_double_t dbg_last_time; /* time when status/peek was last done (Date-based rate limit) */ |
| |
| /* Used to support single-byte stream lookahead. */ |
| duk_bool_t dbg_have_next_byte; |
| duk_uint8_t dbg_next_byte; |
| #endif |
| |
| /* string intern table (weak refs) */ |
| #if defined(DUK_USE_STRTAB_PROBE) |
| #if defined(DUK_USE_HEAPPTR16) |
| duk_uint16_t *strtable16; |
| #else |
| duk_hstring **strtable; |
| #endif |
| duk_uint32_t st_size; /* alloc size in elements */ |
| duk_uint32_t st_used; /* used elements (includes DELETED) */ |
| #endif |
| |
| /* XXX: static alloc is OK until separate chaining stringtable |
| * resizing is implemented. |
| */ |
| #if defined(DUK_USE_STRTAB_CHAIN) |
| duk_strtab_entry strtable[DUK_STRTAB_CHAIN_SIZE]; |
| #endif |
| |
| /* string access cache (codepoint offset -> byte offset) for fast string |
| * character looping; 'weak' reference which needs special handling in GC. |
| */ |
| duk_strcache strcache[DUK_HEAP_STRCACHE_SIZE]; |
| |
| /* built-in strings */ |
| #if defined(DUK_USE_ROM_STRINGS) |
| /* No field needed when strings are in ROM. */ |
| #else |
| #if defined(DUK_USE_HEAPPTR16) |
| duk_uint16_t strs16[DUK_HEAP_NUM_STRINGS]; |
| #else |
| duk_hstring *strs[DUK_HEAP_NUM_STRINGS]; |
| #endif |
| #endif |
| }; |
| |
| /* |
| * Prototypes |
| */ |
| |
| DUK_INTERNAL_DECL |
| 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_DECL void duk_heap_free(duk_heap *heap); |
| DUK_INTERNAL_DECL void duk_free_hobject_inner(duk_heap *heap, duk_hobject *h); |
| DUK_INTERNAL_DECL void duk_free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h); |
| DUK_INTERNAL_DECL void duk_free_hstring_inner(duk_heap *heap, duk_hstring *h); |
| DUK_INTERNAL_DECL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr); |
| |
| DUK_INTERNAL_DECL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr); |
| #if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING) |
| DUK_INTERNAL_DECL void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr); |
| #endif |
| #if defined(DUK_USE_INTERRUPT_COUNTER) |
| DUK_INTERNAL_DECL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr); |
| #endif |
| |
| #if 0 /*unused*/ |
| DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen); |
| #endif |
| DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen); |
| DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len); |
| #if 0 /*unused*/ |
| DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val); |
| #endif |
| DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val); |
| DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val); |
| #if defined(DUK_USE_REFERENCE_COUNTING) |
| DUK_INTERNAL_DECL void duk_heap_string_remove(duk_heap *heap, duk_hstring *h); |
| #endif |
| #if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_MS_STRINGTABLE_RESIZE) |
| DUK_INTERNAL_DECL void duk_heap_force_strtab_resize(duk_heap *heap); |
| #endif |
| DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap); |
| #if defined(DUK_USE_DEBUG) |
| DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap); |
| #endif |
| |
| |
| DUK_INTERNAL_DECL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h); |
| DUK_INTERNAL_DECL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset); |
| |
| #if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS) |
| DUK_INTERNAL_DECL void *duk_default_alloc_function(void *udata, duk_size_t size); |
| DUK_INTERNAL_DECL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize); |
| DUK_INTERNAL_DECL void duk_default_free_function(void *udata, void *ptr); |
| #endif |
| |
| DUK_INTERNAL_DECL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size); |
| DUK_INTERNAL_DECL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size); |
| DUK_INTERNAL_DECL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize); |
| DUK_INTERNAL_DECL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize); |
| DUK_INTERNAL_DECL void duk_heap_mem_free(duk_heap *heap, void *ptr); |
| |
| #ifdef DUK_USE_REFERENCE_COUNTING |
| #if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT) |
| DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv); |
| #endif |
| #if 0 /* unused */ |
| DUK_INTERNAL_DECL void duk_tval_incref_allownull(duk_tval *tv); |
| #endif |
| DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv); |
| #if 0 /* unused */ |
| DUK_INTERNAL_DECL void duk_tval_decref_allownull(duk_hthread *thr, duk_tval *tv); |
| #endif |
| #if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT) |
| DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h); |
| #endif |
| #if 0 /* unused */ |
| DUK_INTERNAL_DECL void duk_heaphdr_incref_allownull(duk_heaphdr *h); |
| #endif |
| DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h); |
| DUK_INTERNAL_DECL void duk_heaphdr_decref_allownull(duk_hthread *thr, duk_heaphdr *h); |
| DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h); |
| DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr); |
| #else |
| /* no refcounting */ |
| #endif |
| |
| #if defined(DUK_USE_MARK_AND_SWEEP) |
| DUK_INTERNAL_DECL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags); |
| #endif |
| |
| DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len); |
| |
| #endif /* DUK_HEAP_H_INCLUDED */ |