ammer

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();
« Previous: Enums Next: Callbacks »