default: break; /* Nothing */
}
}
+
+void gc_register_finalizer(void* obj) {
+#ifdef WITH_LIBGC
+ GC_register_finalizer(obj, &gc_finalize, NULL, NULL, NULL);
+#endif
+}
+
+void __attribute__((weak)) gc_finalize(void *obj, void* client_data) {}
void nit_gcollect(void); /* force a garbage collection */
void initialize_gc_option(void); /* Select the wanted GC using envvar `NIT_GC_OPTION` */
+void gc_set_finializer(void*); /* Tag a pointer for finalization */
+void gc_finalize(void*, void*); /* Finalize a pointer, implemented in the generated code. */
+
#endif
# Initiate a garbage collection
fun force_garbage_collection is intern
end
+
+# An object needing finalization
+#
+# Sub-classes of `Finalizable` must no have cycles, or else they will not be
+# liberated. For this reason, it is recommended to sub-class `Finalizable`
+# only on simple objects directly managing a limited resource. This use case
+# is common when wrapping an extern instance with a standard object.
+class Finalizable
+
+ # Liberate any resources held by `self` before the memory holding `self` is freed
+ #
+ # This method is invoked by the GC during a garbage collection when `self`
+ # is no longer referenced. It can also be called by the user. Its implementation
+ # must be planned accordingly and ensure that it may be invoked more than once.
+ #
+ # The object are finialized in a topological order, it is safe for this method
+ # to use attributes of this instances.
+ fun finalize do end
+end
"""
end
+ fun compile_finalizer_function
+ do
+ var finalizable_type = mainmodule.finalizable_type
+ if finalizable_type == null then return
+
+ var finalize_meth = mainmodule.try_get_primitive_method("finalize", finalizable_type.mclass)
+
+ if finalize_meth == null then
+ modelbuilder.toolcontext.error(null, "The `Finalizable` class doesn't declare the `finalize` method.")
+ return
+ end
+
+ var v = self.new_visitor
+ v.add_decl "void gc_finalize (void *obj, void *client_data) \{"
+ var recv = v.new_expr("obj", finalizable_type)
+ v.send(finalize_meth, [recv])
+ v.add "\}"
+ end
+
# Generate the main C function.
# This function:
# * allocate the Sys object if it exists
# Generate a alloc-instance + init-attributes
fun init_instance(mtype: MClassType): RuntimeVariable is abstract
+ # Set a GC finalizer on `recv`, only if `recv` isa Finalizable
+ fun set_finalizer(recv: RuntimeVariable)
+ do
+ var mtype = recv.mtype
+ var finalizable_type = compiler.mainmodule.finalizable_type
+ if finalizable_type != null and not mtype.need_anchor and
+ mtype.is_subtype(compiler.mainmodule, null, finalizable_type) then
+ add "gc_register_finalizer({recv});"
+ end
+ end
+
# Generate an integer value
fun int_instance(value: Int): RuntimeVariable
do
v.add("{res}->classid = {self.classid(mtype)};")
self.generate_init_attr(v, res, mtype)
+ v.set_finalizer res
v.add("return {res};")
v.add("\}")
end
return get_primitive_class("Sys").mclass_type
end
+ fun finalizable_type: nullable MClassType
+ do
+ var clas = self.model.get_mclasses_by_name("Finalizable")
+ if clas == null then return null
+ return get_primitive_class("Finalizable").mclass_type
+ end
+
# Force to get the primitive class named `name` or abort
fun get_primitive_class(name: String): MClass
do
add_send(maintype, mainprop)
end
+ var finalizable_type = mainmodule.finalizable_type
+ if finalizable_type != null then
+ var finalize_meth = mainmodule.try_get_primitive_method("finalize", finalizable_type.mclass)
+ if finalize_meth != null then add_send(finalizable_type, finalize_meth)
+ end
+
# Force primitive types
force_alive("Bool")
force_alive("Int")
compiler.new_file("{mainmodule.name}.main")
compiler.compile_nitni_global_ref_functions
compiler.compile_main_function
+ compiler.compile_finalizer_function
# compile methods
for m in mainmodule.in_importation.greaters do
v.require_declaration("class_{c_name}")
v.add("{res}->class = &class_{c_name};")
self.generate_init_attr(v, res, mtype)
+ v.set_finalizer res
v.add("return {res};")
end
v.add("\}")
v.require_declaration("class_{c_name}")
v.add("{res}->class = &class_{c_name};")
self.generate_init_attr(v, res, mtype)
+ v.set_finalizer res
v.add("return {res};")
end
v.add("\}")