187 lines
5.1 KiB
C
187 lines
5.1 KiB
C
/*
|
|
* Support functions for duk_heap.
|
|
*/
|
|
|
|
#include "duk_internal.h"
|
|
|
|
DUK_INTERNAL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
|
|
duk_heaphdr *root;
|
|
|
|
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
|
|
|
|
root = heap->heap_allocated;
|
|
#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
|
|
if (root != NULL) {
|
|
DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, root) == NULL);
|
|
DUK_HEAPHDR_SET_PREV(heap, root, hdr);
|
|
}
|
|
DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
|
|
#endif
|
|
DUK_HEAPHDR_SET_NEXT(heap, hdr, root);
|
|
DUK_HEAPHDR_ASSERT_LINKS(heap, hdr);
|
|
DUK_HEAPHDR_ASSERT_LINKS(heap, root);
|
|
heap->heap_allocated = hdr;
|
|
}
|
|
|
|
#if defined(DUK_USE_REFERENCE_COUNTING)
|
|
DUK_INTERNAL void duk_heap_remove_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
|
|
duk_heaphdr *prev;
|
|
duk_heaphdr *next;
|
|
|
|
/* Strings are in string table. */
|
|
DUK_ASSERT(hdr != NULL);
|
|
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
|
|
|
|
/* Target 'hdr' must be in heap_allocated (not e.g. finalize_list).
|
|
* If not, heap lists will become corrupted so assert early for it.
|
|
*/
|
|
#if defined(DUK_USE_ASSERTIONS)
|
|
{
|
|
duk_heaphdr *tmp;
|
|
for (tmp = heap->heap_allocated; tmp != NULL; tmp = DUK_HEAPHDR_GET_NEXT(heap, tmp)) {
|
|
if (tmp == hdr) {
|
|
break;
|
|
}
|
|
}
|
|
DUK_ASSERT(tmp == hdr);
|
|
}
|
|
#endif
|
|
|
|
/* Read/write only once to minimize pointer compression calls. */
|
|
prev = DUK_HEAPHDR_GET_PREV(heap, hdr);
|
|
next = DUK_HEAPHDR_GET_NEXT(heap, hdr);
|
|
|
|
if (prev != NULL) {
|
|
DUK_ASSERT(heap->heap_allocated != hdr);
|
|
DUK_HEAPHDR_SET_NEXT(heap, prev, next);
|
|
} else {
|
|
DUK_ASSERT(heap->heap_allocated == hdr);
|
|
heap->heap_allocated = next;
|
|
}
|
|
if (next != NULL) {
|
|
DUK_HEAPHDR_SET_PREV(heap, next, prev);
|
|
} else {
|
|
;
|
|
}
|
|
}
|
|
#endif /* DUK_USE_REFERENCE_COUNTING */
|
|
|
|
#if defined(DUK_USE_FINALIZER_SUPPORT)
|
|
DUK_INTERNAL void duk_heap_insert_into_finalize_list(duk_heap *heap, duk_heaphdr *hdr) {
|
|
duk_heaphdr *root;
|
|
|
|
root = heap->finalize_list;
|
|
#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
|
|
DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
|
|
if (root != NULL) {
|
|
DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, root) == NULL);
|
|
DUK_HEAPHDR_SET_PREV(heap, root, hdr);
|
|
}
|
|
#endif
|
|
DUK_HEAPHDR_SET_NEXT(heap, hdr, root);
|
|
DUK_HEAPHDR_ASSERT_LINKS(heap, hdr);
|
|
DUK_HEAPHDR_ASSERT_LINKS(heap, root);
|
|
heap->finalize_list = hdr;
|
|
}
|
|
#endif /* DUK_USE_FINALIZER_SUPPORT */
|
|
|
|
#if defined(DUK_USE_FINALIZER_SUPPORT)
|
|
DUK_INTERNAL void duk_heap_remove_from_finalize_list(duk_heap *heap, duk_heaphdr *hdr) {
|
|
#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
|
|
duk_heaphdr *next;
|
|
duk_heaphdr *prev;
|
|
|
|
next = DUK_HEAPHDR_GET_NEXT(heap, hdr);
|
|
prev = DUK_HEAPHDR_GET_PREV(heap, hdr);
|
|
if (next != NULL) {
|
|
DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, next) == hdr);
|
|
DUK_HEAPHDR_SET_PREV(heap, next, prev);
|
|
}
|
|
if (prev == NULL) {
|
|
DUK_ASSERT(hdr == heap->finalize_list);
|
|
heap->finalize_list = next;
|
|
} else {
|
|
DUK_ASSERT(hdr != heap->finalize_list);
|
|
DUK_HEAPHDR_SET_NEXT(heap, prev, next);
|
|
}
|
|
#else
|
|
duk_heaphdr *next;
|
|
duk_heaphdr *curr;
|
|
|
|
/* Random removal is expensive: we need to locate the previous element
|
|
* because we don't have a 'prev' pointer.
|
|
*/
|
|
curr = heap->finalize_list;
|
|
if (curr == hdr) {
|
|
heap->finalize_list = DUK_HEAPHDR_GET_NEXT(heap, curr);
|
|
} else {
|
|
DUK_ASSERT(hdr != heap->finalize_list);
|
|
for (;;) {
|
|
DUK_ASSERT(curr != NULL); /* Caller responsibility. */
|
|
|
|
next = DUK_HEAPHDR_GET_NEXT(heap, curr);
|
|
if (next == hdr) {
|
|
next = DUK_HEAPHDR_GET_NEXT(heap, hdr);
|
|
DUK_HEAPHDR_SET_NEXT(heap, curr, next);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
#endif /* DUK_USE_FINALIZER_SUPPORT */
|
|
|
|
#if defined(DUK_USE_ASSERTIONS)
|
|
DUK_INTERNAL duk_bool_t duk_heap_in_heap_allocated(duk_heap *heap, duk_heaphdr *ptr) {
|
|
duk_heaphdr *curr;
|
|
DUK_ASSERT(heap != NULL);
|
|
|
|
for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) {
|
|
if (curr == ptr) {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
#endif /* DUK_USE_ASSERTIONS */
|
|
|
|
#if defined(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 */
|
|
|
|
#if defined(DUK_USE_ASSERTIONS)
|
|
DUK_INTERNAL void duk_heap_assert_valid(duk_heap *heap) {
|
|
DUK_ASSERT(heap != NULL);
|
|
}
|
|
#endif
|