blob: 6cb1837e5e053646506e272146d852575da21a5a [file] [log] [blame]
/*
* Heap creation and destruction
*/
#include "duk_internal.h"
DUK_EXTERNAL
duk_context *duk_create_heap(duk_alloc_function alloc_func,
duk_realloc_function realloc_func,
duk_free_function free_func,
void *heap_udata,
duk_fatal_function fatal_handler) {
duk_heap *heap = NULL;
duk_context *ctx;
/* Assume that either all memory funcs are NULL or non-NULL, mixed
* cases will now be unsafe.
*/
/* XXX: just assert non-NULL values here and make caller arguments
* do the defaulting to the default implementations (smaller code)?
*/
if (!alloc_func) {
DUK_ASSERT(realloc_func == NULL);
DUK_ASSERT(free_func == NULL);
#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
alloc_func = duk_default_alloc_function;
realloc_func = duk_default_realloc_function;
free_func = duk_default_free_function;
#else
DUK_D(DUK_DPRINT("no allocation functions given and no default providers"));
return NULL;
#endif
} else {
DUK_ASSERT(realloc_func != NULL);
DUK_ASSERT(free_func != NULL);
}
if (!fatal_handler) {
fatal_handler = duk_default_fatal_handler;
}
DUK_ASSERT(alloc_func != NULL);
DUK_ASSERT(realloc_func != NULL);
DUK_ASSERT(free_func != NULL);
DUK_ASSERT(fatal_handler != NULL);
heap = duk_heap_alloc(alloc_func, realloc_func, free_func, heap_udata, fatal_handler);
if (!heap) {
return NULL;
}
ctx = (duk_context *) heap->heap_thread;
DUK_ASSERT(ctx != NULL);
DUK_ASSERT(((duk_hthread *) ctx)->heap != NULL);
return ctx;
}
DUK_EXTERNAL void duk_destroy_heap(duk_context *ctx) {
duk_hthread *thr = (duk_hthread *) ctx;
duk_heap *heap;
if (!ctx) {
return;
}
heap = thr->heap;
DUK_ASSERT(heap != NULL);
duk_heap_free(heap);
}
/* XXX: better place for this */
DUK_EXTERNAL void duk_set_global_object(duk_context *ctx) {
duk_hthread *thr = (duk_hthread *) ctx;
duk_hobject *h_glob;
duk_hobject *h_prev_glob;
duk_hobject *h_env;
duk_hobject *h_prev_env;
DUK_D(DUK_DPRINT("replace global object with: %!T", duk_get_tval(ctx, -1)));
h_glob = duk_require_hobject(ctx, -1);
DUK_ASSERT(h_glob != NULL);
/*
* Replace global object.
*/
h_prev_glob = thr->builtins[DUK_BIDX_GLOBAL];
DUK_UNREF(h_prev_glob);
thr->builtins[DUK_BIDX_GLOBAL] = h_glob;
DUK_HOBJECT_INCREF(thr, h_glob);
DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_glob); /* side effects, in theory (referenced by global env) */
/*
* Replace lexical environment for global scope
*
* Create a new object environment for the global lexical scope.
* We can't just reset the _Target property of the current one,
* because the lexical scope is shared by other threads with the
* same (initial) built-ins.
*/
(void) duk_push_object_helper(ctx,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV),
-1); /* no prototype, updated below */
duk_dup(ctx, -2);
duk_dup(ctx, -3);
/* [ ... new_glob new_env new_glob new_glob ] */
duk_xdef_prop_stridx(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);
/* [ ... new_glob new_env ] */
h_env = duk_get_hobject(ctx, -1);
DUK_ASSERT(h_env != NULL);
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_ALLOWNULL(thr, h_prev_env); /* side effects */
DUK_UNREF(h_env); /* without refcounts */
DUK_UNREF(h_prev_env);
/* [ ... new_glob new_env ] */
duk_pop_2(ctx);
/* [ ... ] */
}