You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

125 lines
3.5 KiB

/*
* A finalizer shouldn't be re-entered unless the finalizer explicitly
* rescued the object.
*/
static duk_ret_t my_print(duk_context *ctx) {
duk_push_string(ctx, " ");
duk_insert(ctx, 0);
duk_join(ctx, duk_get_top(ctx) - 1);
printf("%s\n", duk_safe_to_string(ctx, -1));
return 0;
}
/*===
*** test_heap_destruction (duk_safe_call)
creating heap
heap created
object 1 finalizer
destroying heap
heap destroyed
==> rc=0, result='undefined'
===*/
/* Create an object, force one round of GC and destroy heap immediately.
* Object has been finalized but not yet rescued, and should not be
* finalized again on destruction.
*/
static duk_ret_t test_heap_destruction(duk_context *ignored_ctx, void *udata) {
duk_context *my_ctx;
(void) udata;
printf("creating heap\n"); fflush(stdout);
my_ctx = duk_create_heap_default();
if (!my_ctx) {
printf("failed to create heap\n"); fflush(stdout);
return 0;
}
printf("heap created\n"); fflush(stdout);
/* Dummy print() binding. */
duk_push_c_function(my_ctx, my_print, 1);
duk_put_global_string(my_ctx, "print");
duk_eval_string_noresult(my_ctx,
"(function () {\n"
" var obj1 = {}; var obj2 = {};\n"
" obj1.ref = obj2; obj2.ref = obj1;\n"
" Duktape.fin(obj1, function obj1fin() { print('object 1 finalizer'); });\n"
" obj1 = obj2 = null;\n"
" Duktape.gc();\n"
"})()");
printf("destroying heap\n"); fflush(stdout);
duk_destroy_heap(my_ctx);
printf("heap destroyed\n"); fflush(stdout);
return 0;
}
#if 0 /* Disabled: this is too fragile because it relies on dangling references;
* unfortunately the potential re-run scenario is difficult to confirm
* otherwise.
*/
/* Create a circular reference with a finalizer, force a GC run which runs the
* finalizer. Use a dangling (!) C heaphdr reference to break the loop so that
* refzero code processes the object again. Finalization should not happen again
* in the refcount path.
*/
static duk_ret_t test_markandsweep_finalize_then_refzero(duk_context *ignored_ctx) {
duk_context *my_ctx;
void *ptr;
printf("creating heap\n"); fflush(stdout);
my_ctx = duk_create_heap_default();
if (!my_ctx) {
printf("failed to create heap\n"); fflush(stdout);
return 0;
}
printf("heap created\n"); fflush(stdout);
duk_eval_string(my_ctx,
"(function () {\n"
" var obj1 = {}; var obj2 = {};\n"
" obj1.ref = obj2; obj2.ref = obj1;\n"
" Duktape.fin(obj1, function obj1fin() { print('object 1 finalizer'); });\n"
" return obj1;\n"
"})()");
ptr = duk_get_heapptr(my_ctx, -1);
duk_pop(my_ctx);
if (!ptr) {
printf("heap ptr was NULL\n"); fflush(stdout);
} else {
printf("forcing gc\n"); fflush(stdout);
duk_gc(my_ctx, 0);
printf("gc done\n"); fflush(stdout);
/* Because 'ptr' has a finalizer it's been finalized but would
* require a second round of mark-and-sweep the be actually freed.
* So 'ptr' is reachable but technically dangling so this is not
* fully safe. But it's safe enough to break the circular reference
* unless something else triggers GC before that.
*/
duk_push_heapptr(my_ctx, ptr);
duk_del_prop_string(my_ctx, -1, "ref");
printf("popping final reference after breaking cycle\n"); fflush(stdout);
duk_pop(my_ctx);
printf("pop completed\n"); fflush(stdout);
}
printf("destroying heap\n"); fflush(stdout);
duk_destroy_heap(my_ctx);
printf("heap destroyed\n"); fflush(stdout);
return 0;
}
#endif /* 0 */
void test(duk_context *ctx) {
TEST_SAFE_CALL(test_heap_destruction);
#if 0
TEST_SAFE_CALL(test_markandsweep_finalize_then_refzero);
#endif
}