Browse Source

Merge branch 'perf-direct-refcount-macros'

Use direct refcount macros and only call into a helper when refzero happens.

This reduces compiled binary size (!) and has a small positive performance
impact.
pull/156/head
Sami Vaarala 10 years ago
parent
commit
95e4d8b98f
  1. 10
      Makefile
  2. 3
      RELEASES.rst
  3. 10
      doc/memory-management.rst
  4. 4
      src/duk_api_heap.c
  5. 4
      src/duk_error_macros.c
  6. 15
      src/duk_features.h.in
  7. 25
      src/duk_heap.h
  8. 2
      src/duk_heap_markandsweep.c
  9. 224
      src/duk_heap_refcount.c
  10. 163
      src/duk_heaphdr.h
  11. 4
      src/duk_hobject_misc.c
  12. 24
      src/duk_hobject_props.c
  13. 2
      src/duk_hthread_builtins.c
  14. 6
      src/duk_hthread_stacks.c
  15. 6
      src/duk_js_call.c
  16. 4
      src/duk_js_var.c

10
Makefile

@ -1033,11 +1033,11 @@ perftest: duk
for i in perf-testcases/*.js; do echo \
"`basename $$i`:" \
"duk `time -f %U -o /tmp/time --quiet ./duk $$i >/dev/null 2>&1; cat /tmp/time; rm /tmp/time`" \
"rhino `time -f %U -o /tmp/time --quiet rhino $$i >/dev/null 2>&1; cat /tmp/time; rm /tmp/time`" \
"lua `time -f %U -o /tmp/time --quiet lua $${i%%.js}.lua >/dev/null 2>&1; cat /tmp/time; rm /tmp/time`" \
"python `time -f %U -o /tmp/time --quiet python $${i%%.js}.py >/dev/null 2>&1; cat /tmp/time; rm /tmp/time`" \
"perl `time -f %U -o /tmp/time --quiet perl $${i%%.js}.pl >/dev/null 2>&1; cat /tmp/time; rm /tmp/time`" \
"ruby `time -f %U -o /tmp/time --quiet ruby $${i%%.js}.rb >/dev/null 2>&1; cat /tmp/time; rm /tmp/time`"; \
"rhino `time -f %U -o /tmp/time --quiet rhino $$i >/dev/null 2>&1; if [ $$? -eq 0 ]; then cat /tmp/time; else echo -n n/a; fi; rm /tmp/time`" \
"lua `time -f %U -o /tmp/time --quiet lua $${i%%.js}.lua >/dev/null 2>&1; if [ $$? -eq 0 ]; then cat /tmp/time; else echo -n n/a; fi; rm /tmp/time`" \
"python `time -f %U -o /tmp/time --quiet python $${i%%.js}.py >/dev/null 2>&1; if [ $$? -eq 0 ]; then cat /tmp/time; else echo -n n/a; fi; rm /tmp/time`" \
"perl `time -f %U -o /tmp/time --quiet perl $${i%%.js}.pl >/dev/null 2>&1; if [ $$? -eq 0 ]; then cat /tmp/time; else echo -n n/a; fi; rm /tmp/time`" \
"ruby `time -f %U -o /tmp/time --quiet ruby $${i%%.js}.rb >/dev/null 2>&1; if [ $$? -eq 0 ]; then cat /tmp/time; else echo -n n/a; fi; rm /tmp/time`"; \
done
perftestduk: duk
for i in perf-testcases/*.js; do echo \

3
RELEASES.rst

@ -829,6 +829,9 @@ Planned
* Accept 32-bit codepoints in String.fromCharCode() to better support non-BMP
strings (GH-120)
* Internal performance improvement: direct refcount manipulation from macros
instead of doing a helper function call
* Fix Unicode handling of CJK ideographs and Hangul which were incorrectly
not accepted in identifier names (see GH-103)

10
doc/memory-management.rst

@ -730,14 +730,14 @@ Macros:
* ``DUK_HEAPHDR_DECREF``
* and a bunch of heap element type specific INCREF/DECREF macros,
defined in ``heaphdr.h``
* and a bunch of heap element type specific INCREF/DECREF macros and
helpers, defined in ``heaphdr.h``
Notes on macro semantics:
* The macros tolerate ``NULL`` pointers, which are simply ignored. This
reduces caller code size but requires a pointer check which is unnecessary
in the vast majority of cases.
* The macros are optimized for performance and don't tolerate a ``NULL``
pointer by default. There are ``_ALLOWNULL`` variants for cases where
NULLs may actually occur.
* An ``INCREF`` is guaranteed not to have any side effects.

4
src/duk_api_heap.c

@ -84,7 +84,7 @@ DUK_EXTERNAL void duk_set_global_object(duk_context *ctx) {
h_prev_glob = thr->builtins[DUK_BIDX_GLOBAL];
thr->builtins[DUK_BIDX_GLOBAL] = h_glob;
DUK_HOBJECT_INCREF(thr, h_glob);
DUK_HOBJECT_DECREF(thr, h_prev_glob); /* side effects, in theory (referenced by global env) */
DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_glob); /* side effects, in theory (referenced by global env) */
/*
* Replace lexical environment for global scope
@ -116,7 +116,7 @@ DUK_EXTERNAL void duk_set_global_object(duk_context *ctx) {
h_prev_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_env;
DUK_HOBJECT_INCREF(thr, h_env);
DUK_HOBJECT_DECREF(thr, h_prev_env); /* side effects */
DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_env); /* side effects */
DUK_UNREF(h_env); /* without refcounts */
DUK_UNREF(h_prev_env);

