* Re: [Caml-list] Non-toplevel C functions using OCaml values
2012-01-09 2:35 [Caml-list] Non-toplevel C functions using OCaml values Harrison, John R
@ 2012-01-09 7:33 ` Gerd Stolpmann
2012-01-09 9:23 ` ygrek
0 siblings, 1 reply; 3+ messages in thread
From: Gerd Stolpmann @ 2012-01-09 7:33 UTC (permalink / raw)
To: Harrison, John R; +Cc: caml-list
Am Montag, den 09.01.2012, 02:35 +0000 schrieb Harrison, John R:
> I have a question about interfacing C and OCaml functions that I
> didn't see an answer to in the manual, though maybe I just didn't look
> carefully enough. I think I pretty well understand how to set up a C
> function that is designed to be called directly by OCaml. But what
> about a function that I want to use internally as a utility, callable
> by other C functions that are themselves called by OCaml?
>
> For example, if I want to implement a function designed to be called
> directly by OCaml and basically equivalent to the OCaml definition
>
> let cons h t = h::t;;
>
> then I think (correct me if I'm wrong) that I do the following:
>
> CAMLprim value caml_cons(value h,value t)
> { CAMLparam2(h,t);
> CAMLlocal1(newblock);
> newblock = caml_alloc(2,0);
> Store_field(newblock,0,h);
> Store_field(newblock,1,t);
> CAMLreturn(newblock);
> }
>
> But what if I want to set up a utility that I'm only going to call
> from other C functions, and which involves a mixture of standard C
> types and OCaml values among its arguments or local variables, and/or
> allocates OCaml values? For example, suppose I want to implement the
> special case of the above "cons" for int lists where the first
> argument is a C int (which I assume to be in range for an OCaml
> int). I might guess that I would do something like this:
>
> value int_cons(int h,value t)
> { CAMLparam1(t);
> CAMLlocal1(newblock);
> newblock = caml_alloc(2,0);
> Store_field(newblock,0,Val_int(h));
> Store_field(newblock,1,t);
> CAMLreturn(newblock);
> }
>
> and then just call it like any other C function. However, I can
> imagine several other plausible alternatives, e.g. that I should skip
> some or all of the special CAMLsomething functions, or that I should
> just forget the idea and use OCaml values throughout, calling it as if
> it were any other OCaml function. Can someone enlighten me?
The second example is perfectly legal. Also, you really need the CAML*
macros for t.
What's happening here is that t and newblock are temporarily added to
the list of local roots (CAMLparam and CAMLlocal add the values to this
list, and CAMLreturn removes the values from this list, all in one go).
You need to add t because there is an allocation which may move t (if t
is a pointer) - caml_alloc may call the GC, and t can be moved around by
the GC. If t is a local root, it is automatically updated if such a move
occurs.
You don't need the CAMLlocal1 for newblock, though, because there is no
allocation after newblock is set.
If you are looking for more optimizations, you can also replace the
first Store_field with Field(newblock,0) = Val_int(h). Store_field is
slightly more expensive, because there is a test whether you create a
pointer from the old generation to the young generation, which is only
allowed if this pointer is added to a special list. You only assign an
int here, so it cannot be a pointer.
For the second assignment you need Store_field because there is no
(official) guarantee that newblock is created in the young generation
(although I don't see a reason why newblock could ever reside in the old
generation, but it's really dependent on implementation details in the
GC).
If there is any chance, don't create structured values like this here in
C, but let ocamlopt do this work. The resulting code is a lot slower if
you do it in C because ocamlopt can do a number of optimizations you
cannot do in C (e.g. ocamlopt knows whether newblock can only be in the
young generation, and an ocamlopt-compiled function needs not to
maintain local roots - the stack is scanned anyway).
Gerd
> John.
>
>
>
^ permalink raw reply [flat|nested] 3+ messages in thread