Haxe types
C libraries often contain struct fields or function arguments of type void*
, such that client code using the library can provide a pointer to its own datatypes. In ammer
, such void*
values can stand for instances of a Haxe type, such as a Haxe class
instance.
Garbage collection
All Haxe targets are garbage collected, which means it is the runtime's responsibility to understand which instances are no longer needed and can be re-used to free memory. For Haxe programs which do not interact with native libraries, this is not a problem. However, as soon as a Haxe instance is passed to a native library, a problem may arise: the Haxe runtime could decide that the Haxe instance is no longer usable, so it could be freed, but a reference to it may still be obtainable via the native library.
The solution used in ammer
is to wrap Haxe instances with a reference counter, such that the programmer can indicate when a Haxe instance is or is not in use. To pass Haxe types to native libraries, use the ammer.ffi.Haxe<...>
type in ammer
definitions. When calling such functions, instances of Haxe types must first be wrapped using the ammer.Lib.createHaxeRef
function. The resulting value has a value
field to obtain the underlying Haxe instance, as well as an incref
and decref
function to increment or decrement the reference counter respectively.
The initial reference count of a Haxe reference is 0
.
Example: function accepting a Haxe type
class MyHaxeType { /*...*/ } class Foobar extends ammer.def.Library<"foobar"> { public static function hello(a:ammer.ffi.Haxe<MyHaxeType>):Void; }
In this example, MyHaxeType
is a regular Haxe class. The hello
function of the Foobar
library accepts an instance of MyHaxeType
.
var x:MyHaxeType = #dummy expr/*...*/; var xr = ammer.Lib.createHaxeRef(xr); xr.incref(); Foobar.hello(xr); xr.decref();