4
src/duk_error_macros.c

@ -55,10 +55,14 @@ DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) {
#else /* DUK_USE_VARIADIC_MACROS */
DUK_INTERNAL void duk_err_handle_error_nonverbose1(duk_hthread *thr, duk_errcode_t code, const char *fmt, ...) {
DUK_UNREF(fmt);
duk_err_create_and_throw(thr, code);
}
DUK_INTERNAL void duk_err_handle_error_nonverbose2(const char *filename, duk_int_t line, duk_hthread *thr, duk_errcode_t code, const char *fmt, ...) {
DUK_UNREF(filename);
DUK_UNREF(line);
DUK_UNREF(fmt);
duk_err_create_and_throw(thr, code);
}
#endif /* DUK_USE_VARIADIC_MACROS */

15
src/duk_features.h.in

@ -2233,13 +2233,18 @@ typedef FILE duk_file;
#endif
/*
* General prefer speed/size flag
*
* Catch-all flag which can be used to choose between variant algorithms
* where a speed-size tradeoff exists (e.g. lookup tables). When it really
* matters, specific use flags may be appropriate.
* Speed/size and other performance options
*/
/* Use fast ("inline") refcount operations instead of calling out to helpers
* by default. The difference in binary size is small (~1kB on x64).
*/
#define DUK_USE_FAST_REFCOUNT_DEFAULT
/* Catch-all flag which can be used to choose between variant algorithms
* where a speed-size tradeoff exists (e.g. lookup tables). When it really
* matters, specific use flags may be appropriate.
*/
#define DUK_USE_PREFER_SIZE
/*

25
src/duk_heap.h

@ -572,11 +572,26 @@ DUK_INTERNAL_DECL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_ge
DUK_INTERNAL_DECL void duk_heap_mem_free(duk_heap *heap, void *ptr);
#ifdef DUK_USE_REFERENCE_COUNTING
DUK_INTERNAL_DECL void duk_heap_tval_incref(duk_tval *tv);
DUK_INTERNAL_DECL void duk_heap_tval_decref(duk_hthread *thr, duk_tval *tv);
DUK_INTERNAL_DECL void duk_heap_heaphdr_incref(duk_heaphdr *h);
DUK_INTERNAL_DECL void duk_heap_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h);
DUK_INTERNAL_DECL void duk_heap_refcount_finalize_heaphdr(duk_hthread *thr, duk_heaphdr *hdr);
#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv);
#endif
#if 0 /* unused */
DUK_INTERNAL_DECL void duk_tval_incref_allownull(duk_tval *tv);
#endif
DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv);
#if 0 /* unused */
DUK_INTERNAL_DECL void duk_tval_decref_allownull(duk_hthread *thr, duk_tval *tv);
#endif
#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h);
#endif
#if 0 /* unused */
DUK_INTERNAL_DECL void duk_heaphdr_incref_allownull(duk_heaphdr *h);
#endif
DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h);
DUK_INTERNAL_DECL void duk_heaphdr_decref_allownull(duk_hthread *thr, duk_heaphdr *h);
DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h);
DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr);
#else
/* no refcounting */
#endif

