From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail4-relais-sop.national.inria.fr (mail4-relais-sop.national.inria.fr [192.134.164.105]) by walapai.inria.fr (8.13.6/8.13.6) with ESMTP id q097XY74023922 for ; Mon, 9 Jan 2012 08:33:37 +0100 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AmEBAJ+XCk/U436rkGdsb2JhbABDhQ+lBoIzIgEBAQEJCQ0HFAMigXIBAQQBI1YFCwsaAiYCAlcGiA0CpB2RG4EviUyBFgSNHo08jGk X-IronPort-AV: E=Sophos;i="4.71,479,1320620400"; d="scan'208";a="126046222" Received: from moutng.kundenserver.de ([212.227.126.171]) by mail4-smtp-sop.national.inria.fr with ESMTP; 09 Jan 2012 08:33:23 +0100 Received: from office1.lan.sumadev.de (dslb-188-097-007-242.pools.arcor-ip.net [188.97.7.242]) by mrelayeu.kundenserver.de (node=mreu2) with ESMTP (Nemesis) id 0MLkAx-1Rjssl3XZT-000ltY; Mon, 09 Jan 2012 08:33:21 +0100 Received: from [192.168.0.31] (dslb-084-058-025-016.pools.arcor-ip.net [84.58.25.16]) by office1.lan.sumadev.de (Postfix) with ESMTPSA id 5D5E5C00CE; Mon, 9 Jan 2012 08:33:20 +0100 (CET) From: Gerd Stolpmann To: "Harrison, John R" Cc: "caml-list@inria.fr" In-Reply-To: References: Content-Type: text/plain; charset="UTF-8" Date: Mon, 09 Jan 2012 08:33:18 +0100 Message-ID: <1326094398.2242.26.camel@samsung> Mime-Version: 1.0 X-Mailer: Evolution 2.32.2 Content-Transfer-Encoding: 7bit X-Provags-ID: V02:K0:rSh9hJEUSce2uost/v7ltlt4a0uX3Tf+cGLfn5sHddx Zw9dKg9gEDvdAWk2FMG+K6Y3JHqhT+GsEwk++/Am5maMUKVcGP YBJSDbJEkX+GBG/cgTbaGIcUCFRuM6dNDlXrfWomTPDCRb2MFO WqVWsoHnrBrE5NN1VBM02BP930FJUjbij12ZGZNkdXciGWDtzD eLQfWLQ6BY401oLdI2hc2DpG4PQMVEM97rZVeFzpbHP5oUc8Yi h4wCewL/HQ/C6NvQmWXMMO4X9XYkWcM8atP7lbDxquOy9R0SN/ htFskCYmVx6on/vN8SYuWfjDzzST0IvBAaaESAVSwmJXLE0Pra qCNsUhPhA37fz/PfdOU0ZpfxW76/c64xN5whXigZA Subject: Re: [Caml-list] Non-toplevel C functions using OCaml values 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. > > >