http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b8103f03/thirdparty/civetweb-1.9.1/src/third_party/duktape-1.5.2/src-separate/duk_heap_hashstring.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.9.1/src/third_party/duktape-1.5.2/src-separate/duk_heap_hashstring.c b/thirdparty/civetweb-1.9.1/src/third_party/duktape-1.5.2/src-separate/duk_heap_hashstring.c deleted file mode 100644 index 5cad795..0000000 --- a/thirdparty/civetweb-1.9.1/src/third_party/duktape-1.5.2/src-separate/duk_heap_hashstring.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * String hash computation (interning). - * - * String hashing is performance critical because a string hash is computed - * for all new strings which are candidates to be added to the string table. - * However, strings actually added to the string table go through a codepoint - * length calculation which dominates performance because it goes through - * every byte of the input string (but only for strings added). - * - * The string hash algorithm should be fast, but on the other hand provide - * good enough hashes to ensure both string table and object property table - * hash tables work reasonably well (i.e., there aren't too many collisions - * with real world inputs). Unless the hash is cryptographic, it's always - * possible to craft inputs with maximal hash collisions. - * - * NOTE: The hash algorithms must match src/dukutil.py:duk_heap_hashstring() - * for ROM string support! - */ - -#include "duk_internal.h" - -#if defined(DUK_USE_STRHASH_DENSE) -/* Constants for duk_hashstring(). */ -#define DUK__STRHASH_SHORTSTRING 4096L -#define DUK__STRHASH_MEDIUMSTRING (256L * 1024L) -#define DUK__STRHASH_BLOCKSIZE 256L - -DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) { - duk_uint32_t hash; - - /* Use Murmurhash2 directly for short strings, and use "block skipping" - * for long strings: hash an initial part and then sample the rest of - * the string with reasonably sized chunks. An initial offset for the - * sampling is computed based on a hash of the initial part of the string; - * this is done to (usually) avoid the case where all long strings have - * certain offset ranges which are never sampled. - * - * Skip should depend on length and bound the total time to roughly - * logarithmic. With current values: - * - * 1M string => 256 * 241 = 61696 bytes (0.06M) of hashing - * 1G string => 256 * 16321 = 4178176 bytes (3.98M) of hashing - * - * XXX: It would be better to compute the skip offset more "smoothly" - * instead of having a few boundary values. - */ - - /* note: mixing len into seed improves hashing when skipping */ - duk_uint32_t str_seed = heap->hash_seed ^ ((duk_uint32_t) len); - - if (len <= DUK__STRHASH_SHORTSTRING) { - hash = duk_util_hashbytes(str, len, str_seed); - } else { - duk_size_t off; - duk_size_t skip; - - if (len <= DUK__STRHASH_MEDIUMSTRING) { - skip = (duk_size_t) (16 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE); - } else { - skip = (duk_size_t) (256 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE); - } - - hash = duk_util_hashbytes(str, (duk_size_t) DUK__STRHASH_SHORTSTRING, str_seed); - off = DUK__STRHASH_SHORTSTRING + (skip * (hash % 256)) / 256; - - /* XXX: inefficient loop */ - while (off < len) { - duk_size_t left = len - off; - duk_size_t now = (duk_size_t) (left > DUK__STRHASH_BLOCKSIZE ? DUK__STRHASH_BLOCKSIZE : left); - hash ^= duk_util_hashbytes(str + off, now, str_seed); - off += skip; - } - } - -#if defined(DUK_USE_STRHASH16) - /* Truncate to 16 bits here, so that a computed hash can be compared - * against a hash stored in a 16-bit field. - */ - hash &= 0x0000ffffUL; -#endif - return hash; -} - -#undef DUK__STRHASH_SHORTSTRING -#undef DUK__STRHASH_MEDIUMSTRING -#undef DUK__STRHASH_BLOCKSIZE -#else /* DUK_USE_STRHASH_DENSE */ -DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) { - duk_uint32_t hash; - duk_size_t step; - duk_size_t off; - - /* Slightly modified "Bernstein hash" from: - * - * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx - * - * Modifications: string skipping and reverse direction similar to - * Lua 5.1.5, and different hash initializer. - * - * The reverse direction ensures last byte it always included in the - * hash which is a good default as changing parts of the string are - * more often in the suffix than in the prefix. - */ - - hash = heap->hash_seed ^ ((duk_uint32_t) len); /* Bernstein hash init value is normally 5381 */ - step = (len >> DUK_USE_STRHASH_SKIP_SHIFT) + 1; - for (off = len; off >= step; off -= step) { - DUK_ASSERT(off >= 1); /* off >= step, and step >= 1 */ - hash = (hash * 33) + str[off - 1]; - } - -#if defined(DUK_USE_STRHASH16) - /* Truncate to 16 bits here, so that a computed hash can be compared - * against a hash stored in a 16-bit field. - */ - hash &= 0x0000ffffUL; -#endif - return hash; -} -#endif /* DUK_USE_STRHASH_DENSE */
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b8103f03/thirdparty/civetweb-1.9.1/src/third_party/duktape-1.5.2/src-separate/duk_heap_markandsweep.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.9.1/src/third_party/duktape-1.5.2/src-separate/duk_heap_markandsweep.c b/thirdparty/civetweb-1.9.1/src/third_party/duktape-1.5.2/src-separate/duk_heap_markandsweep.c deleted file mode 100644 index fa7b553..0000000 --- a/thirdparty/civetweb-1.9.1/src/third_party/duktape-1.5.2/src-separate/duk_heap_markandsweep.c +++ /dev/null @@ -1,1421 +0,0 @@ -/* - * Mark-and-sweep garbage collection. - */ - -#include "duk_internal.h" - -#ifdef DUK_USE_MARK_AND_SWEEP - -DUK_LOCAL_DECL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h); -DUK_LOCAL_DECL void duk__mark_tval(duk_heap *heap, duk_tval *tv); - -/* - * Misc - */ - -/* Select a thread for mark-and-sweep use. - * - * XXX: This needs to change later. - */ -DUK_LOCAL duk_hthread *duk__get_temp_hthread(duk_heap *heap) { - if (heap->curr_thread) { - return heap->curr_thread; - } - return heap->heap_thread; /* may be NULL, too */ -} - -/* - * Marking functions for heap types: mark children recursively - */ - -DUK_LOCAL void duk__mark_hstring(duk_heap *heap, duk_hstring *h) { - DUK_UNREF(heap); - DUK_UNREF(h); - - DUK_DDD(DUK_DDDPRINT("duk__mark_hstring: %p", (void *) h)); - DUK_ASSERT(h); - - /* nothing to process */ -} - -DUK_LOCAL void duk__mark_hobject(duk_heap *heap, duk_hobject *h) { - duk_uint_fast32_t i; - - DUK_DDD(DUK_DDDPRINT("duk__mark_hobject: %p", (void *) h)); - - DUK_ASSERT(h); - - /* XXX: use advancing pointers instead of index macros -> faster and smaller? */ - - for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) { - duk_hstring *key = DUK_HOBJECT_E_GET_KEY(heap, h, i); - if (!key) { - continue; - } - duk__mark_heaphdr(heap, (duk_heaphdr *) key); - if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) { - duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get); - duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set); - } else { - duk__mark_tval(heap, &DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->v); - } - } - - for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) { - duk__mark_tval(heap, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i)); - } - - /* hash part is a 'weak reference' and does not contribute */ - - duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h)); - - if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) { - duk_hcompiledfunction *f = (duk_hcompiledfunction *) h; - duk_tval *tv, *tv_end; - duk_hobject **fn, **fn_end; - - /* 'data' is reachable through every compiled function which - * contains a reference. - */ - - duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPILEDFUNCTION_GET_DATA(heap, f)); - - if (DUK_HCOMPILEDFUNCTION_GET_DATA(heap, f) != NULL) { - tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap, f); - tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(heap, f); - while (tv < tv_end) { - duk__mark_tval(heap, tv); - tv++; - } - - fn = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap, f); - fn_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(heap, f); - while (fn < fn_end) { - duk__mark_heaphdr(heap, (duk_heaphdr *) *fn); - fn++; - } - } else { - /* May happen in some out-of-memory corner cases. */ - DUK_D(DUK_DPRINT("duk_hcompiledfunction 'data' is NULL, skipping marking")); - } - } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) { - duk_hnativefunction *f = (duk_hnativefunction *) h; - DUK_UNREF(f); - /* nothing to mark */ - } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) { - duk_hbufferobject *b = (duk_hbufferobject *) h; - duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf); - } else if (DUK_HOBJECT_IS_THREAD(h)) { - duk_hthread *t = (duk_hthread *) h; - duk_tval *tv; - - tv = t->valstack; - while (tv < t->valstack_top) { - duk__mark_tval(heap, tv); - tv++; - } - - for (i = 0; i < (duk_uint_fast32_t) t->callstack_top; i++) { - duk_activation *act = t->callstack + i; - duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_ACT_GET_FUNC(act)); - duk__mark_heaphdr(heap, (duk_heaphdr *) act->var_env); - duk__mark_heaphdr(heap, (duk_heaphdr *) act->lex_env); -#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY - duk__mark_heaphdr(heap, (duk_heaphdr *) act->prev_caller); -#endif - } - -#if 0 /* nothing now */ - for (i = 0; i < (duk_uint_fast32_t) t->catchstack_top; i++) { - duk_catcher *cat = t->catchstack + i; - } -#endif - - duk__mark_heaphdr(heap, (duk_heaphdr *) t->resumer); - - /* XXX: duk_small_uint_t would be enough for this loop */ - for (i = 0; i < DUK_NUM_BUILTINS; i++) { - duk__mark_heaphdr(heap, (duk_heaphdr *) t->builtins[i]); - } - } -} - -/* recursion tracking happens here only */ -DUK_LOCAL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h) { - DUK_DDD(DUK_DDDPRINT("duk__mark_heaphdr %p, type %ld", - (void *) h, - (h != NULL ? (long) DUK_HEAPHDR_GET_TYPE(h) : (long) -1))); - if (!h) { - return; - } -#if defined(DUK_USE_ROM_OBJECTS) - if (DUK_HEAPHDR_HAS_READONLY(h)) { - DUK_DDD(DUK_DDDPRINT("readonly object %p, skip", (void *) h)); - return; - } -#endif - if (DUK_HEAPHDR_HAS_REACHABLE(h)) { - DUK_DDD(DUK_DDDPRINT("already marked reachable, skip")); - return; - } - DUK_HEAPHDR_SET_REACHABLE(h); - - if (heap->mark_and_sweep_recursion_depth >= DUK_USE_MARK_AND_SWEEP_RECLIMIT) { - /* log this with a normal debug level because this should be relatively rare */ - DUK_D(DUK_DPRINT("mark-and-sweep recursion limit reached, marking as temproot: %p", (void *) h)); - DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap); - DUK_HEAPHDR_SET_TEMPROOT(h); - return; - } - - heap->mark_and_sweep_recursion_depth++; - - switch ((int) DUK_HEAPHDR_GET_TYPE(h)) { - case DUK_HTYPE_STRING: - duk__mark_hstring(heap, (duk_hstring *) h); - break; - case DUK_HTYPE_OBJECT: - duk__mark_hobject(heap, (duk_hobject *) h); - break; - case DUK_HTYPE_BUFFER: - /* nothing to mark */ - break; - default: - DUK_D(DUK_DPRINT("attempt to mark heaphdr %p with invalid htype %ld", (void *) h, (long) DUK_HEAPHDR_GET_TYPE(h))); - DUK_UNREACHABLE(); - } - - heap->mark_and_sweep_recursion_depth--; -} - -DUK_LOCAL void duk__mark_tval(duk_heap *heap, duk_tval *tv) { - DUK_DDD(DUK_DDDPRINT("duk__mark_tval %p", (void *) tv)); - if (!tv) { - return; - } - if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { - duk__mark_heaphdr(heap, DUK_TVAL_GET_HEAPHDR(tv)); - } -} - -/* - * Mark the heap. - */ - -DUK_LOCAL void duk__mark_roots_heap(duk_heap *heap) { - duk_small_uint_t i; - - DUK_DD(DUK_DDPRINT("duk__mark_roots_heap: %p", (void *) heap)); - - duk__mark_heaphdr(heap, (duk_heaphdr *) heap->heap_thread); - duk__mark_heaphdr(heap, (duk_heaphdr *) heap->heap_object); - - for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) { - duk_hstring *h = DUK_HEAP_GET_STRING(heap, i); - duk__mark_heaphdr(heap, (duk_heaphdr *) h); - } - - duk__mark_tval(heap, &heap->lj.value1); - duk__mark_tval(heap, &heap->lj.value2); - -#if defined(DUK_USE_DEBUGGER_SUPPORT) - for (i = 0; i < heap->dbg_breakpoint_count; i++) { - duk__mark_heaphdr(heap, (duk_heaphdr *) heap->dbg_breakpoints[i].filename); - } -#endif -} - -/* - * Mark refzero_list objects. - * - * Objects on the refzero_list have no inbound references. They might have - * outbound references to objects that we might free, which would invalidate - * any references held by the refzero objects. A refzero object might also - * be rescued by refcount finalization. Refzero objects are treated as - * reachability roots to ensure they (or anything they point to) are not - * freed in mark-and-sweep. - */ - -#ifdef DUK_USE_REFERENCE_COUNTING -DUK_LOCAL void duk__mark_refzero_list(duk_heap *heap) { - duk_heaphdr *hdr; - - DUK_DD(DUK_DDPRINT("duk__mark_refzero_list: %p", (void *) heap)); - - hdr = heap->refzero_list; - while (hdr) { - duk__mark_heaphdr(heap, hdr); - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -} -#endif - -/* - * Mark unreachable, finalizable objects. - * - * Such objects will be moved aside and their finalizers run later. They have - * to be treated as reachability roots for their properties etc to remain - * allocated. This marking is only done for unreachable values which would - * be swept later (refzero_list is thus excluded). - * - * Objects are first marked FINALIZABLE and only then marked as reachability - * roots; otherwise circular references might be handled inconsistently. - */ - -DUK_LOCAL void duk__mark_finalizable(duk_heap *heap) { - duk_hthread *thr; - duk_heaphdr *hdr; - duk_size_t count_finalizable = 0; - - DUK_DD(DUK_DDPRINT("duk__mark_finalizable: %p", (void *) heap)); - - thr = duk__get_temp_hthread(heap); - DUK_ASSERT(thr != NULL); - - hdr = heap->heap_allocated; - while (hdr) { - /* A finalizer is looked up from the object and up its prototype chain - * (which allows inherited finalizers). A prototype loop must not cause - * an error to be thrown here; duk_hobject_hasprop_raw() will ignore a - * prototype loop silently and indicate that the property doesn't exist. - */ - - if (!DUK_HEAPHDR_HAS_REACHABLE(hdr) && - DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_OBJECT && - !DUK_HEAPHDR_HAS_FINALIZED(hdr) && - duk_hobject_hasprop_raw(thr, (duk_hobject *) hdr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) { - - /* heaphdr: - * - is not reachable - * - is an object - * - is not a finalized object - * - has a finalizer - */ - - DUK_DD(DUK_DDPRINT("unreachable heap object will be " - "finalized -> mark as finalizable " - "and treat as a reachability root: %p", - (void *) hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr)); - DUK_HEAPHDR_SET_FINALIZABLE(hdr); - count_finalizable ++; - } - - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } - - if (count_finalizable == 0) { - return; - } - - DUK_DD(DUK_DDPRINT("marked %ld heap objects as finalizable, now mark them reachable", - (long) count_finalizable)); - - hdr = heap->heap_allocated; - while (hdr) { - if (DUK_HEAPHDR_HAS_FINALIZABLE(hdr)) { - duk__mark_heaphdr(heap, hdr); - } - - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } - - /* Caller will finish the marking process if we hit a recursion limit. */ -} - -/* - * Mark objects on finalize_list. - * - */ - -DUK_LOCAL void duk__mark_finalize_list(duk_heap *heap) { - duk_heaphdr *hdr; -#ifdef DUK_USE_DEBUG - duk_size_t count_finalize_list = 0; -#endif - - DUK_DD(DUK_DDPRINT("duk__mark_finalize_list: %p", (void *) heap)); - - hdr = heap->finalize_list; - while (hdr) { - duk__mark_heaphdr(heap, hdr); - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); -#ifdef DUK_USE_DEBUG - count_finalize_list++; -#endif - } - -#ifdef DUK_USE_DEBUG - if (count_finalize_list > 0) { - DUK_D(DUK_DPRINT("marked %ld objects on the finalize_list as reachable (previous finalizer run skipped)", - (long) count_finalize_list)); - } -#endif -} - -/* - * Fallback marking handler if recursion limit is reached. - * - * Iterates 'temproots' until recursion limit is no longer hit. Note - * that temproots may reside either in heap allocated list or the - * refzero work list. This is a slow scan, but guarantees that we - * finish with a bounded C stack. - * - * Note that nodes may have been marked as temproots before this - * scan begun, OR they may have been marked during the scan (as - * we process nodes recursively also during the scan). This is - * intended behavior. - */ - -#ifdef DUK_USE_DEBUG -DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr, duk_size_t *count) { -#else -DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr) { -#endif - if (!DUK_HEAPHDR_HAS_TEMPROOT(hdr)) { - DUK_DDD(DUK_DDDPRINT("not a temp root: %p", (void *) hdr)); - return; - } - - DUK_DDD(DUK_DDDPRINT("found a temp root: %p", (void *) hdr)); - DUK_HEAPHDR_CLEAR_TEMPROOT(hdr); - DUK_HEAPHDR_CLEAR_REACHABLE(hdr); /* done so that duk__mark_heaphdr() works correctly */ - duk__mark_heaphdr(heap, hdr); - -#ifdef DUK_USE_DEBUG - (*count)++; -#endif -} - -DUK_LOCAL void duk__mark_temproots_by_heap_scan(duk_heap *heap) { - duk_heaphdr *hdr; -#ifdef DUK_USE_DEBUG - duk_size_t count; -#endif - - DUK_DD(DUK_DDPRINT("duk__mark_temproots_by_heap_scan: %p", (void *) heap)); - - while (DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)) { - DUK_DD(DUK_DDPRINT("recursion limit reached, doing heap scan to continue from temproots")); - -#ifdef DUK_USE_DEBUG - count = 0; -#endif - DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap); - - hdr = heap->heap_allocated; - while (hdr) { -#ifdef DUK_USE_DEBUG - duk__handle_temproot(heap, hdr, &count); -#else - duk__handle_temproot(heap, hdr); -#endif - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } - - /* must also check refzero_list */ -#ifdef DUK_USE_REFERENCE_COUNTING - hdr = heap->refzero_list; - while (hdr) { -#ifdef DUK_USE_DEBUG - duk__handle_temproot(heap, hdr, &count); -#else - duk__handle_temproot(heap, hdr); -#endif - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -#endif /* DUK_USE_REFERENCE_COUNTING */ - -#ifdef DUK_USE_DEBUG - DUK_DD(DUK_DDPRINT("temproot mark heap scan processed %ld temp roots", (long) count)); -#endif - } -} - -/* - * Finalize refcounts for heap elements just about to be freed. - * This must be done for all objects before freeing to avoid any - * stale pointer dereferences. - * - * Note that this must deduce the set of objects to be freed - * identically to duk__sweep_heap(). - */ - -#ifdef DUK_USE_REFERENCE_COUNTING -DUK_LOCAL void duk__finalize_refcounts(duk_heap *heap) { - duk_hthread *thr; - duk_heaphdr *hdr; - - thr = duk__get_temp_hthread(heap); - DUK_ASSERT(thr != NULL); - - DUK_DD(DUK_DDPRINT("duk__finalize_refcounts: heap=%p, hthread=%p", - (void *) heap, (void *) thr)); - - hdr = heap->heap_allocated; - while (hdr) { - if (!DUK_HEAPHDR_HAS_REACHABLE(hdr)) { - /* - * Unreachable object about to be swept. Finalize target refcounts - * (objects which the unreachable object points to) without doing - * refzero processing. Recursive decrefs are also prevented when - * refzero processing is disabled. - * - * Value cannot be a finalizable object, as they have been made - * temporarily reachable for this round. - */ - - DUK_DDD(DUK_DDDPRINT("unreachable object, refcount finalize before sweeping: %p", (void *) hdr)); - duk_heaphdr_refcount_finalize(thr, hdr); - } - - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -} -#endif /* DUK_USE_REFERENCE_COUNTING */ - -/* - * Clear (reachable) flags of refzero work list. - */ - -#ifdef DUK_USE_REFERENCE_COUNTING -DUK_LOCAL void duk__clear_refzero_list_flags(duk_heap *heap) { - duk_heaphdr *hdr; - - DUK_DD(DUK_DDPRINT("duk__clear_refzero_list_flags: %p", (void *) heap)); - - hdr = heap->refzero_list; - while (hdr) { - DUK_HEAPHDR_CLEAR_REACHABLE(hdr); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr)); - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -} -#endif /* DUK_USE_REFERENCE_COUNTING */ - -/* - * Clear (reachable) flags of finalize_list - * - * We could mostly do in the sweep phase when we move objects from the - * heap into the finalize_list. However, if a finalizer run is skipped - * during a mark-and-sweep, the objects on the finalize_list will be marked - * reachable during the next mark-and-sweep. Since they're already on the - * finalize_list, no-one will be clearing their REACHABLE flag so we do it - * here. (This now overlaps with the sweep handling in a harmless way.) - */ - -DUK_LOCAL void duk__clear_finalize_list_flags(duk_heap *heap) { - duk_heaphdr *hdr; - - DUK_DD(DUK_DDPRINT("duk__clear_finalize_list_flags: %p", (void *) heap)); - - hdr = heap->finalize_list; - while (hdr) { - DUK_HEAPHDR_CLEAR_REACHABLE(hdr); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr)); - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -} - -/* - * Sweep stringtable - */ - -#if defined(DUK_USE_STRTAB_CHAIN) - -/* XXX: skip count_free w/o debug? */ -#if defined(DUK_USE_HEAPPTR16) -DUK_LOCAL void duk__sweep_string_chain16(duk_heap *heap, duk_uint16_t *slot, duk_size_t *count_keep, duk_size_t *count_free) { - duk_uint16_t h16 = *slot; - duk_hstring *h; - duk_uint16_t null16 = heap->heapptr_null16; - - if (h16 == null16) { - /* nop */ - return; - } - h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, h16); - DUK_ASSERT(h != NULL); - - if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { - DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); - (*count_keep)++; - } else { -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); -#endif - /* deal with weak references first */ - duk_heap_strcache_string_remove(heap, (duk_hstring *) h); - *slot = null16; - - /* free inner references (these exist e.g. when external - * strings are enabled) - */ - duk_free_hstring_inner(heap, h); - DUK_FREE(heap, h); - (*count_free)++; - } -} -#else /* DUK_USE_HEAPPTR16 */ -DUK_LOCAL void duk__sweep_string_chain(duk_heap *heap, duk_hstring **slot, duk_size_t *count_keep, duk_size_t *count_free) { - duk_hstring *h = *slot; - - if (h == NULL) { - /* nop */ - return; - } - - if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { - DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); - (*count_keep)++; - } else { -#if defined(DUK_USE_REFERENCE_COUNTING) - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); -#endif - /* deal with weak references first */ - duk_heap_strcache_string_remove(heap, (duk_hstring *) h); - *slot = NULL; - - /* free inner references (these exist e.g. when external - * strings are enabled) - */ - duk_free_hstring_inner(heap, h); - DUK_FREE(heap, h); - (*count_free)++; - } -} -#endif /* DUK_USE_HEAPPTR16 */ - -DUK_LOCAL void duk__sweep_stringtable_chain(duk_heap *heap, duk_size_t *out_count_keep) { - duk_strtab_entry *e; - duk_uint_fast32_t i; - duk_size_t count_free = 0; - duk_size_t count_keep = 0; - duk_size_t j, n; -#if defined(DUK_USE_HEAPPTR16) - duk_uint16_t *lst; -#else - duk_hstring **lst; -#endif - - DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap)); - - /* Non-zero refcounts should not happen for unreachable strings, - * because we refcount finalize all unreachable objects which - * should have decreased unreachable string refcounts to zero - * (even for cycles). - */ - - for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { - e = heap->strtable + i; - if (e->listlen == 0) { -#if defined(DUK_USE_HEAPPTR16) - duk__sweep_string_chain16(heap, &e->u.str16, &count_keep, &count_free); -#else - duk__sweep_string_chain(heap, &e->u.str, &count_keep, &count_free); -#endif - } else { -#if defined(DUK_USE_HEAPPTR16) - lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16); -#else - lst = e->u.strlist; -#endif - for (j = 0, n = e->listlen; j < n; j++) { -#if defined(DUK_USE_HEAPPTR16) - duk__sweep_string_chain16(heap, lst + j, &count_keep, &count_free); -#else - duk__sweep_string_chain(heap, lst + j, &count_keep, &count_free); -#endif - } - } - } - - DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept", - (long) count_free, (long) count_keep)); - *out_count_keep = count_keep; -} -#endif /* DUK_USE_STRTAB_CHAIN */ - -#if defined(DUK_USE_STRTAB_PROBE) -DUK_LOCAL void duk__sweep_stringtable_probe(duk_heap *heap, duk_size_t *out_count_keep) { - duk_hstring *h; - duk_uint_fast32_t i; -#ifdef DUK_USE_DEBUG - duk_size_t count_free = 0; -#endif - duk_size_t count_keep = 0; - - DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap)); - - for (i = 0; i < heap->st_size; i++) { -#if defined(DUK_USE_HEAPPTR16) - h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); -#else - h = heap->strtable[i]; -#endif - if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) { - continue; - } else if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) { - DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); - count_keep++; - continue; - } - -#ifdef DUK_USE_DEBUG - count_free++; -#endif - -#if defined(DUK_USE_REFERENCE_COUNTING) - /* Non-zero refcounts should not happen for unreachable strings, - * because we refcount finalize all unreachable objects which - * should have decreased unreachable string refcounts to zero - * (even for cycles). - */ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0); -#endif - - DUK_DDD(DUK_DDDPRINT("sweep string, not reachable: %p", (void *) h)); - - /* deal with weak references first */ - duk_heap_strcache_string_remove(heap, (duk_hstring *) h); - - /* remove the string (mark DELETED), could also call - * duk_heap_string_remove() but that would be slow and - * pointless because we already know the slot. - */ -#if defined(DUK_USE_HEAPPTR16) - heap->strtable16[i] = heap->heapptr_deleted16; -#else - heap->strtable[i] = DUK_STRTAB_DELETED_MARKER(heap); -#endif - - /* free inner references (these exist e.g. when external - * strings are enabled) - */ - duk_free_hstring_inner(heap, (duk_hstring *) h); - - /* finally free the struct itself */ - DUK_FREE(heap, h); - } - -#ifdef DUK_USE_DEBUG - DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept", - (long) count_free, (long) count_keep)); -#endif - *out_count_keep = count_keep; -} -#endif /* DUK_USE_STRTAB_PROBE */ - -/* - * Sweep heap - */ - -DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_count_keep) { - duk_heaphdr *prev; /* last element that was left in the heap */ - duk_heaphdr *curr; - duk_heaphdr *next; -#ifdef DUK_USE_DEBUG - duk_size_t count_free = 0; - duk_size_t count_finalize = 0; - duk_size_t count_rescue = 0; -#endif - duk_size_t count_keep = 0; - - DUK_UNREF(flags); - DUK_DD(DUK_DDPRINT("duk__sweep_heap: %p", (void *) heap)); - - prev = NULL; - curr = heap->heap_allocated; - heap->heap_allocated = NULL; - while (curr) { - /* Strings and ROM objects are never placed on the heap allocated list. */ - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_STRING); - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr)); - - next = DUK_HEAPHDR_GET_NEXT(heap, curr); - - if (DUK_HEAPHDR_HAS_REACHABLE(curr)) { - /* - * Reachable object, keep - */ - - DUK_DDD(DUK_DDDPRINT("sweep, reachable: %p", (void *) curr)); - - if (DUK_HEAPHDR_HAS_FINALIZABLE(curr)) { - /* - * If object has been marked finalizable, move it to the - * "to be finalized" work list. It will be collected on - * the next mark-and-sweep if it is still unreachable - * after running the finalizer. - */ - - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); - DUK_DDD(DUK_DDDPRINT("object has finalizer, move to finalization work list: %p", (void *) curr)); - -#ifdef DUK_USE_DOUBLE_LINKED_HEAP - if (heap->finalize_list) { - DUK_HEAPHDR_SET_PREV(heap, heap->finalize_list, curr); - } - DUK_HEAPHDR_SET_PREV(heap, curr, NULL); -#endif - DUK_HEAPHDR_SET_NEXT(heap, curr, heap->finalize_list); - DUK_ASSERT_HEAPHDR_LINKS(heap, curr); - heap->finalize_list = curr; -#ifdef DUK_USE_DEBUG - count_finalize++; -#endif - } else { - /* - * Object will be kept; queue object back to heap_allocated (to tail) - */ - - if (DUK_HEAPHDR_HAS_FINALIZED(curr)) { - /* - * Object's finalizer was executed on last round, and - * object has been happily rescued. - */ - - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); - DUK_DD(DUK_DDPRINT("object rescued during mark-and-sweep finalization: %p", (void *) curr)); -#ifdef DUK_USE_DEBUG - count_rescue++; -#endif - } else { - /* - * Plain, boring reachable object. - */ - DUK_DD(DUK_DDPRINT("keep object: %!iO", curr)); - count_keep++; - } - - if (!heap->heap_allocated) { - heap->heap_allocated = curr; - } - if (prev) { - DUK_HEAPHDR_SET_NEXT(heap, prev, curr); - } -#ifdef DUK_USE_DOUBLE_LINKED_HEAP - DUK_HEAPHDR_SET_PREV(heap, curr, prev); -#endif - DUK_ASSERT_HEAPHDR_LINKS(heap, prev); - DUK_ASSERT_HEAPHDR_LINKS(heap, curr); - prev = curr; - } - - DUK_HEAPHDR_CLEAR_REACHABLE(curr); - DUK_HEAPHDR_CLEAR_FINALIZED(curr); - DUK_HEAPHDR_CLEAR_FINALIZABLE(curr); - - DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); - - curr = next; - } else { - /* - * Unreachable object, free - */ - - DUK_DDD(DUK_DDDPRINT("sweep, not reachable: %p", (void *) curr)); - -#if defined(DUK_USE_REFERENCE_COUNTING) - /* Non-zero refcounts should not happen because we refcount - * finalize all unreachable objects which should cancel out - * refcounts (even for cycles). - */ - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) == 0); -#endif - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); - - if (DUK_HEAPHDR_HAS_FINALIZED(curr)) { - DUK_DDD(DUK_DDDPRINT("finalized object not rescued: %p", (void *) curr)); - } - - /* Note: object cannot be a finalizable unreachable object, as - * they have been marked temporarily reachable for this round, - * and are handled above. - */ - -#ifdef DUK_USE_DEBUG - count_free++; -#endif - - /* weak refs should be handled here, but no weak refs for - * any non-string objects exist right now. - */ - - /* free object and all auxiliary (non-heap) allocs */ - duk_heap_free_heaphdr_raw(heap, curr); - - curr = next; - } - } - if (prev) { - DUK_HEAPHDR_SET_NEXT(heap, prev, NULL); - } - DUK_ASSERT_HEAPHDR_LINKS(heap, prev); - -#ifdef DUK_USE_DEBUG - DUK_D(DUK_DPRINT("mark-and-sweep sweep objects (non-string): %ld freed, %ld kept, %ld rescued, %ld queued for finalization", - (long) count_free, (long) count_keep, (long) count_rescue, (long) count_finalize)); -#endif - *out_count_keep = count_keep; -} - -/* - * Run (object) finalizers in the "to be finalized" work list. - */ - -DUK_LOCAL void duk__run_object_finalizers(duk_heap *heap, duk_small_uint_t flags) { - duk_heaphdr *curr; - duk_heaphdr *next; -#ifdef DUK_USE_DEBUG - duk_size_t count = 0; -#endif - duk_hthread *thr; - - DUK_DD(DUK_DDPRINT("duk__run_object_finalizers: %p", (void *) heap)); - - thr = duk__get_temp_hthread(heap); - DUK_ASSERT(thr != NULL); - - curr = heap->finalize_list; - while (curr) { - DUK_DDD(DUK_DDDPRINT("mark-and-sweep finalize: %p", (void *) curr)); - - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* only objects have finalizers */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr)); /* flags have been already cleared */ - DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr)); /* No finalizers for ROM objects */ - - if (DUK_LIKELY((flags & DUK_MS_FLAG_SKIP_FINALIZERS) == 0)) { - /* Run the finalizer, duk_hobject_run_finalizer() sets FINALIZED. - * Next mark-and-sweep will collect the object unless it has - * become reachable (i.e. rescued). FINALIZED prevents the - * finalizer from being executed again before that. - */ - duk_hobject_run_finalizer(thr, (duk_hobject *) curr); /* must never longjmp */ - DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(curr)); - } else { - /* Used during heap destruction: don't actually run finalizers - * because we're heading into forced finalization. Instead, - * queue finalizable objects back to the heap_allocated list. - */ - DUK_D(DUK_DPRINT("skip finalizers flag set, queue object to heap_allocated without finalizing")); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); - } - - /* queue back to heap_allocated */ - next = DUK_HEAPHDR_GET_NEXT(heap, curr); - DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr); - - curr = next; -#ifdef DUK_USE_DEBUG - count++; -#endif - } - - /* finalize_list will always be processed completely */ - heap->finalize_list = NULL; - -#ifdef DUK_USE_DEBUG - DUK_D(DUK_DPRINT("mark-and-sweep finalize objects: %ld finalizers called", (long) count)); -#endif -} - -/* - * Object compaction. - * - * Compaction is assumed to never throw an error. - */ - -DUK_LOCAL int duk__protected_compact_object(duk_context *ctx) { - /* XXX: for threads, compact value stack, call stack, catch stack? */ - - duk_hobject *obj = duk_get_hobject(ctx, -1); - DUK_ASSERT(obj != NULL); - duk_hobject_compact_props((duk_hthread *) ctx, obj); - return 0; -} - -#ifdef DUK_USE_DEBUG -DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start, duk_size_t *p_count_check, duk_size_t *p_count_compact, duk_size_t *p_count_bytes_saved) { -#else -DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start) { -#endif - duk_heaphdr *curr; -#ifdef DUK_USE_DEBUG - duk_size_t old_size, new_size; -#endif - duk_hobject *obj; - - DUK_UNREF(heap); - - curr = start; - while (curr) { - DUK_DDD(DUK_DDDPRINT("mark-and-sweep compact: %p", (void *) curr)); - - if (DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_OBJECT) { - goto next; - } - obj = (duk_hobject *) curr; - -#ifdef DUK_USE_DEBUG - old_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj), - DUK_HOBJECT_GET_ASIZE(obj), - DUK_HOBJECT_GET_HSIZE(obj)); -#endif - - DUK_DD(DUK_DDPRINT("compact object: %p", (void *) obj)); - duk_push_hobject((duk_context *) thr, obj); - /* XXX: disable error handlers for duration of compaction? */ - duk_safe_call((duk_context *) thr, duk__protected_compact_object, 1, 0); - -#ifdef DUK_USE_DEBUG - new_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj), - DUK_HOBJECT_GET_ASIZE(obj), - DUK_HOBJECT_GET_HSIZE(obj)); -#endif - -#ifdef DUK_USE_DEBUG - (*p_count_compact)++; - (*p_count_bytes_saved) += (duk_size_t) (old_size - new_size); -#endif - - next: - curr = DUK_HEAPHDR_GET_NEXT(heap, curr); -#ifdef DUK_USE_DEBUG - (*p_count_check)++; -#endif - } -} - -DUK_LOCAL void duk__compact_objects(duk_heap *heap) { - /* XXX: which lists should participate? to be finalized? */ -#ifdef DUK_USE_DEBUG - duk_size_t count_check = 0; - duk_size_t count_compact = 0; - duk_size_t count_bytes_saved = 0; -#endif - duk_hthread *thr; - - DUK_DD(DUK_DDPRINT("duk__compact_objects: %p", (void *) heap)); - - thr = duk__get_temp_hthread(heap); - DUK_ASSERT(thr != NULL); - -#ifdef DUK_USE_DEBUG - duk__compact_object_list(heap, thr, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved); - duk__compact_object_list(heap, thr, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved); -#ifdef DUK_USE_REFERENCE_COUNTING - duk__compact_object_list(heap, thr, heap->refzero_list, &count_check, &count_compact, &count_bytes_saved); -#endif -#else - duk__compact_object_list(heap, thr, heap->heap_allocated); - duk__compact_object_list(heap, thr, heap->finalize_list); -#ifdef DUK_USE_REFERENCE_COUNTING - duk__compact_object_list(heap, thr, heap->refzero_list); -#endif -#endif - -#ifdef DUK_USE_DEBUG - DUK_D(DUK_DPRINT("mark-and-sweep compact objects: %ld checked, %ld compaction attempts, %ld bytes saved by compaction", - (long) count_check, (long) count_compact, (long) count_bytes_saved)); -#endif -} - -/* - * Assertion helpers. - */ - -#ifdef DUK_USE_ASSERTIONS -DUK_LOCAL void duk__assert_heaphdr_flags(duk_heap *heap) { - duk_heaphdr *hdr; - - hdr = heap->heap_allocated; - while (hdr) { - DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr)); - /* may have FINALIZED */ - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } - -#ifdef DUK_USE_REFERENCE_COUNTING - hdr = heap->refzero_list; - while (hdr) { - DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr)); - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -#endif /* DUK_USE_REFERENCE_COUNTING */ -} - -#ifdef DUK_USE_REFERENCE_COUNTING -DUK_LOCAL void duk__assert_valid_refcounts(duk_heap *heap) { - duk_heaphdr *hdr = heap->heap_allocated; - while (hdr) { - if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0 && - DUK_HEAPHDR_HAS_FINALIZED(hdr)) { - /* An object may be in heap_allocated list with a zero - * refcount if it has just been finalized and is waiting - * to be collected by the next cycle. - */ - } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0) { - /* An object may be in heap_allocated list with a zero - * refcount also if it is a temporary object created by - * a finalizer; because finalization now runs inside - * mark-and-sweep, such objects will not be queued to - * refzero_list and will thus appear here with refcount - * zero. - */ -#if 0 /* this case can no longer occur because refcount is unsigned */ - } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) < 0) { - DUK_D(DUK_DPRINT("invalid refcount: %ld, %p -> %!O", - (hdr != NULL ? (long) DUK_HEAPHDR_GET_REFCOUNT(hdr) : (long) 0), - (void *) hdr, (duk_heaphdr *) hdr)); - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(hdr) > 0); -#endif - } - hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } -} -#endif /* DUK_USE_REFERENCE_COUNTING */ -#endif /* DUK_USE_ASSERTIONS */ - -/* - * Finalizer torture. Do one fake finalizer call which causes side effects - * similar to one or more finalizers on actual objects. - */ - -#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE) -DUK_LOCAL duk_ret_t duk__markandsweep_fake_finalizer(duk_context *ctx) { - DUK_D(DUK_DPRINT("fake mark-and-sweep torture finalizer executed")); - - /* Require a lot of stack to force a value stack grow/shrink. - * Recursive mark-and-sweep is prevented by allocation macros - * so this won't trigger another mark-and-sweep. - */ - duk_require_stack(ctx, 100000); - - /* XXX: do something to force a callstack grow/shrink, perhaps - * just a manual forced resize or a forced relocating realloc? - */ - - return 0; -} - -DUK_LOCAL void duk__markandsweep_torture_finalizer(duk_hthread *thr) { - duk_context *ctx; - duk_int_t rc; - - DUK_ASSERT(thr != NULL); - ctx = (duk_context *) thr; - - /* Avoid fake finalization when callstack limit has been reached. - * Otherwise a callstack limit error will be created, then refzero'ed. - */ - if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit || - thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) { - DUK_D(DUK_DPRINT("call recursion depth reached, avoid fake mark-and-sweep torture finalizer")); - return; - } - - /* Run fake finalizer. Avoid creating unnecessary garbage. */ - duk_push_c_function(ctx, duk__markandsweep_fake_finalizer, 0 /*nargs*/); - rc = duk_pcall(ctx, 0 /*nargs*/); - DUK_UNREF(rc); /* ignored */ - duk_pop(ctx); -} -#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */ - -/* - * Main mark-and-sweep function. - * - * 'flags' represents the features requested by the caller. The current - * heap->mark_and_sweep_base_flags is ORed automatically into the flags; - * the base flags mask typically prevents certain mark-and-sweep operations - * to avoid trouble. - */ - -DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags) { - duk_hthread *thr; - duk_size_t count_keep_obj; - duk_size_t count_keep_str; -#ifdef DUK_USE_VOLUNTARY_GC - duk_size_t tmp; -#endif - - /* XXX: thread selection for mark-and-sweep is currently a hack. - * If we don't have a thread, the entire mark-and-sweep is now - * skipped (although we could just skip finalizations). - */ - - /* If thr != NULL, the thr may still be in the middle of - * initialization. - * XXX: Improve the thread viability test. - */ - thr = duk__get_temp_hthread(heap); - if (thr == NULL) { - DUK_D(DUK_DPRINT("gc skipped because we don't have a temp thread")); - - /* reset voluntary gc trigger count */ -#ifdef DUK_USE_VOLUNTARY_GC - heap->mark_and_sweep_trigger_counter = DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP; -#endif - return 0; /* OK */ - } - - /* If debugger is paused, garbage collection is disabled by default. */ - /* XXX: will need a force flag if garbage collection is triggered - * explicitly during paused state. - */ -#if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_HEAP_IS_PAUSED(heap)) { - /* Checking this here rather that in memory alloc primitives - * reduces checking code there but means a failed allocation - * will go through a few retries before giving up. That's - * fine because this only happens during debugging. - */ - DUK_D(DUK_DPRINT("gc skipped because debugger is paused")); - return 0; - } -#endif - - DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) starting, requested flags: 0x%08lx, effective flags: 0x%08lx", - (unsigned long) flags, (unsigned long) (flags | heap->mark_and_sweep_base_flags))); - - flags |= heap->mark_and_sweep_base_flags; - - /* - * Assertions before - */ - -#ifdef DUK_USE_ASSERTIONS - DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)); - DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)); - DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0); - duk__assert_heaphdr_flags(heap); -#ifdef DUK_USE_REFERENCE_COUNTING - /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount - * finalizer may trigger a mark-and-sweep. - */ - duk__assert_valid_refcounts(heap); -#endif /* DUK_USE_REFERENCE_COUNTING */ -#endif /* DUK_USE_ASSERTIONS */ - - /* - * Begin - */ - - DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap); - - /* - * Mark roots, hoping that recursion limit is not normally hit. - * If recursion limit is hit, run additional reachability rounds - * starting from "temproots" until marking is complete. - * - * Marking happens in two phases: first we mark actual reachability - * roots (and run "temproots" to complete the process). Then we - * check which objects are unreachable and are finalizable; such - * objects are marked as FINALIZABLE and marked as reachability - * (and "temproots" is run again to complete the process). - * - * The heap finalize_list must also be marked as a reachability root. - * There may be objects on the list from a previous round if the - * previous run had finalizer skip flag. - */ - - duk__mark_roots_heap(heap); /* main reachability roots */ -#ifdef DUK_USE_REFERENCE_COUNTING - duk__mark_refzero_list(heap); /* refzero_list treated as reachability roots */ -#endif - duk__mark_temproots_by_heap_scan(heap); /* temproots */ - - duk__mark_finalizable(heap); /* mark finalizable as reachability roots */ - duk__mark_finalize_list(heap); /* mark finalizer work list as reachability roots */ - duk__mark_temproots_by_heap_scan(heap); /* temproots */ - - /* - * Sweep garbage and remove marking flags, and move objects with - * finalizers to the finalizer work list. - * - * Objects to be swept need to get their refcounts finalized before - * they are swept. In other words, their target object refcounts - * need to be decreased. This has to be done before freeing any - * objects to avoid decref'ing dangling pointers (which may happen - * even without bugs, e.g. with reference loops) - * - * Because strings don't point to other heap objects, similar - * finalization is not necessary for strings. - */ - - /* XXX: more emergency behavior, e.g. find smaller hash sizes etc */ - -#ifdef DUK_USE_REFERENCE_COUNTING - duk__finalize_refcounts(heap); -#endif - duk__sweep_heap(heap, flags, &count_keep_obj); -#if defined(DUK_USE_STRTAB_CHAIN) - duk__sweep_stringtable_chain(heap, &count_keep_str); -#elif defined(DUK_USE_STRTAB_PROBE) - duk__sweep_stringtable_probe(heap, &count_keep_str); -#else -#error internal error, invalid strtab options -#endif -#ifdef DUK_USE_REFERENCE_COUNTING - duk__clear_refzero_list_flags(heap); -#endif - duk__clear_finalize_list_flags(heap); - - /* - * Object compaction (emergency only). - * - * Object compaction is a separate step after sweeping, as there is - * more free memory for it to work with. Also, currently compaction - * may insert new objects into the heap allocated list and the string - * table which we don't want to do during a sweep (the reachability - * flags of such objects would be incorrect). The objects inserted - * are currently: - * - * - a temporary duk_hbuffer for a new properties allocation - * - if array part is abandoned, string keys are interned - * - * The object insertions go to the front of the list, so they do not - * cause an infinite loop (they are not compacted). - */ - - if ((flags & DUK_MS_FLAG_EMERGENCY) && - !(flags & DUK_MS_FLAG_NO_OBJECT_COMPACTION)) { - duk__compact_objects(heap); - } - - /* - * String table resize check. - * - * Note: this may silently (and safely) fail if GC is caused by an - * allocation call in stringtable resize_hash(). Resize_hash() - * will prevent a recursive call to itself by setting the - * DUK_MS_FLAG_NO_STRINGTABLE_RESIZE in heap->mark_and_sweep_base_flags. - */ - - /* XXX: stringtable emergency compaction? */ - - /* XXX: remove this feature entirely? it would only matter for - * emergency GC. Disable for lowest memory builds. - */ -#if defined(DUK_USE_MS_STRINGTABLE_RESIZE) - if (!(flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE)) { - DUK_DD(DUK_DDPRINT("resize stringtable: %p", (void *) heap)); - duk_heap_force_strtab_resize(heap); - } else { - DUK_D(DUK_DPRINT("stringtable resize skipped because DUK_MS_FLAG_NO_STRINGTABLE_RESIZE is set")); - } -#endif - - /* - * Finalize objects in the finalization work list. Finalized - * objects are queued back to heap_allocated with FINALIZED set. - * - * Since finalizers may cause arbitrary side effects, they are - * prevented during string table and object property allocation - * resizing using the DUK_MS_FLAG_NO_FINALIZERS flag in - * heap->mark_and_sweep_base_flags. In this case the objects - * remain in the finalization work list after mark-and-sweep - * exits and they may be finalized on the next pass. - * - * Finalization currently happens inside "MARKANDSWEEP_RUNNING" - * protection (no mark-and-sweep may be triggered by the - * finalizers). As a side effect: - * - * 1) an out-of-memory error inside a finalizer will not - * cause a mark-and-sweep and may cause the finalizer - * to fail unnecessarily - * - * 2) any temporary objects whose refcount decreases to zero - * during finalization will not be put into refzero_list; - * they can only be collected by another mark-and-sweep - * - * This is not optimal, but since the sweep for this phase has - * already happened, this is probably good enough for now. - */ - -#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE) - /* Cannot simulate individual finalizers because finalize_list only - * contains objects with actual finalizers. But simulate side effects - * from finalization by doing a bogus function call and resizing the - * stacks. - */ - if (flags & DUK_MS_FLAG_NO_FINALIZERS) { - DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, DUK_MS_FLAG_NO_FINALIZERS is set")); - } else if (!(thr->valstack != NULL && thr->callstack != NULL && thr->catchstack != NULL)) { - DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, thread not yet viable")); - } else { - DUK_D(DUK_DPRINT("run mark-and-sweep torture finalizer")); - duk__markandsweep_torture_finalizer(thr); - } -#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */ - - if (flags & DUK_MS_FLAG_NO_FINALIZERS) { - DUK_D(DUK_DPRINT("finalizer run skipped because DUK_MS_FLAG_NO_FINALIZERS is set")); - } else { - duk__run_object_finalizers(heap, flags); - } - - /* - * Finish - */ - - DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap); - - /* - * Assertions after - */ - -#ifdef DUK_USE_ASSERTIONS - DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)); - DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)); - DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0); - duk__assert_heaphdr_flags(heap); -#ifdef DUK_USE_REFERENCE_COUNTING - /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount - * finalizer may trigger a mark-and-sweep. - */ - duk__assert_valid_refcounts(heap); -#endif /* DUK_USE_REFERENCE_COUNTING */ -#endif /* DUK_USE_ASSERTIONS */ - - /* - * Reset trigger counter - */ - -#ifdef DUK_USE_VOLUNTARY_GC - tmp = (count_keep_obj + count_keep_str) / 256; - heap->mark_and_sweep_trigger_counter = (duk_int_t) ( - (tmp * DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT) + - DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD); - DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, trigger reset to %ld", - (long) count_keep_obj, (long) count_keep_str, (long) heap->mark_and_sweep_trigger_counter)); -#else - DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, no voluntary trigger", - (long) count_keep_obj, (long) count_keep_str)); -#endif - - return 0; /* OK */ -} - -#else /* DUK_USE_MARK_AND_SWEEP */ - -/* no mark-and-sweep gc */ - -#endif /* DUK_USE_MARK_AND_SWEEP */ http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b8103f03/thirdparty/civetweb-1.9.1/src/third_party/duktape-1.5.2/src-separate/duk_heap_memory.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.9.1/src/third_party/duktape-1.5.2/src-separate/duk_heap_memory.c b/thirdparty/civetweb-1.9.1/src/third_party/duktape-1.5.2/src-separate/duk_heap_memory.c deleted file mode 100644 index c0d7030..0000000 --- a/thirdparty/civetweb-1.9.1/src/third_party/duktape-1.5.2/src-separate/duk_heap_memory.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Memory allocation handling. - */ - -#include "duk_internal.h" - -/* - * Helpers - * - * The fast path checks are done within a macro to ensure "inlining" - * while the slow path actions use a helper (which won't typically be - * inlined in size optimized builds). - */ - -#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_VOLUNTARY_GC) -#define DUK__VOLUNTARY_PERIODIC_GC(heap) do { \ - (heap)->mark_and_sweep_trigger_counter--; \ - if ((heap)->mark_and_sweep_trigger_counter <= 0) { \ - duk__run_voluntary_gc(heap); \ - } \ - } while (0) - -DUK_LOCAL void duk__run_voluntary_gc(duk_heap *heap) { - if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { - DUK_DD(DUK_DDPRINT("mark-and-sweep in progress -> skip voluntary mark-and-sweep now")); - } else { - duk_small_uint_t flags; - duk_bool_t rc; - - DUK_D(DUK_DPRINT("triggering voluntary mark-and-sweep")); - flags = 0; - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); - } -} -#else -#define DUK__VOLUNTARY_PERIODIC_GC(heap) /* no voluntary gc */ -#endif /* DUK_USE_MARK_AND_SWEEP && DUK_USE_VOLUNTARY_GC */ - -/* - * Allocate memory with garbage collection - */ - -#ifdef DUK_USE_MARK_AND_SWEEP -DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) { - void *res; - duk_bool_t rc; - duk_small_int_t i; - - DUK_ASSERT(heap != NULL); - DUK_ASSERT_DISABLE(size >= 0); - - /* - * Voluntary periodic GC (if enabled) - */ - - DUK__VOLUNTARY_PERIODIC_GC(heap); - - /* - * First attempt - */ - -#ifdef DUK_USE_GC_TORTURE - /* simulate alloc failure on every alloc (except when mark-and-sweep is running) */ - if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { - DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first alloc attempt fails")); - res = NULL; - DUK_UNREF(res); - goto skip_attempt; - } -#endif - res = heap->alloc_func(heap->heap_udata, size); - if (res || size == 0) { - /* for zero size allocations NULL is allowed */ - return res; - } -#ifdef DUK_USE_GC_TORTURE - skip_attempt: -#endif - - DUK_D(DUK_DPRINT("first alloc attempt failed, attempt to gc and retry")); - - /* - * Avoid a GC if GC is already running. This can happen at a late - * stage in a GC when we try to e.g. resize the stringtable - * or compact objects. - */ - - if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { - DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed, gc in progress (gc skipped), alloc size %ld", (long) size)); - return NULL; - } - - /* - * Retry with several GC attempts. Initial attempts are made without - * emergency mode; later attempts use emergency mode which minimizes - * memory allocations forcibly. - */ - - for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) { - duk_small_uint_t flags; - - flags = 0; - if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) { - flags |= DUK_MS_FLAG_EMERGENCY; - } - - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); - - res = heap->alloc_func(heap->heap_udata, size); - if (res) { - DUK_D(DUK_DPRINT("duk_heap_mem_alloc() succeeded after gc (pass %ld), alloc size %ld", - (long) (i + 1), (long) size)); - return res; - } - } - - DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed even after gc, alloc size %ld", (long) size)); - return NULL; -} -#else /* DUK_USE_MARK_AND_SWEEP */ -/* - * Compared to a direct macro expansion this wrapper saves a few - * instructions because no heap dereferencing is required. - */ -DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) { - DUK_ASSERT(heap != NULL); - DUK_ASSERT_DISABLE(size >= 0); - - return heap->alloc_func(heap->heap_udata, size); -} -#endif /* DUK_USE_MARK_AND_SWEEP */ - -DUK_INTERNAL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size) { - void *res; - - DUK_ASSERT(heap != NULL); - DUK_ASSERT_DISABLE(size >= 0); - - res = DUK_ALLOC(heap, size); - if (res) { - /* assume memset with zero size is OK */ - DUK_MEMZERO(res, size); - } - return res; -} - -/* - * Reallocate memory with garbage collection - */ - -#ifdef DUK_USE_MARK_AND_SWEEP -DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize) { - void *res; - duk_bool_t rc; - duk_small_int_t i; - - DUK_ASSERT(heap != NULL); - /* ptr may be NULL */ - DUK_ASSERT_DISABLE(newsize >= 0); - - /* - * Voluntary periodic GC (if enabled) - */ - - DUK__VOLUNTARY_PERIODIC_GC(heap); - - /* - * First attempt - */ - -#ifdef DUK_USE_GC_TORTURE - /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */ - if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { - DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first realloc attempt fails")); - res = NULL; - DUK_UNREF(res); - goto skip_attempt; - } -#endif - res = heap->realloc_func(heap->heap_udata, ptr, newsize); - if (res || newsize == 0) { - /* for zero size allocations NULL is allowed */ - return res; - } -#ifdef DUK_USE_GC_TORTURE - skip_attempt: -#endif - - DUK_D(DUK_DPRINT("first realloc attempt failed, attempt to gc and retry")); - - /* - * Avoid a GC if GC is already running. See duk_heap_mem_alloc(). - */ - - if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { - DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed, gc in progress (gc skipped), alloc size %ld", (long) newsize)); - return NULL; - } - - /* - * Retry with several GC attempts. Initial attempts are made without - * emergency mode; later attempts use emergency mode which minimizes - * memory allocations forcibly. - */ - - for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) { - duk_small_uint_t flags; - - flags = 0; - if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) { - flags |= DUK_MS_FLAG_EMERGENCY; - } - - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); - - res = heap->realloc_func(heap->heap_udata, ptr, newsize); - if (res || newsize == 0) { - DUK_D(DUK_DPRINT("duk_heap_mem_realloc() succeeded after gc (pass %ld), alloc size %ld", - (long) (i + 1), (long) newsize)); - return res; - } - } - - DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed even after gc, alloc size %ld", (long) newsize)); - return NULL; -} -#else /* DUK_USE_MARK_AND_SWEEP */ -/* saves a few instructions to have this wrapper (see comment on duk_heap_mem_alloc) */ -DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize) { - DUK_ASSERT(heap != NULL); - /* ptr may be NULL */ - DUK_ASSERT_DISABLE(newsize >= 0); - - return heap->realloc_func(heap->heap_udata, ptr, newsize); -} -#endif /* DUK_USE_MARK_AND_SWEEP */ - -/* - * Reallocate memory with garbage collection, using a callback to provide - * the current allocated pointer. This variant is used when a mark-and-sweep - * (e.g. finalizers) might change the original pointer. - */ - -#ifdef DUK_USE_MARK_AND_SWEEP -DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) { - void *res; - duk_bool_t rc; - duk_small_int_t i; - - DUK_ASSERT(heap != NULL); - DUK_ASSERT_DISABLE(newsize >= 0); - - /* - * Voluntary periodic GC (if enabled) - */ - - DUK__VOLUNTARY_PERIODIC_GC(heap); - - /* - * First attempt - */ - -#ifdef DUK_USE_GC_TORTURE - /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */ - if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { - DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first indirect realloc attempt fails")); - res = NULL; - DUK_UNREF(res); - goto skip_attempt; - } -#endif - res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize); - if (res || newsize == 0) { - /* for zero size allocations NULL is allowed */ - return res; - } -#ifdef DUK_USE_GC_TORTURE - skip_attempt: -#endif - - DUK_D(DUK_DPRINT("first indirect realloc attempt failed, attempt to gc and retry")); - - /* - * Avoid a GC if GC is already running. See duk_heap_mem_alloc(). - */ - - if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { - DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed, gc in progress (gc skipped), alloc size %ld", (long) newsize)); - return NULL; - } - - /* - * Retry with several GC attempts. Initial attempts are made without - * emergency mode; later attempts use emergency mode which minimizes - * memory allocations forcibly. - */ - - for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) { - duk_small_uint_t flags; - -#ifdef DUK_USE_ASSERTIONS - void *ptr_pre; /* ptr before mark-and-sweep */ - void *ptr_post; -#endif - -#ifdef DUK_USE_ASSERTIONS - ptr_pre = cb(heap, ud); -#endif - flags = 0; - if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) { - flags |= DUK_MS_FLAG_EMERGENCY; - } - - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); -#ifdef DUK_USE_ASSERTIONS - ptr_post = cb(heap, ud); - if (ptr_pre != ptr_post) { - /* useful for debugging */ - DUK_DD(DUK_DDPRINT("note: base pointer changed by mark-and-sweep: %p -> %p", - (void *) ptr_pre, (void *) ptr_post)); - } -#endif - - /* Note: key issue here is to re-lookup the base pointer on every attempt. - * The pointer being reallocated may change after every mark-and-sweep. - */ - - res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize); - if (res || newsize == 0) { - DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() succeeded after gc (pass %ld), alloc size %ld", - (long) (i + 1), (long) newsize)); - return res; - } - } - - DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed even after gc, alloc size %ld", (long) newsize)); - return NULL; -} -#else /* DUK_USE_MARK_AND_SWEEP */ -/* saves a few instructions to have this wrapper (see comment on duk_heap_mem_alloc) */ -DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) { - return heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize); -} -#endif /* DUK_USE_MARK_AND_SWEEP */ - -/* - * Free memory - */ - -#ifdef DUK_USE_MARK_AND_SWEEP -DUK_INTERNAL void duk_heap_mem_free(duk_heap *heap, void *ptr) { - DUK_ASSERT(heap != NULL); - /* ptr may be NULL */ - - /* Must behave like a no-op with NULL and any pointer returned from - * malloc/realloc with zero size. - */ - heap->free_func(heap->heap_udata, ptr); - - /* Count free operations toward triggering a GC but never actually trigger - * a GC from a free. Otherwise code which frees internal structures would - * need to put in NULLs at every turn to ensure the object is always in - * consistent state for a mark-and-sweep. - */ -#ifdef DUK_USE_VOLUNTARY_GC - heap->mark_and_sweep_trigger_counter--; -#endif -} -#else -/* saves a few instructions to have this wrapper (see comment on duk_heap_mem_alloc) */ -DUK_INTERNAL void duk_heap_mem_free(duk_heap *heap, void *ptr) { - DUK_ASSERT(heap != NULL); - /* ptr may be NULL */ - - /* Note: must behave like a no-op with NULL and any pointer - * returned from malloc/realloc with zero size. - */ - heap->free_func(heap->heap_udata, ptr); -} -#endif http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b8103f03/thirdparty/civetweb-1.9.1/src/third_party/duktape-1.5.2/src-separate/duk_heap_misc.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.9.1/src/third_party/duktape-1.5.2/src-separate/duk_heap_misc.c b/thirdparty/civetweb-1.9.1/src/third_party/duktape-1.5.2/src-separate/duk_heap_misc.c deleted file mode 100644 index f4edd2c..0000000 --- a/thirdparty/civetweb-1.9.1/src/third_party/duktape-1.5.2/src-separate/duk_heap_misc.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Support functions for duk_heap. - */ - -#include "duk_internal.h" - -#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING) -/* arbitrary remove only works with double linked heap, and is only required by - * reference counting so far. - */ -DUK_INTERNAL void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) { - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING); - - if (DUK_HEAPHDR_GET_PREV(heap, hdr)) { - DUK_HEAPHDR_SET_NEXT(heap, DUK_HEAPHDR_GET_PREV(heap, hdr), DUK_HEAPHDR_GET_NEXT(heap, hdr)); - } else { - heap->heap_allocated = DUK_HEAPHDR_GET_NEXT(heap, hdr); - } - if (DUK_HEAPHDR_GET_NEXT(heap, hdr)) { - DUK_HEAPHDR_SET_PREV(heap, DUK_HEAPHDR_GET_NEXT(heap, hdr), DUK_HEAPHDR_GET_PREV(heap, hdr)); - } else { - ; - } - - /* The prev/next pointers of the removed duk_heaphdr are left as garbage. - * It's up to the caller to ensure they're written before inserting the - * object back. - */ -} -#endif - -DUK_INTERNAL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) { - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING); - -#ifdef DUK_USE_DOUBLE_LINKED_HEAP - if (heap->heap_allocated) { - DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, heap->heap_allocated) == NULL); - DUK_HEAPHDR_SET_PREV(heap, heap->heap_allocated, hdr); - } - DUK_HEAPHDR_SET_PREV(heap, hdr, NULL); -#endif - DUK_HEAPHDR_SET_NEXT(heap, hdr, heap->heap_allocated); - heap->heap_allocated = hdr; -} - -#ifdef DUK_USE_INTERRUPT_COUNTER -DUK_INTERNAL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr) { - duk_hthread *curr_thr; - - DUK_ASSERT(heap != NULL); - - if (new_thr != NULL) { - curr_thr = heap->curr_thread; - if (curr_thr == NULL) { - /* For initial entry use default value; zero forces an - * interrupt before executing the first insturction. - */ - DUK_DD(DUK_DDPRINT("switch thread, initial entry, init default interrupt counter")); - new_thr->interrupt_counter = 0; - new_thr->interrupt_init = 0; - } else { - /* Copy interrupt counter/init value state to new thread (if any). - * It's OK for new_thr to be the same as curr_thr. - */ -#if defined(DUK_USE_DEBUG) - if (new_thr != curr_thr) { - DUK_DD(DUK_DDPRINT("switch thread, not initial entry, copy interrupt counter")); - } -#endif - new_thr->interrupt_counter = curr_thr->interrupt_counter; - new_thr->interrupt_init = curr_thr->interrupt_init; - } - } else { - DUK_DD(DUK_DDPRINT("switch thread, new thread is NULL, no interrupt counter changes")); - } - - heap->curr_thread = new_thr; /* may be NULL */ -} -#endif /* DUK_USE_INTERRUPT_COUNTER */ http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/b8103f03/thirdparty/civetweb-1.9.1/src/third_party/duktape-1.5.2/src-separate/duk_heap_refcount.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.9.1/src/third_party/duktape-1.5.2/src-separate/duk_heap_refcount.c b/thirdparty/civetweb-1.9.1/src/third_party/duktape-1.5.2/src-separate/duk_heap_refcount.c deleted file mode 100644 index 4580dc1..0000000 --- a/thirdparty/civetweb-1.9.1/src/third_party/duktape-1.5.2/src-separate/duk_heap_refcount.c +++ /dev/null @@ -1,614 +0,0 @@ -/* - * Reference counting implementation. - */ - -#include "duk_internal.h" - -#ifdef DUK_USE_REFERENCE_COUNTING - -#ifndef DUK_USE_DOUBLE_LINKED_HEAP -#error internal error, reference counting requires a double linked heap -#endif - -/* - * Misc - */ - -DUK_LOCAL void duk__queue_refzero(duk_heap *heap, duk_heaphdr *hdr) { - /* tail insert: don't disturb head in case refzero is running */ - - if (heap->refzero_list != NULL) { - duk_heaphdr *hdr_prev; - - hdr_prev = heap->refzero_list_tail; - DUK_ASSERT(hdr_prev != NULL); - DUK_ASSERT(DUK_HEAPHDR_GET_NEXT(heap, hdr_prev) == NULL); - - DUK_HEAPHDR_SET_NEXT(heap, hdr, NULL); - DUK_HEAPHDR_SET_PREV(heap, hdr, hdr_prev); - DUK_HEAPHDR_SET_NEXT(heap, hdr_prev, hdr); - DUK_ASSERT_HEAPHDR_LINKS(heap, hdr); - DUK_ASSERT_HEAPHDR_LINKS(heap, hdr_prev); - heap->refzero_list_tail = hdr; - } else { - DUK_ASSERT(heap->refzero_list_tail == NULL); - DUK_HEAPHDR_SET_NEXT(heap, hdr, NULL); - DUK_HEAPHDR_SET_PREV(heap, hdr, NULL); - DUK_ASSERT_HEAPHDR_LINKS(heap, hdr); - heap->refzero_list = hdr; - heap->refzero_list_tail = hdr; - } -} - -/* - * Heap object refcount finalization. - * - * When an object is about to be freed, all other objects it refers to must - * be decref'd. Refcount finalization does NOT free the object or its inner - * allocations (mark-and-sweep shares these helpers), it just manipulates - * the refcounts. - * - * Note that any of the decref's may cause a refcount to drop to zero, BUT - * it will not be processed inline; instead, because refzero is already - * running, the objects will just be queued to refzero list and processed - * later. This eliminates C recursion. - */ - -DUK_LOCAL void duk__refcount_finalize_hobject(duk_hthread *thr, duk_hobject *h) { - duk_uint_fast32_t i; - - DUK_ASSERT(h); - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h) == DUK_HTYPE_OBJECT); - - /* XXX: better to get base and walk forwards? */ - - for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) { - duk_hstring *key = DUK_HOBJECT_E_GET_KEY(thr->heap, h, i); - if (!key) { - continue; - } - duk_heaphdr_decref(thr, (duk_heaphdr *) key); - if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h, i)) { - duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, h, i)); - duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, h, i)); - } else { - duk_tval_decref(thr, DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h, i)); - } - } - - for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) { - duk_tval_decref(thr, DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, h, i)); - } - - /* hash part is a 'weak reference' and does not contribute */ - - duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h)); - - if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) { - duk_hcompiledfunction *f = (duk_hcompiledfunction *) h; - duk_tval *tv, *tv_end; - duk_hobject **funcs, **funcs_end; - - if (DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f) != NULL) { - tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, f); - tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, f); - while (tv < tv_end) { - duk_tval_decref(thr, tv); - tv++; - } - - funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, f); - funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, f); - while (funcs < funcs_end) { - duk_heaphdr_decref(thr, (duk_heaphdr *) *funcs); - funcs++; - } - } else { - /* May happen in some out-of-memory corner cases. */ - DUK_D(DUK_DPRINT("duk_hcompiledfunction 'data' is NULL, skipping decref")); - } - - duk_heaphdr_decref(thr, (duk_heaphdr *) DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f)); - } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) { - duk_hnativefunction *f = (duk_hnativefunction *) h; - DUK_UNREF(f); - /* nothing to finalize */ - } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) { - duk_hbufferobject *b = (duk_hbufferobject *) h; - if (b->buf) { - duk_heaphdr_decref(thr, (duk_heaphdr *) b->buf); - } - } else if (DUK_HOBJECT_IS_THREAD(h)) { - duk_hthread *t = (duk_hthread *) h; - duk_tval *tv; - - tv = t->valstack; - while (tv < t->valstack_top) { - duk_tval_decref(thr, tv); - tv++; - } - - for (i = 0; i < (duk_uint_fast32_t) t->callstack_top; i++) { - duk_activation *act = t->callstack + i; - duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_ACT_GET_FUNC(act)); - duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) act->var_env); - duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) act->lex_env); -#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY - duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) act->prev_caller); -#endif - } - -#if 0 /* nothing now */ - for (i = 0; i < (duk_uint_fast32_t) t->catchstack_top; i++) { - duk_catcher *cat = t->catchstack + i; - } -#endif - - for (i = 0; i < DUK_NUM_BUILTINS; i++) { - duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) t->builtins[i]); - } - - duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) t->resumer); - } -} - -DUK_INTERNAL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr) { - DUK_ASSERT(hdr); - - switch ((int) DUK_HEAPHDR_GET_TYPE(hdr)) { - case DUK_HTYPE_OBJECT: - duk__refcount_finalize_hobject(thr, (duk_hobject *) hdr); - break; - case DUK_HTYPE_BUFFER: - /* nothing to finalize */ - break; - case DUK_HTYPE_STRING: - /* cannot happen: strings are not put into refzero list (they don't even have the next/prev pointers) */ - default: - DUK_UNREACHABLE(); - } -} - -#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE) -DUK_LOCAL duk_ret_t duk__refcount_fake_finalizer(duk_context *ctx) { - DUK_UNREF(ctx); - DUK_D(DUK_DPRINT("fake refcount torture finalizer executed")); -#if 0 - DUK_DD(DUK_DDPRINT("fake torture finalizer for: %!T", duk_get_tval(ctx, 0))); -#endif - /* Require a lot of stack to force a value stack grow/shrink. */ - duk_require_stack(ctx, 100000); - - /* XXX: do something to force a callstack grow/shrink, perhaps - * just a manual forced resize? - */ - return 0; -} - -DUK_LOCAL void duk__refcount_run_torture_finalizer(duk_hthread *thr, duk_hobject *obj) { - duk_context *ctx; - duk_int_t rc; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(obj != NULL); - ctx = (duk_context *) thr; - - /* Avoid fake finalization for the duk__refcount_fake_finalizer function - * itself, otherwise we're in infinite recursion. - */ - if (DUK_HOBJECT_HAS_NATIVEFUNCTION(obj)) { - if (((duk_hnativefunction *) obj)->func == duk__refcount_fake_finalizer) { - DUK_DD(DUK_DDPRINT("avoid fake torture finalizer for duk__refcount_fake_finalizer itself")); - return; - } - } - /* Avoid fake finalization when callstack limit has been reached. - * Otherwise a callstack limit error will be created, then refzero'ed, - * and we're in an infinite loop. - */ - if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit || - thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) { - DUK_D(DUK_DPRINT("call recursion depth reached, avoid fake torture finalizer")); - return; - } - - /* Run fake finalizer. Avoid creating new refzero queue entries - * so that we are not forced into a forever loop. - */ - duk_push_c_function(ctx, duk__refcount_fake_finalizer, 1 /*nargs*/); - duk_push_hobject(ctx, obj); - rc = duk_pcall(ctx, 1); - DUK_UNREF(rc); /* ignored */ - duk_pop(ctx); -} -#endif /* DUK_USE_REFZERO_FINALIZER_TORTURE */ - -/* - * Refcount memory freeing loop. - * - * Frees objects in the refzero_pending list until the list becomes - * empty. When an object is freed, its references get decref'd and - * may cause further objects to be queued for freeing. - * - * This could be expanded to allow incremental freeing: just bail out - * early and resume at a future alloc/decref/refzero. - */ - -DUK_LOCAL void duk__refzero_free_pending(duk_hthread *thr) { - duk_heaphdr *h1, *h2; - duk_heap *heap; - duk_int_t count = 0; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - heap = thr->heap; - DUK_ASSERT(heap != NULL); - - /* - * Detect recursive invocation - */ - - if (DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap)) { - DUK_DDD(DUK_DDDPRINT("refzero free running, skip run")); - return; - } - - /* - * Churn refzero_list until empty - */ - - DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap); - while (heap->refzero_list) { - duk_hobject *obj; - duk_bool_t rescued = 0; - - /* - * Pick an object from the head (don't remove yet). - */ - - h1 = heap->refzero_list; - obj = (duk_hobject *) h1; - DUK_DD(DUK_DDPRINT("refzero processing %p: %!O", (void *) h1, (duk_heaphdr *) h1)); - DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, h1) == NULL); - DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h1) == DUK_HTYPE_OBJECT); /* currently, always the case */ - -#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE) - /* Torture option to shake out finalizer side effect issues: - * make a bogus function call for every finalizable object, - * essentially simulating the case where everything has a - * finalizer. - */ - DUK_DD(DUK_DDPRINT("refzero torture enabled, fake finalizer")); - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h1) == 0); - DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */ - duk__refcount_run_torture_finalizer(thr, obj); /* must never longjmp */ - DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */ - DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */ -#endif - - /* - * Finalizer check. - * - * Note: running a finalizer may have arbitrary side effects, e.g. - * queue more objects on refzero_list (tail), or even trigger a - * mark-and-sweep. - * - * Note: quick reject check should match vast majority of - * objects and must be safe (not throw any errors, ever). - */ - - /* An object may have FINALIZED here if it was finalized by mark-and-sweep - * on a previous run and refcount then decreased to zero. We won't run the - * finalizer again here. - */ - - /* A finalizer is looked up from the object and up its prototype chain - * (which allows inherited finalizers). - */ - if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) { - DUK_DDD(DUK_DDDPRINT("object has a finalizer, run it")); - - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h1) == 0); - DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */ - - duk_hobject_run_finalizer(thr, obj); /* must never longjmp */ - DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1)); /* duk_hobject_run_finalizer() sets */ - - DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */ - DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */ - - if (DUK_HEAPHDR_GET_REFCOUNT(h1) != 0) { - DUK_DDD(DUK_DDDPRINT("-> object refcount after finalization non-zero, object will be rescued")); - rescued = 1; - } else { - DUK_DDD(DUK_DDDPRINT("-> object refcount still zero after finalization, object will be freed")); - } - } - - /* Refzero head is still the same. This is the case even if finalizer - * inserted more refzero objects; they are inserted to the tail. - */ - DUK_ASSERT(h1 == heap->refzero_list); - - /* - * Remove the object from the refzero list. This cannot be done - * before a possible finalizer has been executed; the finalizer - * may trigger a mark-and-sweep, and mark-and-sweep must be able - * to traverse a complete refzero_list. - */ - - h2 = DUK_HEAPHDR_GET_NEXT(heap, h1); - if (h2) { - DUK_HEAPHDR_SET_PREV(heap, h2, NULL); /* not strictly necessary */ - heap->refzero_list = h2; - } else { - heap->refzero_list = NULL; - heap->refzero_list_tail = NULL; - } - - /* - * Rescue or free. - */ - - if (rescued) { - /* yes -> move back to heap allocated */ - DUK_DD(DUK_DDPRINT("object rescued during refcount finalization: %p", (void *) h1)); - DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(h1)); - DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1)); - DUK_HEAPHDR_CLEAR_FINALIZED(h1); - h2 = heap->heap_allocated; - DUK_HEAPHDR_SET_PREV(heap, h1, NULL); - if (h2) { - DUK_HEAPHDR_SET_PREV(heap, h2, h1); - } - DUK_HEAPHDR_SET_NEXT(heap, h1, h2); - DUK_ASSERT_HEAPHDR_LINKS(heap, h1); - DUK_ASSERT_HEAPHDR_LINKS(heap, h2); - heap->heap_allocated = h1; - } else { - /* no -> decref members, then free */ - duk__refcount_finalize_hobject(thr, obj); - duk_heap_free_heaphdr_raw(heap, h1); - } - - count++; - } - DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap); - - DUK_DDD(DUK_DDDPRINT("refzero processed %ld objects", (long) count)); - - /* - * Once the whole refzero cascade has been freed, check for - * a voluntary mark-and-sweep. - */ - -#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_VOLUNTARY_GC) - /* 'count' is more or less comparable to normal trigger counter update - * which happens in memory block (re)allocation. - */ - heap->mark_and_sweep_trigger_counter -= count; - if (heap->mark_and_sweep_trigger_counter <= 0) { - duk_bool_t rc; - duk_small_uint_t flags = 0; /* not emergency */ - DUK_D(DUK_DPRINT("refcount triggering mark-and-sweep")); - rc = duk_heap_mark_and_sweep(heap, flags); - DUK_UNREF(rc); - DUK_D(DUK_DPRINT("refcount triggered mark-and-sweep => rc %ld", (long) rc)); - } -#endif /* DUK_USE_MARK_AND_SWEEP && DUK_USE_VOLUNTARY_GC */ -} - -/* - * Incref and decref functions. - * - * Decref may trigger immediate refzero handling, which may free and finalize - * an arbitrary number of objects. - * - */ - -DUK_INTERNAL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h) { - duk_heap *heap; - - DUK_ASSERT(thr != NULL); - DUK_ASSERT(h != NULL); - - heap = thr->heap; - DUK_DDD(DUK_DDDPRINT("refzero %p: %!O", (void *) h, (duk_heaphdr *) h)); - - /* - * Refzero handling is skipped entirely if (1) mark-and-sweep is - * running or (2) execution is paused in the debugger. The objects - * are left in the heap, and will be freed by mark-and-sweep or - * eventual heap destruction. - * - * This is necessary during mark-and-sweep because refcounts are also - * updated during the sweep phase (otherwise objects referenced by a - * swept object would have incorrect refcounts) which then calls here. - * This could be avoided by using separate decref macros in - * mark-and-sweep; however, mark-and-sweep also calls finalizers which - * would use the ordinary decref macros anyway and still call this - * function. - * - * This check must be enabled also when mark-and-sweep support has been - * disabled: the flag is also used in heap destruction when running - * finalizers for remaining objects, and the flag prevents objects from - * being moved around in heap linked lists. - */ - - /* XXX: ideally this would be just one flag (maybe a derived one) so - * that a single bit test is sufficient to check the condition. - */ -#if defined(DUK_USE_DEBUGGER_SUPPORT) - if (DUK_UNLIKELY(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) || DUK_HEAP_IS_PAUSED(heap))) { -#else - if (DUK_UNLIKELY(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap))) { -#endif - DUK_DDD(DUK_DDDPRINT("refzero handling suppressed when mark-and-sweep running, object: %p", (void *) h)); - return; - } - - switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) { - case DUK_HTYPE_STRING: - /* - * Strings have no internal references but do have "weak" - * references in the string cache. Also note that strings - * are not on the heap_allocated list like other heap - * elements. - */ - - duk_heap_strcache_string_remove(heap, (duk_hstring *) h); - duk_heap_string_remove(heap, (duk_hstring *) h); - duk_heap_free_heaphdr_raw(heap, h); - break; - - case DUK_HTYPE_OBJECT: - /* - * Objects have internal references. Must finalize through - * the "refzero" work list. - */ - - duk_heap_remove_any_from_heap_allocated(heap, h); - duk__queue_refzero(heap, h); - duk__refzero_free_pending(thr); - break; - - case DUK_HTYPE_BUFFER: - /* - * Buffers have no internal references. However, a dynamic - * buffer has a separate allocation for the buffer. This is - * freed by duk_heap_free_heaphdr_raw(). - */ - - duk_heap_remove_any_from_heap_allocated(heap, h); - duk_heap_free_heaphdr_raw(heap, h); - break; - - default: - DUK_D(DUK_DPRINT("invalid heap type in decref: %ld", (long) DUK_HEAPHDR_GET_TYPE(h))); - DUK_UNREACHABLE(); - } -} - -#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT) -DUK_INTERNAL void duk_tval_incref(duk_tval *tv) { - DUK_ASSERT(tv != NULL); - - if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) { - duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv); - DUK_ASSERT(h != NULL); - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); - DUK_ASSERT_DISABLE(h->h_refcount >= 0); - DUK_HEAPHDR_PREINC_REFCOUNT(h); - } -} -#endif - -#if 0 /* unused */ -DUK_INTERNAL void duk_tval_incref_allownull(duk_tval *tv) { - if (tv == NULL) { - return; - } - if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) { - duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv); - DUK_ASSERT(h != NULL); - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); - DUK_ASSERT_DISABLE(h->h_refcount >= 0); - DUK_HEAPHDR_PREINC_REFCOUNT(h); - } -} -#endif - -DUK_INTERNAL void duk_tval_decref(duk_hthread *thr, duk_tval *tv) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT(tv != NULL); - - if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) { - duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv); - DUK_ASSERT(h != NULL); - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); - duk_heaphdr_decref(thr, h); - } -} - -#if 0 /* unused */ -DUK_INTERNAL void duk_tval_decref_allownull(duk_hthread *thr, duk_tval *tv) { - DUK_ASSERT(thr != NULL); - - if (tv == NULL) { - return; - } - if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) { - duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv); - DUK_ASSERT(h != NULL); - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); - duk_heaphdr_decref(thr, h); - } -} -#endif - -#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT) -DUK_INTERNAL void duk_heaphdr_incref(duk_heaphdr *h) { - DUK_ASSERT(h != NULL); - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); - DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0); - - DUK_HEAPHDR_PREINC_REFCOUNT(h); -} -#endif - -#if 0 /* unused */ -DUK_INTERNAL void duk_heaphdr_incref_allownull(duk_heaphdr *h) { - if (h == NULL) { - return; - } - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); - DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0); - - DUK_HEAPHDR_PREINC_REFCOUNT(h); -} -#endif - -DUK_INTERNAL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - DUK_ASSERT(h != NULL); - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1); - -#if defined(DUK_USE_ROM_OBJECTS) - if (DUK_HEAPHDR_HAS_READONLY(h)) { - return; - } -#endif - if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) { - return; - } - duk_heaphdr_refzero(thr, h); -} - -DUK_INTERNAL void duk_heaphdr_decref_allownull(duk_hthread *thr, duk_heaphdr *h) { - DUK_ASSERT(thr != NULL); - DUK_ASSERT(thr->heap != NULL); - - if (h == NULL) { - return; - } - DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); - -#if defined(DUK_USE_ROM_OBJECTS) - if (DUK_HEAPHDR_HAS_READONLY(h)) { - return; - } -#endif - DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1); - if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) { - return; - } - duk_heaphdr_refzero(thr, h); -} - -#else - -/* no refcounting */ - -#endif /* DUK_USE_REFERENCE_COUNTING */