2
src/duk_heap_markandsweep.c

@ -453,7 +453,7 @@ DUK_LOCAL void duk__finalize_refcounts(duk_heap *heap) {
*/
DUK_DDD(DUK_DDDPRINT("unreachable object, refcount finalize before sweeping: %p", (void *) hdr));
duk_heap_refcount_finalize_heaphdr(thr, hdr);
duk_heaphdr_refcount_finalize(thr, hdr);
}
hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);

224
src/duk_heap_refcount.c

@ -64,22 +64,22 @@ DUK_LOCAL void duk__refcount_finalize_hobject(duk_hthread *thr, duk_hobject *h)
if (!key) {
continue;
}
duk_heap_heaphdr_decref(thr, (duk_heaphdr *) key);
duk_heaphdr_decref(thr, (duk_heaphdr *) key);
if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h, i)) {
duk_heap_heaphdr_decref(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, h, i));
duk_heap_heaphdr_decref(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_SETTER(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_heap_tval_decref(thr, DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h, i));
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_heap_tval_decref(thr, DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, 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_heap_heaphdr_decref(thr, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h));
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;
@ -91,18 +91,18 @@ DUK_LOCAL void duk__refcount_finalize_hobject(duk_hthread *thr, duk_hobject *h)
tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, f);
tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, f);
while (tv < tv_end) {
duk_heap_tval_decref(thr, tv);
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_heap_heaphdr_decref(thr, (duk_heaphdr *) *funcs);
duk_heaphdr_decref(thr, (duk_heaphdr *) *funcs);
funcs++;
}
duk_heap_heaphdr_decref(thr, (duk_heaphdr *) DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f));
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);
@ -113,17 +113,17 @@ DUK_LOCAL void duk__refcount_finalize_hobject(duk_hthread *thr, duk_hobject *h)
tv = t->valstack;
while (tv < t->valstack_end) {
duk_heap_tval_decref(thr, tv);
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_heap_heaphdr_decref(thr, (duk_heaphdr *) DUK_ACT_GET_FUNC(act));
duk_heap_heaphdr_decref(thr, (duk_heaphdr *) act->var_env);
duk_heap_heaphdr_decref(thr, (duk_heaphdr *) act->lex_env);
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_heap_heaphdr_decref(thr, (duk_heaphdr *) act->prev_caller);
duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) act->prev_caller);
#endif
}
@ -134,14 +134,14 @@ DUK_LOCAL void duk__refcount_finalize_hobject(duk_hthread *thr, duk_hobject *h)
#endif
for (i = 0; i < DUK_NUM_BUILTINS; i++) {
duk_heap_heaphdr_decref(thr, (duk_heaphdr *) t->builtins[i]);
duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) t->builtins[i]);
}
duk_heap_heaphdr_decref(thr, (duk_heaphdr *) t->resumer);
duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) t->resumer);
}
}
DUK_INTERNAL void duk_heap_refcount_finalize_heaphdr(duk_hthread *thr, duk_heaphdr *hdr) {
DUK_INTERNAL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr) {
DUK_ASSERT(hdr);
switch ((int) DUK_HEAPHDR_GET_TYPE(hdr)) {
@ -318,88 +318,11 @@ DUK_LOCAL void duk__refzero_free_pending(duk_hthread *thr) {
*
*/
DUK_INTERNAL void duk_heap_tval_incref(duk_tval *tv) {
#if 0
DUK_DDD(DUK_DDDPRINT("tval incref %p (%ld->%ld): %!T",
(void *) tv,
(tv != NULL && DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? (long) DUK_TVAL_GET_HEAPHDR(tv)->h_refcount : (long) 0),
(tv != NULL && DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? (long) (DUK_TVAL_GET_HEAPHDR(tv)->h_refcount + 1) : (long) 0),
(duk_tval *) tv));
#endif
if (!tv) {
return;
}
if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
if (h) {
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
DUK_ASSERT_DISABLE(h->h_refcount >= 0);
DUK_HEAPHDR_PREINC_REFCOUNT(h);
}
}
}
DUK_INTERNAL void duk_heap_tval_decref(duk_hthread *thr, duk_tval *tv) {
#if 0
DUK_DDD(DUK_DDDPRINT("tval decref %p (%ld->%ld): %!T",
(void *) tv,
(tv != NULL && DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? (long) DUK_TVAL_GET_HEAPHDR(tv)->h_refcount : (long) 0),
(tv != NULL && DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? (long) (DUK_TVAL_GET_HEAPHDR(tv)->h_refcount - 1) : (long) 0),
(duk_tval *) tv));
#endif
if (!tv) {
return;
}
if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
duk_heap_heaphdr_decref(thr, DUK_TVAL_GET_HEAPHDR(tv));
}
}
DUK_INTERNAL void duk_heap_heaphdr_incref(duk_heaphdr *h) {
#if 0
DUK_DDD(DUK_DDDPRINT("heaphdr incref %p (%ld->%ld): %!O",
(void *) h,
(h != NULL ? (long) h->h_refcount : (long) 0),
(h != NULL ? (long) (h->h_refcount + 1) : (long) 0),
(duk_heaphdr *) h));
#endif
if (!h) {
return;
}
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0);
DUK_HEAPHDR_PREINC_REFCOUNT(h);
}
DUK_INTERNAL void duk_heap_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h) {
DUK_INTERNAL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h) {
duk_heap *heap;
#if 0
DUK_DDD(DUK_DDDPRINT("heaphdr decref %p (%ld->%ld): %!O",
(void *) h,
(h != NULL ? (long) h->h_refcount : (long) 0),
(h != NULL ? (long) (h->h_refcount - 1) : (long) 0),
(duk_heaphdr *) h));
#endif
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
if (!h) {
return;
}
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1);
if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) {
return;
}
DUK_ASSERT(h != NULL);
heap = thr->heap;
DUK_DDD(DUK_DDDPRINT("refzero %p: %!O", (void *) h, (duk_heaphdr *) h));
@ -463,6 +386,115 @@ DUK_INTERNAL void duk_heap_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h) {
}
}
#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
DUK_INTERNAL void duk_tval_incref(duk_tval *tv) {
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_HEAP_ALLOCATED(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_IS_HEAP_ALLOCATED(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_IS_HEAP_ALLOCATED(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_IS_HEAP_ALLOCATED(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 (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));
DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1);
if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) {
return;
}
duk_heaphdr_refzero(thr, h);
}
#else
/* no refcounting */

163
src/duk_heaphdr.h

@ -244,43 +244,138 @@ struct duk_heaphdr_string {
#if defined(DUK_USE_REFERENCE_COUNTING)
#define DUK_TVAL_INCREF(thr,tv) duk_heap_tval_incref((tv))
#define DUK_TVAL_DECREF(thr,tv) duk_heap_tval_decref((thr),(tv))
#define DUK__HEAPHDR_INCREF(thr,h) duk_heap_heaphdr_incref((h))
#define DUK__HEAPHDR_DECREF(thr,h) duk_heap_heaphdr_decref((thr),(h))
#define DUK_HEAPHDR_INCREF(thr,h) DUK__HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
#define DUK_HEAPHDR_DECREF(thr,h) DUK__HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
#define DUK_HSTRING_INCREF(thr,h) DUK__HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
#define DUK_HSTRING_DECREF(thr,h) DUK__HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
#define DUK_HOBJECT_INCREF(thr,h) DUK__HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
#define DUK_HOBJECT_DECREF(thr,h) DUK__HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
#define DUK_HBUFFER_INCREF(thr,h) DUK__HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
#define DUK_HBUFFER_DECREF(thr,h) DUK__HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
#define DUK_HCOMPILEDFUNCTION_INCREF(thr,h) DUK__HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
#define DUK_HCOMPILEDFUNCTION_DECREF(thr,h) DUK__HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
#define DUK_HNATIVEFUNCTION_INCREF(thr,h) DUK__HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
#define DUK_HNATIVEFUNCTION_DECREF(thr,h) DUK__HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
#define DUK_HTHREAD_INCREF(thr,h) DUK__HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
#define DUK_HTHREAD_DECREF(thr,h) DUK__HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
/* Fast variants, inline refcount operations except for refzero handling.
* Can be used explicitly when speed is always more important than size.
* For a good compiler and a single file build, these are basically the
* same as a forced inline.
*/
#define DUK_TVAL_INCREF_FAST(thr,tv) do { \
duk_tval *duk__tv = (tv); \
DUK_ASSERT(duk__tv != NULL); \
if (DUK_TVAL_IS_HEAP_ALLOCATED(duk__tv)) { \
duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
DUK_ASSERT(duk__h != NULL); \
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \
} \
} while (0)
#define DUK_TVAL_DECREF_FAST(thr,tv) do { \
duk_tval *duk__tv = (tv); \
DUK_ASSERT(duk__tv != NULL); \
if (DUK_TVAL_IS_HEAP_ALLOCATED(duk__tv)) { \
duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
DUK_ASSERT(duk__h != NULL); \
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
duk_heaphdr_refzero(thr, duk__h); \
} \
} \
} while (0)
#define DUK_HEAPHDR_INCREF_FAST(thr,h) do { \
duk_heaphdr *duk__h = (duk_heaphdr *) (h); \
DUK_ASSERT(duk__h != NULL); \
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \
} while (0)
#define DUK_HEAPHDR_DECREF_FAST(thr,h) do { \
duk_heaphdr *duk__h = (duk_heaphdr *) (h); \
DUK_ASSERT(duk__h != NULL); \
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
duk_heaphdr_refzero(thr, duk__h); \
} \
} while (0)
/* Slow variants, call to a helper to reduce code size.
* Can be used explicitly when size is always more important than speed.
*/
#define DUK_TVAL_INCREF_SLOW(thr,tv) do { \
duk_tval_incref((tv)); \
} while (0)
#define DUK_TVAL_DECREF_SLOW(thr,tv) do { \
duk_tval_decref((thr), (tv)); \
} while (0)
#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do { \
duk_heaphdr_incref((duk_heaphdr *) (h)); \
} while (0)
#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do { \
duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); \
} while (0)
/* Default variants. Selection depends on speed/size preference.
* Concretely: with gcc 4.8.1 -Os x64 the difference in final binary
* is about +1kB for _FAST variants.
*/
#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_FAST((thr),(tv))
#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_FAST((thr),(tv))
#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_FAST((thr),(h))
#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST((thr),(h))
#else
#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_SLOW((thr),(tv))
#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_SLOW((thr),(tv))
#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_SLOW((thr),(h))
#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_SLOW((thr),(h))
#endif
/* Casting convenience. */
#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
#define DUK_HSTRING_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
#define DUK_HOBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
#define DUK_HBUFFER_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
#define DUK_HCOMPILEDFUNCTION_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
#define DUK_HCOMPILEDFUNCTION_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
#define DUK_HNATIVEFUNCTION_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
#define DUK_HNATIVEFUNCTION_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
#define DUK_HTHREAD_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
/* Convenience for some situations; the above macros don't allow NULLs
* for performance reasons.
*/
#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \
if ((h) != NULL) { \
DUK_HEAPHDR_INCREF((thr), (duk_heaphdr *) (h)); \
} \
} while (0)
#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \
if ((h) != NULL) { \
DUK_HEAPHDR_DECREF((thr), (duk_heaphdr *) (h)); \
} \
} while (0)
#else /* DUK_USE_REFERENCE_COUNTING */
#define DUK_TVAL_INCREF(thr,v) /* nop */
#define DUK_TVAL_DECREF(thr,v) /* nop */
#define DUK_HEAPHDR_INCREF(thr,h) /* nop */
#define DUK_HEAPHDR_DECREF(thr,h) /* nop */
#define DUK_HSTRING_INCREF(thr,h) /* nop */
#define DUK_HSTRING_DECREF(thr,h) /* nop */
#define DUK_HOBJECT_INCREF(thr,h) /* nop */
#define DUK_HOBJECT_DECREF(thr,h) /* nop */
#define DUK_HBUFFER_INCREF(thr,h) /* nop */
#define DUK_HBUFFER_DECREF(thr,h) /* nop */
#define DUK_HCOMPILEDFUNCTION_INCREF(thr,h) /* nop */
#define DUK_HCOMPILEDFUNCTION_DECREF(thr,h) /* nop */
#define DUK_HNATIVEFUNCTION_INCREF(thr,h) /* nop */
#define DUK_HNATIVEFUNCTION_DECREF(thr,h) /* nop */
#define DUK_HTHREAD_INCREF(thr,h) /* nop */
#define DUK_HTHREAD_DECREF(thr,h) /* nop */
#define DUK_TVAL_INCREF_FAST(thr,v) do {} while (0) /* nop */
#define DUK_TVAL_DECREF_FAST(thr,v) do {} while (0) /* nop */
#define DUK_TVAL_INCREF_SLOW(thr,v) do {} while (0) /* nop */
#define DUK_TVAL_DECREF_SLOW(thr,v) do {} while (0) /* nop */
#define DUK_TVAL_INCREF(thr,v) do {} while (0) /* nop */
#define DUK_TVAL_DECREF(thr,v) do {} while (0) /* nop */
#define DUK_HEAPHDR_INCREF_FAST(thr,h) do {} while (0) /* nop */
#define DUK_HEAPHDR_DECREF_FAST(thr,h) do {} while (0) /* nop */
#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do {} while (0) /* nop */
#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do {} while (0) /* nop */
#define DUK_HEAPHDR_INCREF(thr,h) do {} while (0) /* nop */
#define DUK_HEAPHDR_DECREF(thr,h) do {} while (0) /* nop */
#define DUK_HSTRING_INCREF(thr,h) do {} while (0) /* nop */
#define DUK_HSTRING_DECREF(thr,h) do {} while (0) /* nop */
#define DUK_HOBJECT_INCREF(thr,h) do {} while (0) /* nop */
#define DUK_HOBJECT_DECREF(thr,h) do {} while (0) /* nop */
#define DUK_HBUFFER_INCREF(thr,h) do {} while (0) /* nop */
#define DUK_HBUFFER_DECREF(thr,h) do {} while (0) /* nop */
#define DUK_HCOMPILEDFUNCTION_INCREF(thr,h) do {} while (0) /* nop */
#define DUK_HCOMPILEDFUNCTION_DECREF(thr,h) do {} while (0) /* nop */
#define DUK_HNATIVEFUNCTION_INCREF(thr,h) do {} while (0) /* nop */
#define DUK_HNATIVEFUNCTION_DECREF(thr,h) do {} while (0) /* nop */
#define DUK_HTHREAD_INCREF(thr,h) do {} while (0) /* nop */
#define DUK_HTHREAD_DECREF(thr,h) do {} while (0) /* nop */
#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
#endif /* DUK_USE_REFERENCE_COUNTING */

