You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ph...@apache.org on 2018/01/02 18:28:12 UTC
[17/51] [partial] nifi-minifi-cpp git commit: MINIFICPP-351: Remove
Civetweb third party directory
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/ede68a10/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_heap_hashstring.c
----------------------------------------------------------------------
diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_heap_hashstring.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_heap_hashstring.c
deleted file mode 100644
index 5cad795..0000000
--- a/thirdparty/civetweb-1.10/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/ede68a10/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_heap_markandsweep.c
----------------------------------------------------------------------
diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_heap_markandsweep.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_heap_markandsweep.c
deleted file mode 100644
index fa7b553..0000000
--- a/thirdparty/civetweb-1.10/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/ede68a10/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_heap_memory.c
----------------------------------------------------------------------
diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_heap_memory.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_heap_memory.c
deleted file mode 100644
index c0d7030..0000000
--- a/thirdparty/civetweb-1.10/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/ede68a10/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_heap_misc.c
----------------------------------------------------------------------
diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_heap_misc.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_heap_misc.c
deleted file mode 100644
index f4edd2c..0000000
--- a/thirdparty/civetweb-1.10/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/ede68a10/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_heap_refcount.c
----------------------------------------------------------------------
diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_heap_refcount.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/src-separate/duk_heap_refcount.c
deleted file mode 100644
index 4580dc1..0000000
--- a/thirdparty/civetweb-1.10/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 */