Finaliser
Created by: wks
NOTE: This proposal may go to the interface of a specific µVM implementation rather than the µVM specification. The µVM can cheat by presenting an "infinite heap" and telling the program no objects are ever reclaimed.
Proposed mechanism
Add an objects-to-finalise queue. This queue is maintained internally by the µVM. Each element is a strong reference to an object. It may not be FIFO.
Add a new instruction @uvm.gc.prevent_death_once (%r: ref<T>) -> void
. Then the next time when the GC decided that the object of %r
is a garbage, it will put it in the queue. This instruction is atomic.
Add a new instruction @uvm.gc.next_object_to_finalise () -> ref<void>
. This instruction removes one reference from the objects-to-finalise queue and return it. The current µVM thread blocks if this queue is empty. This instruction is atomic.
Typical usage
Take Java for example.
- On allocating any object that has an overridden
finalize
method, the@uvm.gc.prevent_death_once
instruction is executed on the newly allocated object. - There is a background thread (ordinary µVM thread, running Client-supplied µVM IR code) running in a loop, executing the
@uvm.gc.next_object_to_finalise
instruction. - When the GC is about to collect the finalisable object, it instead puts the object in the queue. The background thread gets that object and do whatever it wants according to the high-level language semantics.
Backgrounds
Java: Objects with finalize
methods are finalised. finalize
is executed automatically only once per object. Finalisers are executed in unspecified threads, at unspecified times, in unspecified order, may be executed concurrently. This sentence: "Every pre-finalization write to a field of an object must be visible to the finalization of that object." implies some kind of fence.
Python, Ruby, PHP, ...: Using naive reference counting, finalisers are deterministically executed when the reference count drops to 0.
Open questions
- The blocking mechanism (the instruction
@uvm.gc.next_object_to_finalise
can block) looks redundant given that the µVM already has the Futex interface which blocks a thread. There is no obvious way to wake up a thread waiting on this "queue".