/* FIXME: unused now, remove */ duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, int hobject_flags) { duk_hobject *res = duk_hobject_alloc(thr->heap, hobject_flags); if (!res) { DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "failed to allocate an object"); } return res; }
/* when nothing is running, API calls are in non-strict mode */ DUK_ASSERT(res->strict == 0); res->heap = heap; res->valstack_max = DUK_VALSTACK_DEFAULT_MAX; res->callstack_max = DUK_CALLSTACK_DEFAULT_MAX; res->catchstack_max = DUK_CATCHSTACK_DEFAULT_MAX; return res; } #if 0 /* unused now */ DUK_INTERNAL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags) { duk_hobject *res = duk_hobject_alloc(thr->heap, hobject_flags); if (!res) { DUK_ERROR_ALLOC_FAILED(thr); } return res; }
duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, duk_realloc_function realloc_func, duk_free_function free_func, void *alloc_udata, duk_fatal_function fatal_func) { duk_heap *res = NULL; DUK_D(DUK_DPRINT("allocate heap")); /* Debug dump type sizes */ #ifdef DUK_USE_DEBUG duk__dump_type_sizes(); #endif /* If selftests enabled, run them as early as possible. */ #ifdef DUK_USE_SELF_TESTS DUK_D(DUK_DPRINT("running self tests")); duk_selftest_run_tests(); DUK_D(DUK_DPRINT("self tests passed")); #endif #ifdef DUK_USE_COMPUTED_NAN do { /* Workaround for some exotic platforms where NAN is missing * and the expression (0.0 / 0.0) does NOT result in a NaN. * Such platforms use the global 'duk_computed_nan' which must * be initialized at runtime. Use 'volatile' to ensure that * the compiler will actually do the computation and not try * to do constant folding which might result in the original * problem. */ volatile double dbl1 = 0.0; volatile double dbl2 = 0.0; duk_computed_nan = dbl1 / dbl2; } while (0); #endif #ifdef DUK_USE_COMPUTED_INFINITY do { /* Similar workaround for INFINITY. */ volatile double dbl1 = 1.0; volatile double dbl2 = 0.0; duk_computed_infinity = dbl1 / dbl2; } while (0); #endif /* use a raw call, all macros expect the heap to be initialized */ res = (duk_heap *) alloc_func(alloc_udata, sizeof(duk_heap)); if (!res) { goto error; } /* zero everything */ DUK_MEMZERO(res, sizeof(*res)); /* explicit NULL inits */ #ifdef DUK_USE_EXPLICIT_NULL_INIT res->alloc_udata = NULL; res->heap_allocated = NULL; #ifdef DUK_USE_REFERENCE_COUNTING res->refzero_list = NULL; res->refzero_list_tail = NULL; #endif #ifdef DUK_USE_MARK_AND_SWEEP res->finalize_list = NULL; #endif res->heap_thread = NULL; res->curr_thread = NULL; res->heap_object = NULL; res->log_buffer = NULL; res->st = NULL; { int i; for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) { res->strs[i] = NULL; } } #endif /* initialize the structure, roughly in order */ res->alloc_func = alloc_func; res->realloc_func = realloc_func; res->free_func = free_func; res->alloc_udata = alloc_udata; res->fatal_func = fatal_func; /* res->mark_and_sweep_trigger_counter == 0 -> now causes immediate GC; which is OK */ res->call_recursion_depth = 0; res->call_recursion_limit = DUK_HEAP_DEFAULT_CALL_RECURSION_LIMIT; /* FIXME: use the pointer as a seed for now: mix in time at least */ /* cast through C99 intptr_t to avoid GCC warning: * * warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] */ res->hash_seed = (duk_uint32_t) (duk_intptr_t) res; res->rnd_state = (duk_uint32_t) (duk_intptr_t) res; #ifdef DUK_USE_INTERRUPT_COUNTER /* zero value causes an interrupt before executing first instruction */ DUK_ASSERT(res->interrupt_counter == 0); DUK_ASSERT(res->interrupt_init == 0); #endif #ifdef DUK_USE_EXPLICIT_NULL_INIT res->lj.jmpbuf_ptr = NULL; #endif DUK_ASSERT(res->lj.type == DUK_LJ_TYPE_UNKNOWN); /* zero */ DUK_TVAL_SET_UNDEFINED_UNUSED(&res->lj.value1); DUK_TVAL_SET_UNDEFINED_UNUSED(&res->lj.value2); #if (DUK_STRTAB_INITIAL_SIZE < DUK_UTIL_MIN_HASH_PRIME) #error initial heap stringtable size is defined incorrectly #endif res->st = (duk_hstring **) alloc_func(alloc_udata, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE); if (!res->st) { goto error; } res->st_size = DUK_STRTAB_INITIAL_SIZE; #ifdef DUK_USE_EXPLICIT_NULL_INIT { duk_uint_fast32_t i; for (i = 0; i < res->st_size; i++) { res->st[i] = NULL; } } #else DUK_MEMZERO(res->st, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE); #endif /* strcache init */ #ifdef DUK_USE_EXPLICIT_NULL_INIT { int i; for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) { res->strcache[i].h = NULL; } } #endif /* FIXME: error handling is incomplete. It would be cleanest if * there was a setjmp catchpoint, so that all init code could * freely throw errors. If that were the case, the return code * passing here could be removed. */ /* built-in strings */ DUK_DD(DUK_DDPRINT("HEAP: INIT STRINGS")); if (!duk__init_heap_strings(res)) { goto error; } /* heap thread */ DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP THREAD")); if (!duk__init_heap_thread(res)) { goto error; } /* heap object */ DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP OBJECT")); DUK_ASSERT(res->heap_thread != NULL); res->heap_object = duk_hobject_alloc(res, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT)); if (!res->heap_object) { goto error; } DUK_HOBJECT_INCREF(res->heap_thread, res->heap_object); /* log buffer */ DUK_DD(DUK_DDPRINT("HEAP: INIT LOG BUFFER")); res->log_buffer = (duk_hbuffer_dynamic *) duk_hbuffer_alloc(res, DUK_BI_LOGGER_SHORT_MSG_LIMIT, 1 /*dynamic*/); if (!res->log_buffer) { goto error; } DUK_HBUFFER_INCREF(res->heap_thread, res->log_buffer); DUK_D(DUK_DPRINT("allocated heap: %p", res)); return res; error: DUK_D(DUK_DPRINT("heap allocation failed")); if (res) { /* assumes that allocated pointers and alloc funcs are valid * if res exists */ DUK_ASSERT(res->alloc_func != NULL); DUK_ASSERT(res->realloc_func != NULL); DUK_ASSERT(res->free_func != NULL); duk_heap_free(res); } return NULL; }
DUK_INTERNAL duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, duk_realloc_function realloc_func, duk_free_function free_func, void *heap_udata, duk_fatal_function fatal_func) { duk_heap *res = NULL; /* Silence a few global unused warnings here. */ DUK_UNREF(duk_str_unsupported); DUK_D(DUK_DPRINT("allocate heap")); /* * Debug dump type sizes */ #ifdef DUK_USE_DEBUG duk__dump_misc_options(); duk__dump_type_sizes(); duk__dump_type_limits(); #endif /* * If selftests enabled, run them as early as possible */ #ifdef DUK_USE_SELF_TESTS DUK_D(DUK_DPRINT("running self tests")); duk_selftest_run_tests(); DUK_D(DUK_DPRINT("self tests passed")); #endif /* * Computed values (e.g. INFINITY) */ #ifdef DUK_USE_COMPUTED_NAN do { /* Workaround for some exotic platforms where NAN is missing * and the expression (0.0 / 0.0) does NOT result in a NaN. * Such platforms use the global 'duk_computed_nan' which must * be initialized at runtime. Use 'volatile' to ensure that * the compiler will actually do the computation and not try * to do constant folding which might result in the original * problem. */ volatile double dbl1 = 0.0; volatile double dbl2 = 0.0; duk_computed_nan = dbl1 / dbl2; } while (0); #endif #ifdef DUK_USE_COMPUTED_INFINITY do { /* Similar workaround for INFINITY. */ volatile double dbl1 = 1.0; volatile double dbl2 = 0.0; duk_computed_infinity = dbl1 / dbl2; } while (0); #endif /* * Allocate heap struct * * Use a raw call, all macros expect the heap to be initialized */ res = (duk_heap *) alloc_func(heap_udata, sizeof(duk_heap)); if (!res) { goto error; } /* * Zero the struct, and start initializing roughly in order */ DUK_MEMZERO(res, sizeof(*res)); /* explicit NULL inits */ #ifdef DUK_USE_EXPLICIT_NULL_INIT res->heap_udata = NULL; res->heap_allocated = NULL; #ifdef DUK_USE_REFERENCE_COUNTING res->refzero_list = NULL; res->refzero_list_tail = NULL; #endif #ifdef DUK_USE_MARK_AND_SWEEP res->finalize_list = NULL; #endif res->heap_thread = NULL; res->curr_thread = NULL; res->heap_object = NULL; #if defined(DUK_USE_STRTAB_CHAIN) /* nothing to NULL */ #elif defined(DUK_USE_STRTAB_PROBE) #if defined(DUK_USE_HEAPPTR16) res->strtable16 = (duk_uint16_t *) NULL; #else res->strtable = (duk_hstring **) NULL; #endif #endif #if defined(DUK_USE_HEAPPTR16) /* res->strs16[] is zeroed and zero decodes to NULL, so no NULL inits. */ #else { duk_small_uint_t i; for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) { res->strs[i] = NULL; } } #endif #if defined(DUK_USE_DEBUGGER_SUPPORT) res->dbg_read_cb = NULL; res->dbg_write_cb = NULL; res->dbg_peek_cb = NULL; res->dbg_read_flush_cb = NULL; res->dbg_write_flush_cb = NULL; res->dbg_udata = NULL; res->dbg_step_thread = NULL; #endif #endif /* DUK_USE_EXPLICIT_NULL_INIT */ res->alloc_func = alloc_func; res->realloc_func = realloc_func; res->free_func = free_func; res->heap_udata = heap_udata; res->fatal_func = fatal_func; #if defined(DUK_USE_HEAPPTR16) /* XXX: zero assumption */ res->heapptr_null16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) NULL); res->heapptr_deleted16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) DUK_STRTAB_DELETED_MARKER(res)); #endif /* res->mark_and_sweep_trigger_counter == 0 -> now causes immediate GC; which is OK */ res->call_recursion_depth = 0; res->call_recursion_limit = DUK_HEAP_DEFAULT_CALL_RECURSION_LIMIT; /* XXX: use the pointer as a seed for now: mix in time at least */ /* The casts through duk_intr_pt is to avoid the following GCC warning: * * warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] * * This still generates a /Wp64 warning on VS2010 when compiling for x86. */ res->hash_seed = (duk_uint32_t) (duk_intptr_t) res; res->rnd_state = (duk_uint32_t) (duk_intptr_t) res; #ifdef DUK_USE_EXPLICIT_NULL_INIT res->lj.jmpbuf_ptr = NULL; #endif DUK_ASSERT(res->lj.type == DUK_LJ_TYPE_UNKNOWN); /* zero */ DUK_TVAL_SET_UNDEFINED_UNUSED(&res->lj.value1); DUK_TVAL_SET_UNDEFINED_UNUSED(&res->lj.value2); #if (DUK_STRTAB_INITIAL_SIZE < DUK_UTIL_MIN_HASH_PRIME) #error initial heap stringtable size is defined incorrectly #endif /* * Init stringtable: fixed variant */ #if defined(DUK_USE_STRTAB_CHAIN) DUK_MEMZERO(res->strtable, sizeof(duk_strtab_entry) * DUK_STRTAB_CHAIN_SIZE); #ifdef DUK_USE_EXPLICIT_NULL_INIT { duk_small_uint_t i; for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) { #if defined(DUK_USE_HEAPPTR16) res->strtable[i].u.str16 = res->heapptr_null16; #else res->strtable[i].u.str = NULL; #endif } } #endif /* DUK_USE_EXPLICIT_NULL_INIT */ #endif /* DUK_USE_STRTAB_CHAIN */ /* * Init stringtable: probe variant */ #if defined(DUK_USE_STRTAB_PROBE) #if defined(DUK_USE_HEAPPTR16) res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE); if (!res->strtable16) { goto error; } #else /* DUK_USE_HEAPPTR16 */ res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE); if (!res->strtable) { goto error; } #endif /* DUK_USE_HEAPPTR16 */ res->st_size = DUK_STRTAB_INITIAL_SIZE; #ifdef DUK_USE_EXPLICIT_NULL_INIT { duk_small_uint_t i; DUK_ASSERT(res->st_size == DUK_STRTAB_INITIAL_SIZE); for (i = 0; i < DUK_STRTAB_INITIAL_SIZE; i++) { #if defined(DUK_USE_HEAPPTR16) res->strtable16[i] = res->heapptr_null16; #else res->strtable[i] = NULL; #endif } } #else /* DUK_USE_EXPLICIT_NULL_INIT */ #if defined(DUK_USE_HEAPPTR16) DUK_MEMZERO(res->strtable16, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE); #else DUK_MEMZERO(res->strtable, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE); #endif #endif /* DUK_USE_EXPLICIT_NULL_INIT */ #endif /* DUK_USE_STRTAB_PROBE */ /* * Init stringcache */ #ifdef DUK_USE_EXPLICIT_NULL_INIT { duk_small_uint_t i; for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) { res->strcache[i].h = NULL; } } #endif /* XXX: error handling is incomplete. It would be cleanest if * there was a setjmp catchpoint, so that all init code could * freely throw errors. If that were the case, the return code * passing here could be removed. */ /* * Init built-in strings */ DUK_DD(DUK_DDPRINT("HEAP: INIT STRINGS")); if (!duk__init_heap_strings(res)) { goto error; } /* * Init the heap thread */ DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP THREAD")); if (!duk__init_heap_thread(res)) { goto error; } /* * Init the heap object */ DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP OBJECT")); DUK_ASSERT(res->heap_thread != NULL); res->heap_object = duk_hobject_alloc(res, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT)); if (!res->heap_object) { goto error; } DUK_HOBJECT_INCREF(res->heap_thread, res->heap_object); /* * All done */ DUK_D(DUK_DPRINT("allocated heap: %p", (void *) res)); return res; error: DUK_D(DUK_DPRINT("heap allocation failed")); if (res) { /* assumes that allocated pointers and alloc funcs are valid * if res exists */ DUK_ASSERT(res->alloc_func != NULL); DUK_ASSERT(res->realloc_func != NULL); DUK_ASSERT(res->free_func != NULL); duk_heap_free(res); } return NULL; }