4
src/duk_hobject_misc.c

@ -37,8 +37,8 @@ DUK_INTERNAL void duk_hobject_set_prototype(duk_hthread *thr, duk_hobject *h, du
DUK_ASSERT(h);
tmp = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p);
DUK_HOBJECT_INCREF(thr, p); /* avoid problems if p == h->prototype */
DUK_HOBJECT_DECREF(thr, tmp);
DUK_HOBJECT_INCREF_ALLOWNULL(thr, p); /* avoid problems if p == h->prototype */
DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
#else
DUK_ASSERT(h);
DUK_UNREF(thr);

24
src/duk_hobject_props.c

@ -3828,12 +3828,12 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *o
tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, desc.e_idx);
DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, desc.e_idx, NULL);
DUK_UNREF(tmp);
DUK_HOBJECT_DECREF(thr, tmp);
DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, desc.e_idx);
DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, desc.e_idx, NULL);
DUK_UNREF(tmp);
DUK_HOBJECT_DECREF(thr, tmp);
DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
} else {
tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
DUK_TVAL_SET_TVAL(&tv_tmp, tv);
@ -4316,8 +4316,8 @@ DUK_INTERNAL void duk_hobject_define_accessor_internal(duk_hthread *thr, duk_hob
DUK_HOBJECT_E_SLOT_SET_ACCESSOR(thr->heap, obj, e_idx);
DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, e_idx, getter);
DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, e_idx, setter);
DUK_HOBJECT_INCREF(thr, getter);
DUK_HOBJECT_INCREF(thr, setter);
DUK_HOBJECT_INCREF_ALLOWNULL(thr, getter);
DUK_HOBJECT_INCREF_ALLOWNULL(thr, setter);
}
/*
@ -4810,8 +4810,8 @@ void duk_hobject_define_property_helper(duk_context *ctx,
DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, e_idx, get);
DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, e_idx, set);
DUK_HOBJECT_INCREF(thr, get);
DUK_HOBJECT_INCREF(thr, set);
DUK_HOBJECT_INCREF_ALLOWNULL(thr, get);
DUK_HOBJECT_INCREF_ALLOWNULL(thr, set);
DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, new_flags);
goto success_exotics;
@ -5073,11 +5073,11 @@ void duk_hobject_define_property_helper(duk_context *ctx,
tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx);
DUK_UNREF(tmp);
DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL);
DUK_HOBJECT_DECREF(thr, tmp);
DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx);
DUK_UNREF(tmp);
DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL);
DUK_HOBJECT_DECREF(thr, tmp);
DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
DUK_TVAL_SET_UNDEFINED_ACTUAL(DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx));
DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx);
@ -5208,8 +5208,8 @@ void duk_hobject_define_property_helper(duk_context *ctx,
tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx);
DUK_UNREF(tmp);
DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, set);
DUK_HOBJECT_INCREF(thr, set);
DUK_HOBJECT_DECREF(thr, tmp);
DUK_HOBJECT_INCREF_ALLOWNULL(thr, set);
DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
}
if (has_get) {
duk_hobject *tmp;
@ -5220,8 +5220,8 @@ void duk_hobject_define_property_helper(duk_context *ctx,
tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx);
DUK_UNREF(tmp);
DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, get);
DUK_HOBJECT_INCREF(thr, get);
DUK_HOBJECT_DECREF(thr, tmp);
DUK_HOBJECT_INCREF_ALLOWNULL(thr, get);
DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
}
if (has_value) {
duk_tval *tv1, *tv2;

2
src/duk_hthread_builtins.c

@ -666,6 +666,6 @@ DUK_INTERNAL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_ht
for (i = 0; i < DUK_NUM_BUILTINS; i++) {
thr_to->builtins[i] = thr_from->builtins[i];
DUK_HOBJECT_INCREF(thr_to, thr_to->builtins[i]); /* side effect free */
DUK_HOBJECT_INCREF_ALLOWNULL(thr_to, thr_to->builtins[i]); /* side effect free */
}
}

