[MLton] Registering roots in the FFI
Jens Axel Søgaard
jensaxel@soegaard.net
Mon, 02 May 2005 23:50:14 +0200
Stephen Weeks wrote:
>>Since globals are treated as roots by the garbage collector,
>>I can use global reference cells to prevent the garbage
>>collector to free needed values.
>
> Possibly. You need to worry about MLton's optimizer being clever
> enough to notice that a ref cell's contents are unused and then
> removing the contents, or even the ref cell.
I decided to try the "Register in roots in ML"-approach. The initial
experiments on int arrays seemed to work, so now I am trying to
generalize to other types as well.
For each type t there are three functions:
registerRoot : t -> int
getRoot : int -> t
unregisterRoot : int -> unit
Since there are 17 basic types, and one can have arrays, vectors and
references of the basic types, and for each combination there are 3
functions to export. This amounts to 153 functions.
The question is whether there is a better way to organize the code
than the following? Specifically is there a smater way of handling
the exporting?
(* root.sig *)
signature ROOT_TYPE =
sig
type t
end
signature ROOT =
sig
type t
exception RootNotFound;
val getRoot: int -> t
val registerRoot: t -> int
val unregisterRoot: int -> unit
end
----------------------
(* root.fun *)
functor Root (R: ROOT_TYPE): ROOT =
struct
type t = R.t;
exception RootNotFound;
val roots = ref []; (* association list of integer*root pairs *)
val nextRoot = ref 0;
val getRoot =
fn i => let
val rec loop = fn nil => raise RootNotFound
| (j,r)::more => if i=j then r else (loop more)
in
loop (!roots)
end;
val registerRoot =
fn r => (roots := (!nextRoot,r)::(!roots);
nextRoot := !nextRoot+1;
!nextRoot-1);
val unregisterRoot =
fn i => roots := let val rec loop =
fn [] => raise RootNotFound
| (j,r)::more => if i=j
then more
else (j,r)::(loop more)
in
loop (!roots)
end;
end
----------------------
(* test.sml for now *)
structure BoolArrayRoots = Root(struct type t = bool array end);
structure CharArrayRoots = Root(struct type t = char array end);
structure Int8ArrayRoots = Root(struct type t = Int8.int array end);
structure Int16ArrayRoots = Root(struct type t = Int16.int array end);
structure Int32ArrayRoots = Root(struct type t = Int32.int array end);
structure Int64ArrayRoots = Root(struct type t = Int64.int array end);
structure IntArrayRoots = Root(struct type t = int array end);
structure PointerArrayRoots = Root(struct type t = MLton.Pointer.t array end);
structure Real32ArrayRoots = Root(struct type t = Real32.real array end);
structure Real64ArrayRoots = Root(struct type t = Real64.real array end);
structure RealArrayRoots = Root(struct type t = Real64.real array end);
structure StringArrayRoots = Root(struct type t = string array end);
structure Word8ArrayRoots = Root(struct type t = Word8.word array end);
structure Word16ArrayRoots = Root(struct type t = Word16.word array end);
structure Word32ArrayRoots = Root(struct type t = Word32.word array end);
structure Word64ArrayRoots = Root(struct type t = Word64.word array end);
structure WordArrayRoots = Root(struct type t = word array end);
(* here comes vectors and references to the same types *)
val _ = _export "registerRoot_BoolArray": bool Array.array -> int; BoolArrayRoots.registerRoot;
val _ = _export "unregisterRoot_BoolArray": int -> unit; BoolArrayRoots.unregisterRoot;
val _ = _export "getRoot_BoolArray": int -> bool Array.array; BoolArrayRoots.getRoot;
--
Jens Axel Søgaard