/* * Test Duktape specific mark-and-sweep initiated finalizer calling. * In particular, test that "rescuing" and re-finalizing works * correctly. * * Note: print messages for both finalizers are identical because * the order in which they run is not guaranteed. * * Manipulation of 'a' and 'b' are in helper functions to guarantee * that no references are held in temporary registers. Cleanup of * references in temporary registers is currently NOT guaranteed * while a function is running. */ /*--- { "custom": true } ---*/ /*=== object object finalizer: rescue finalizer: rescue object object finalizer: rescue finalizer: rescue object object finalizer: no rescue finalizer: no rescue undefined undefined ===*/ var a; var b; var rescue; function finalizer_a(x) { if (rescue) { print('finalizer: rescue'); a = x; } else { print('finalizer: no rescue'); } } function finalizer_b(x) { if (rescue) { print('finalizer: rescue'); b = x; } else { print('finalizer: no rescue'); } } function init() { a = { name: 'a' }; b = { name: 'b' }; /* circular refs */ a.ref = b; b.ref = a; __duk__.setFinalizer(a, finalizer_a); __duk__.setFinalizer(b, finalizer_b); } function delrefs() { a = undefined; b = undefined; } function testrefs() { print(typeof a); print(typeof b); //print(__duk__.refc(a)); //print(__duk__.refc(b)); } init(); testrefs(); rescue = true; delrefs(); __duk__.gc(); // both a and b should be unreachable and have their finalizers executed __duk__.gc(); // a second gc will rescue the objects, allowing their finalizer to run again testrefs(); /* Note: a single gc above is NOT sufficient to ensure that the finalizer will run again. * Consider the sequence: * * 1. Value X is made unreachable and GC runs. GC marks the value as finalizable, * and runs the finalizer. Finally, GC places value X back to heap_allocated * with the flag FINALIZED. * * 2. Application code makes X unreachable again before GC runs again. * * 3. GC detects that X is FINALIZED and not reachable, and will thus not be rescued, * nor will finalization run again. * * If there is a GC between steps 2 and 3 (as there is here) the value will be rescued * and FINALIZED flag will be cleared. This causes the object to be finalized again in * step 3. */ rescue = true; delrefs(); __duk__.gc(); // again __duk__.gc(); testrefs(); rescue = false; delrefs(); __duk__.gc(); // swept immediately testrefs();