6
src/duk_hthread_stacks.c

@ -282,7 +282,7 @@ DUK_INTERNAL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_
#endif
act->var_env = NULL;
#ifdef DUK_USE_REFERENCE_COUNTING
DUK_HOBJECT_DECREF(thr, tmp);
DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
act = thr->callstack + idx; /* avoid side effect issues */
#endif
@ -291,7 +291,7 @@ DUK_INTERNAL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_
#endif
act->lex_env = NULL;
#ifdef DUK_USE_REFERENCE_COUNTING
DUK_HOBJECT_DECREF(thr, tmp);
DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
act = thr->callstack + idx; /* avoid side effect issues */
#endif
@ -303,7 +303,7 @@ DUK_INTERNAL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_
#endif
act->func = NULL;
#ifdef DUK_USE_REFERENCE_COUNTING
DUK_HOBJECT_DECREF(thr, tmp);
DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
act = thr->callstack + idx; /* avoid side effect issues */
DUK_UNREF(act);
#endif

6
src/duk_js_call.c

@ -467,8 +467,8 @@ void duk__handle_oldenv_for_call(duk_hthread *thr,
act->var_env = act->lex_env;
}
DUK_HOBJECT_INCREF(thr, act->lex_env);
DUK_HOBJECT_INCREF(thr, act->var_env);
DUK_HOBJECT_INCREF_ALLOWNULL(thr, act->lex_env);
DUK_HOBJECT_INCREF_ALLOWNULL(thr, act->var_env);
}
/*
@ -1201,7 +1201,7 @@ duk_int_t duk_handle_call(duk_hthread *thr,
* reference reachable through the value stack? If changed, stack
* unwind code also needs to be fixed to match.
*/
DUK_HOBJECT_INCREF(thr, func); /* act->func */
DUK_HOBJECT_INCREF_ALLOWNULL(thr, func); /* act->func */
#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
if (func) {

4
src/duk_js_var.c

@ -1671,11 +1671,11 @@ duk_bool_t duk__declvar_helper(duk_hthread *thr,
tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, holder, e_idx);
DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, holder, e_idx, NULL);
DUK_HOBJECT_DECREF(thr, tmp);
DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
DUK_UNREF(tmp);
tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, holder, e_idx);
DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, holder, e_idx, NULL);
DUK_HOBJECT_DECREF(thr, tmp);
DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
DUK_UNREF(tmp);
} else {
duk_tval tv_tmp;

Loading…
Cancel
Save