diff --git a/src/duk_features.h.in b/src/duk_features.h.in index 0e7a9917..2c744ebc 100644 --- a/src/duk_features.h.in +++ b/src/duk_features.h.in @@ -2521,16 +2521,20 @@ typedef FILE duk_file; */ #undef DUK_USE_HSTRING_EXTDATA -#undef DUK_USE_EXTSTR_INTERN_CHECK - #if defined(DUK_OPT_EXTERNAL_STRINGS) #define DUK_USE_HSTRING_EXTDATA #endif +#undef DUK_USE_EXTSTR_INTERN_CHECK #if defined(DUK_OPT_EXTERNAL_STRINGS) && defined(DUK_OPT_EXTSTR_INTERN_CHECK) #define DUK_USE_EXTSTR_INTERN_CHECK(ptr,len) DUK_OPT_EXTSTR_INTERN_CHECK((ptr), (len)) #endif +#undef DUK_USE_EXTSTR_FREE +#if defined(DUK_OPT_EXTERNAL_STRINGS) && defined(DUK_OPT_EXTSTR_FREE) +#define DUK_USE_EXTSTR_FREE(ptr) DUK_OPT_EXTSTR_FREE((ptr)) +#endif + /* * Lightweight functions */ diff --git a/src/duk_heap.h b/src/duk_heap.h index 1ff55e67..38355715 100644 --- a/src/duk_heap.h +++ b/src/duk_heap.h @@ -402,6 +402,9 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, void *alloc_udata, duk_fatal_function fatal_func); DUK_INTERNAL_DECL void duk_heap_free(duk_heap *heap); +DUK_INTERNAL_DECL void duk_free_hobject_inner(duk_heap *heap, duk_hobject *h); +DUK_INTERNAL_DECL void duk_free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h); +DUK_INTERNAL_DECL void duk_free_hstring_inner(duk_heap *heap, duk_hstring *h); DUK_INTERNAL_DECL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr); DUK_INTERNAL_DECL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr); diff --git a/src/duk_heap_alloc.c b/src/duk_heap_alloc.c index 9eb1369b..db35ed0f 100644 --- a/src/duk_heap_alloc.c +++ b/src/duk_heap_alloc.c @@ -21,7 +21,7 @@ * been already dealt with. */ -DUK_LOCAL void duk__free_hobject_inner(duk_heap *heap, duk_hobject *h) { +DUK_INTERNAL void duk_free_hobject_inner(duk_heap *heap, duk_hobject *h) { DUK_ASSERT(heap != NULL); DUK_ASSERT(h != NULL); @@ -52,7 +52,7 @@ DUK_LOCAL void duk__free_hobject_inner(duk_heap *heap, duk_hobject *h) { } } -DUK_LOCAL void duk__free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h) { +DUK_INTERNAL void duk_free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h) { DUK_ASSERT(heap != NULL); DUK_ASSERT(h != NULL); @@ -63,6 +63,22 @@ DUK_LOCAL void duk__free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h) { } } +DUK_INTERNAL void duk_free_hstring_inner(duk_heap *heap, duk_hstring *h) { + DUK_ASSERT(heap != NULL); + DUK_ASSERT(h != NULL); + + DUK_UNREF(heap); + DUK_UNREF(h); + +#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_FREE) + if (DUK_HSTRING_HAS_EXTDATA(h)) { + DUK_DDD(DUK_DDDPRINT("free extstr: hstring %!O, extdata: %p", + h, DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h))); + DUK_USE_EXTSTR_FREE((const void *) DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h)); + } +#endif +} + DUK_INTERNAL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr) { DUK_ASSERT(heap); DUK_ASSERT(hdr); @@ -71,13 +87,13 @@ DUK_INTERNAL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr) { switch ((int) DUK_HEAPHDR_GET_TYPE(hdr)) { case DUK_HTYPE_STRING: - /* no inner refs to free */ + duk_free_hstring_inner(heap, (duk_hstring *) hdr); break; case DUK_HTYPE_OBJECT: - duk__free_hobject_inner(heap, (duk_hobject *) hdr); + duk_free_hobject_inner(heap, (duk_hobject *) hdr); break; case DUK_HTYPE_BUFFER: - duk__free_hbuffer_inner(heap, (duk_hbuffer *) hdr); + duk_free_hbuffer_inner(heap, (duk_hbuffer *) hdr); break; default: DUK_UNREACHABLE(); @@ -165,11 +181,14 @@ DUK_LOCAL void duk__free_stringtable(duk_heap *heap) { #else e = heap->strtable[i]; #endif - if (e == DUK_STRTAB_DELETED_MARKER(heap)) { + if (e == NULL || e == DUK_STRTAB_DELETED_MARKER(heap)) { continue; } + DUK_ASSERT(e != NULL); + + /* strings may have inner refs (extdata) in some cases */ + duk_free_hstring_inner(heap, (duk_hstring *) e); - /* strings have no inner allocations so free directly */ DUK_DDD(DUK_DDDPRINT("FINALFREE (string): %!iO", (duk_heaphdr *) e)); DUK_FREE(heap, e); diff --git a/src/duk_heap_markandsweep.c b/src/duk_heap_markandsweep.c index f05ef19a..b8c9efeb 100644 --- a/src/duk_heap_markandsweep.c +++ b/src/duk_heap_markandsweep.c @@ -558,12 +558,13 @@ DUK_LOCAL void duk__sweep_stringtable(duk_heap *heap, duk_size_t *out_count_keep heap->strtable[i] = DUK_STRTAB_DELETED_MARKER(heap); #endif - /* then free */ -#if 1 - DUK_FREE(heap, (duk_heaphdr *) h); /* no inner refs/allocs, just free directly */ -#else - duk_heap_free_heaphdr_raw(heap, (duk_heaphdr *) h); /* this would be OK but unnecessary */ -#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, (duk_heaphdr *) h); } #ifdef DUK_USE_DEBUG diff --git a/src/duk_hstring.h b/src/duk_hstring.h index ce05704e..5d00f6f6 100644 --- a/src/duk_hstring.h +++ b/src/duk_hstring.h @@ -102,8 +102,11 @@ #endif #if defined(DUK_USE_HSTRING_EXTDATA) +#define DUK_HSTRING_GET_EXTDATA(x) \ + ((x)->extdata) #define DUK_HSTRING_GET_DATA(x) \ - (DUK_HSTRING_HAS_EXTDATA((x)) ? ((duk_hstring_external *) (x))->extdata : ((const duk_uint8_t *) ((x) + 1))) + (DUK_HSTRING_HAS_EXTDATA((x)) ? \ + DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) (x)) : ((const duk_uint8_t *) ((x) + 1))) #else #define DUK_HSTRING_GET_DATA(x) \ ((const duk_uint8_t *) ((x) + 1))