Browse Source

Merge pull request #936 from svaarala/optional-finalizer-support

Make finalizer support optional
pull/957/head
Sami Vaarala 8 years ago
committed by GitHub
parent
commit
5b49146b75
  1. 3
      RELEASES.rst
  2. 2
      config/config-options/DUK_USE_COROUTINE_SUPPORT.yaml
  3. 7
      config/config-options/DUK_USE_FINALIZER_SUPPORT.yaml
  4. 3
      config/examples/low_memory_strip.yaml
  5. 14
      src-input/duk_api_object.c
  6. 6
      src-input/duk_bi_duktape.c
  7. 4
      src-input/duk_heap_alloc.c
  8. 20
      src-input/duk_heap_markandsweep.c
  9. 30
      src-input/duk_heap_refcount.c
  10. 2
      src-input/duk_hobject.h
  11. 2
      src-input/duk_hobject_finalizer.c

3
RELEASES.rst

@ -1814,6 +1814,9 @@ Planned
* Make coroutine support optional (DUK_USE_COROUTINE_SUPPORT); disabling
coroutines reduces code footprint by about 2kB (GH-829)
* Make finalizer support optional (DUK_USE_FINALIZER_SUPPORT); disabling
coroutines reduces code footprint by about 0.8kB (GH-936)
* Add an internal type for representing Array instances (duk_harray) to
simplify array operations and improve performance; this also changes the
key order of Object.getOwnPropertyNames() for sparse arrays (arrays whose

2
config/config-options/DUK_USE_COROUTINE_SUPPORT.yaml

@ -4,4 +4,4 @@ default: true
tags:
- execution
description: >
Enable support Duktape coroutines, i.e. yield/resume.
Enable support for Duktape coroutines, i.e. yield/resume.

7
config/config-options/DUK_USE_FINALIZER_SUPPORT.yaml

@ -0,0 +1,7 @@
define: DUK_USE_FINALIZER_SUPPORT
introduced: 2.0.0
default: true
tags:
- execution
description: >
Enable support for object finalizers (Duktape specific).

3
config/examples/low_memory_strip.yaml

@ -18,6 +18,9 @@ DUK_USE_REGEXP_CANON_WORKAROUND: false
# Coroutine support has about 2kB footprint.
DUK_USE_COROUTINE_SUPPORT: false
# Finalizer support has about 0.8kB footprint.
DUK_USE_FINALIZER_SUPPORT: false
# ES6 Proxy has about 2kB footprint.
DUK_USE_ES6_PROXY: false

14
src-input/duk_api_object.c

@ -651,6 +651,7 @@ DUK_EXTERNAL void duk_set_prototype(duk_context *ctx, duk_idx_t idx) {
* Object finalizer
*/
#if defined(DUK_USE_FINALIZER_SUPPORT)
/* XXX: these could be implemented as macros calling an internal function
* directly.
* XXX: same issue as with Duktape.fin: there's no way to delete the property
@ -667,3 +668,16 @@ DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t idx) {
duk_put_prop_stridx(ctx, idx, DUK_STRIDX_INT_FINALIZER);
}
#else /* DUK_USE_FINALIZER_SUPPORT */
DUK_EXTERNAL void duk_get_finalizer(duk_context *ctx, duk_idx_t idx) {
DUK_ASSERT_CTX_VALID(ctx);
DUK_UNREF(idx);
DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
}
DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t idx) {
DUK_ASSERT_CTX_VALID(ctx);
DUK_UNREF(idx);
DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
}
#endif /* DUK_USE_FINALIZER_SUPPORT */

6
src-input/duk_bi_duktape.c

@ -203,6 +203,7 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx) {
#endif
}
#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx) {
(void) duk_require_hobject(ctx, 0);
if (duk_get_top(ctx) >= 2) {
@ -222,6 +223,11 @@ DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx) {
return 1;
}
}
#else /* DUK_USE_FINALIZER_SUPPORT */
DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx) {
DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
}
#endif /* DUK_USE_FINALIZER_SUPPORT */
DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) {
duk_hthread *thr = (duk_hthread *) ctx;

4
src-input/duk_heap_alloc.c

@ -175,6 +175,7 @@ DUK_LOCAL void duk__free_stringtable(duk_heap *heap) {
duk_heap_free_strtab(heap);
}
#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) {
duk_hthread *thr;
duk_heaphdr *curr;
@ -268,6 +269,7 @@ DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) {
DUK_ASSERT(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap);
}
#endif /* DUK_USE_FINALIZER_SUPPORT */
DUK_INTERNAL void duk_heap_free(duk_heap *heap) {
DUK_D(DUK_DPRINT("free heap: %p", (void *) heap));
@ -313,8 +315,10 @@ DUK_INTERNAL void duk_heap_free(duk_heap *heap) {
duk_heap_mark_and_sweep(heap, DUK_MS_FLAG_SKIP_FINALIZERS); /* skip finalizers; queue finalizable objects to heap_allocated */
#endif
#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* rescue no longer supported */
duk__free_run_finalizers(heap);
#endif /* DUK_USE_FINALIZER_SUPPORT */
/* Note: heap->heap_thread, heap->curr_thread, and heap->heap_object
* are on the heap allocated list.

20
src-input/duk_heap_markandsweep.c

@ -264,6 +264,7 @@ DUK_LOCAL void duk__mark_refzero_list(duk_heap *heap) {
* roots; otherwise circular references might be handled inconsistently.
*/
#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_LOCAL void duk__mark_finalizable(duk_heap *heap) {
duk_hthread *thr;
duk_heaphdr *hdr;
@ -324,12 +325,14 @@ DUK_LOCAL void duk__mark_finalizable(duk_heap *heap) {
/* Caller will finish the marking process if we hit a recursion limit. */
}
#endif /* DUK_USE_FINALIZER_SUPPORT */
/*
* Mark objects on finalize_list.
*
*/
#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_LOCAL void duk__mark_finalize_list(duk_heap *heap) {
duk_heaphdr *hdr;
#ifdef DUK_USE_DEBUG
@ -354,6 +357,7 @@ DUK_LOCAL void duk__mark_finalize_list(duk_heap *heap) {
}
#endif
}
#endif /* DUK_USE_FINALIZER_SUPPORT */
/*
* Fallback marking handler if recursion limit is reached.
@ -443,7 +447,6 @@ DUK_LOCAL void duk__mark_temproots_by_heap_scan(duk_heap *heap) {
* 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;
@ -474,7 +477,6 @@ DUK_LOCAL void duk__finalize_refcounts(duk_heap *heap) {
hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
}
}
#endif /* DUK_USE_REFERENCE_COUNTING */
/*
* Clear (reachable) flags of refzero work list.
@ -508,6 +510,7 @@ DUK_LOCAL void duk__clear_refzero_list_flags(duk_heap *heap) {
* here. (This now overlaps with the sweep handling in a harmless way.)
*/
#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_LOCAL void duk__clear_finalize_list_flags(duk_heap *heap) {
duk_heaphdr *hdr;
@ -522,6 +525,7 @@ DUK_LOCAL void duk__clear_finalize_list_flags(duk_heap *heap) {
hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
}
}
#endif /* DUK_USE_FINALIZER_SUPPORT */
/*
* Sweep stringtable
@ -874,6 +878,7 @@ DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_
* Run (object) finalizers in the "to be finalized" work list.
*/
#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_LOCAL void duk__run_object_finalizers(duk_heap *heap, duk_small_uint_t flags) {
duk_heaphdr *curr;
duk_heaphdr *next;
@ -932,6 +937,7 @@ DUK_LOCAL void duk__run_object_finalizers(duk_heap *heap, duk_small_uint_t flags
DUK_D(DUK_DPRINT("mark-and-sweep finalize objects: %ld finalizers called", (long) count));
#endif
}
#endif /* DUK_USE_FINALIZER_SUPPORT */
/*
* Object compaction.
@ -1102,6 +1108,7 @@ DUK_LOCAL void duk__assert_valid_refcounts(duk_heap *heap) {
* similar to one or more finalizers on actual objects.
*/
#if defined(DUK_USE_FINALIZER_SUPPORT)
#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"));
@ -1142,6 +1149,7 @@ DUK_LOCAL void duk__markandsweep_torture_finalizer(duk_hthread *thr) {
duk_pop(ctx);
}
#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */
#endif /* DUK_USE_FINALIZER_SUPPORT */
/*
* Main mark-and-sweep function.
@ -1246,8 +1254,10 @@ DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t
#endif
duk__mark_temproots_by_heap_scan(heap); /* temproots */
#if defined(DUK_USE_FINALIZER_SUPPORT)
duk__mark_finalizable(heap); /* mark finalizable as reachability roots */
duk__mark_finalize_list(heap); /* mark finalizer work list as reachability roots */
#endif
duk__mark_temproots_by_heap_scan(heap); /* temproots */
/*
@ -1277,10 +1287,12 @@ DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t
#else
#error internal error, invalid strtab options
#endif
#ifdef DUK_USE_REFERENCE_COUNTING
#if defined(DUK_USE_REFERENCE_COUNTING)
duk__clear_refzero_list_flags(heap);
#endif
#if defined(DUK_USE_FINALIZER_SUPPORT)
duk__clear_finalize_list_flags(heap);
#endif
/*
* Object compaction (emergency only).
@ -1354,6 +1366,7 @@ DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t
* already happened, this is probably good enough for now.
*/
#if defined(DUK_USE_FINALIZER_SUPPORT)
#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE)
/* Cannot simulate individual finalizers because finalize_list only
* contains objects with actual finalizers. But simulate side effects
@ -1375,6 +1388,7 @@ DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t
} else {
duk__run_object_finalizers(heap, flags);
}
#endif /* DUK_USE_FINALIZER_SUPPORT */
/*
* Finish

30
src-input/duk_heap_refcount.c

@ -174,6 +174,7 @@ DUK_INTERNAL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *h
}
}
#if defined(DUK_USE_FINALIZER_SUPPORT)
#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE)
DUK_LOCAL duk_ret_t duk__refcount_fake_finalizer(duk_context *ctx) {
DUK_UNREF(ctx);
@ -227,6 +228,7 @@ DUK_LOCAL void duk__refcount_run_torture_finalizer(duk_hthread *thr, duk_hobject
duk_pop(ctx);
}
#endif /* DUK_USE_REFZERO_FINALIZER_TORTURE */
#endif /* DUK_USE_FINALIZER_SUPPORT */
/*
* Refcount memory freeing loop.
@ -265,7 +267,9 @@ DUK_LOCAL void duk__refzero_free_pending(duk_hthread *thr) {
DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap);
while (heap->refzero_list) {
duk_hobject *obj;
#if defined(DUK_USE_FINALIZER_SUPPORT)
duk_bool_t rescued = 0;
#endif /* DUK_USE_FINALIZER_SUPPORT */
/*
* Pick an object from the head (don't remove yet).
@ -277,6 +281,7 @@ DUK_LOCAL void duk__refzero_free_pending(duk_hthread *thr) {
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_FINALIZER_SUPPORT)
#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,
@ -289,7 +294,8 @@ DUK_LOCAL void duk__refzero_free_pending(duk_hthread *thr) {
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
#endif /* DUK_USE_REFZERO_FINALIZER_TORTURE */
#endif /* DUK_USE_FINALIZER_SUPPORT */
/*
* Finalizer check.
@ -300,16 +306,16 @@ DUK_LOCAL void duk__refzero_free_pending(duk_hthread *thr) {
*
* 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).
*/
/* 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 defined(DUK_USE_FINALIZER_SUPPORT)
if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
DUK_DDD(DUK_DDDPRINT("object has a finalizer, run it"));
@ -329,6 +335,7 @@ DUK_LOCAL void duk__refzero_free_pending(duk_hthread *thr) {
DUK_DDD(DUK_DDDPRINT("-> object refcount still zero after finalization, object will be freed"));
}
}
#endif /* DUK_USE_FINALIZER_SUPPORT */
/* Refzero head is still the same. This is the case even if finalizer
* inserted more refzero objects; they are inserted to the tail.
@ -355,6 +362,7 @@ DUK_LOCAL void duk__refzero_free_pending(duk_hthread *thr) {
* Rescue or free.
*/
#if defined(DUK_USE_FINALIZER_SUPPORT)
if (rescued) {
/* yes -> move back to heap allocated */
DUK_DD(DUK_DDPRINT("object rescued during refcount finalization: %p", (void *) h1));
@ -370,7 +378,9 @@ DUK_LOCAL void duk__refzero_free_pending(duk_hthread *thr) {
DUK_ASSERT_HEAPHDR_LINKS(heap, h1);
DUK_ASSERT_HEAPHDR_LINKS(heap, h2);
heap->heap_allocated = h1;
} else {
} else
#endif /* DUK_USE_FINALIZER_SUPPORT */
{
/* no -> decref members, then free */
duk__refcount_finalize_hobject(thr, obj);
duk_heap_free_heaphdr_raw(heap, h1);

2
src-input/duk_hobject.h

@ -939,7 +939,9 @@ DUK_INTERNAL_DECL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_b
DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p);
/* finalization */
#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_INTERNAL_DECL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj);
#endif
/* pc2line */
#if defined(DUK_USE_PC2LINE)

2
src-input/duk_hobject_finalizer.c

@ -17,6 +17,7 @@
#include "duk_internal.h"
#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_LOCAL duk_ret_t duk__finalize_helper(duk_context *ctx, void *udata) {
duk_hthread *thr;
@ -109,3 +110,4 @@ DUK_INTERNAL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj)
DUK_ASSERT_TOP(ctx, entry_top);
}
#endif /* DUK_USE_FINALIZER_SUPPORT */

Loading…
Cancel
Save