From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Stefan Israelsson Tampe Newsgroups: gmane.lisp.guile.devel Subject: Re: RFC: Foreign objects facility Date: Sun, 27 Apr 2014 18:46:36 +0200 Message-ID: References: <87bnvm52u6.fsf@pobox.com> <87a9b692ys.fsf@yeeloong.lan> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/alternative; boundary=047d7b86f7dc3276a504f808f130 X-Trace: ger.gmane.org 1398617226 24977 80.91.229.3 (27 Apr 2014 16:47:06 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sun, 27 Apr 2014 16:47:06 +0000 (UTC) Cc: Andy Wingo , guile-devel To: Mark H Weaver Original-X-From: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Sun Apr 27 18:47:01 2014 Return-path: Envelope-to: guile-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1WeSEH-0003ey-2x for guile-devel@m.gmane.org; Sun, 27 Apr 2014 18:47:01 +0200 Original-Received: from localhost ([::1]:39995 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WeSEG-0005Wv-MJ for guile-devel@m.gmane.org; Sun, 27 Apr 2014 12:47:00 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:51755) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WeSDy-0005Ec-7w for guile-devel@gnu.org; Sun, 27 Apr 2014 12:46:44 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WeSDu-0006YW-VU for guile-devel@gnu.org; Sun, 27 Apr 2014 12:46:42 -0400 Original-Received: from mail-pa0-x232.google.com ([2607:f8b0:400e:c03::232]:34814) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WeSDu-0006YA-GN for guile-devel@gnu.org; Sun, 27 Apr 2014 12:46:38 -0400 Original-Received: by mail-pa0-f50.google.com with SMTP id rd3so4902656pab.23 for ; Sun, 27 Apr 2014 09:46:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=0Fiw1P/B6p9iKP4U6iqTU0t64ESo04acj3FxLSfqNyY=; b=x1LqL/S71JeNoKvTuFmGdfcsffdXLqcfrGInBU9+mLUoPjeRwU3Lzw4X6v+YwzT4Rx 84BMFrfRATTA1AB7rIeAkB8f0HENsSUwwP0vQGf/8pWbaetFJ+8/6oq/M/oXJIcw5FX3 Q/kD1YKi1Ho3QiJU+5TgvcwoZqLhqBHfaNGthm67LcKgEDa3ZnfR0Xqqdyoo3HdIGIGg J4lUHM0cKxIbTsOfLol3zjWhKARzcfr5HmlI7J1sJy+Z02Xw6drA+AXQrZfMUhzw6mOv 3yJmX2yqfOufOp/P4ftO2F+3+IcoPw/qnwm5gINeXC9HzdQ58RXu2f90NfGp6YacGHo8 TXvw== X-Received: by 10.68.170.131 with SMTP id am3mr20165134pbc.97.1398617196883; Sun, 27 Apr 2014 09:46:36 -0700 (PDT) Original-Received: by 10.70.106.133 with HTTP; Sun, 27 Apr 2014 09:46:36 -0700 (PDT) In-Reply-To: <87a9b692ys.fsf@yeeloong.lan> X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2607:f8b0:400e:c03::232 X-BeenThere: guile-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Developers list for Guile, the GNU extensibility library" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Original-Sender: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.lisp.guile.devel:17106 Archived-At: --047d7b86f7dc3276a504f808f130 Content-Type: text/plain; charset=UTF-8 Currently only having 256 smob types is enough arguments for the additions. This can only be a good thing even if I need to the current smob for modelling prolog variables (the overhead of 2 words is a bit heavy if you only have one data slot). So it is brilliant to dispatch all the multitude of larger smob types to the slightly heavier interface. FYI I need need the gc mark interface for my prolog variables in order to hope for garbage collecting of prolog programs, e.g. clean the variables bindings in the prolog stack for variables that no longer is referenced. It is possible to even skip this if I could probe if a SCM variable is unreferenced (but still gc protected) /Stefan On Sun, Apr 27, 2014 at 6:00 PM, Mark H Weaver wrote: > Hi Andy, > > Andy Wingo writes: > > > I propose to provide a new interface that will eventually make SMOBs > > obsolete. This new interface is based on structs with raw fields -- the > > 'u' fields. (See > > > http://www.gnu.org/software/guile/docs/master/guile.html/Vtables.html#Vtables > > for description of 'u' fields. Note that the documentation is wrong -- > > these fields are indeed traced by the GC.) > > Sounds like a good idea, in general. > > > Here is the proposed C API: > > > > SCM scm_make_foreign_object_type (SCM name, SCM slot_names, > > scm_t_struct_finalize finalizer); > > Shouldn't it be 'scm_t_struct_finalizer', with trailing 'r'? > > > void scm_assert_foreign_object_type (SCM type, SCM val); > > > > SCM scm_make_foreign_object_1 (SCM type, scm_t_bits val0); > > SCM scm_make_foreign_object_2 (SCM type, scm_t_bits val0, > > scm_t_bits val1); > > SCM scm_make_foreign_object_3 (SCM type, scm_t_bits val0, > > scm_t_bits val1, scm_t_bits val2); > > If we include an interface like this, I think we should have more of > these, but see below. > > > SCM scm_make_foreign_object_n (SCM type, size_t n, scm_t_bits > vals[]); > > > > scm_t_bits scm_foreign_object_ref (SCM obj, size_t n); > > void scm_foreign_object_set_x (SCM obj, size_t n, scm_t_bits val); > > I'm worried about the type-punning that's implied by this interface. > The C standards are now very strict about this sort of thing, and modern > compilers are becoming increasingly aggressive about taking advantage of > these restrictions to derive assumptions about the code. > > For example, having recently researched this, I know that converting > unsigned integers to signed integers is very awkward and potentially > inefficient to do portably, so using 'scm_foreign_object_ref' to extract > a signed integer will be a pain. It would look something like this > (untested): > > --8<---------------cut here---------------start------------->8--- > scm_t_signed_bits > scm_foreign_object_signed_ref (SCM obj, size_t n) > { > scm_t_bits bits = scm_foreign_object_ref (obj, n); > > /* GNU C specifies that when casting to a signed integer of width N, the > value is reduced modulo 2^N to be within range of the type. Neither > C99 nor C11 make any guarantees about casting an out-of-range value > to a signed integer type. */ > > #ifndef __GNUC__ > if (bits > SCM_T_SIGNED_BITS_MAX) > return -1 - (scm_t_signed_bits) ~bits; > #endif > return (scm_t_signed_bits) bits; > } > --8<---------------cut here---------------end--------------->8--- > > Portability is more problematic for pointer types. The C standards make > no guarantees about the semantics of converting between pointers and > integers, and it's not clear to me how future proof this will be. One > related issue is that I'd like to leave open the possibility that > 'scm_t_bits' might be larger than a pointer. > > For slot refs and sets, I suggest that we need to have multiple variants > for different types. At the very least, we'll need variants for signed > integers, unsigned integers, and pointers. > > For constructors, I think we should provide a macro that handles the > conversion from pointer to scm_t_bits. (Converting from signed to > unsigned is portable, so there's no issue there). > > > The overhead of a foreign object is two words -- the same as the > > overhead on any struct. (Compare to SMOBs, which have a half-word > > overhead.) > > It would be good to think about how we might someday reduce this > overhead in the future, and to make sure we don't make decisions that > would prevent us from doing that. > > > From a12efcfaae1c65cc703616ea15106a88efba3f55 Mon Sep 17 00:00:00 2001 > > From: Andy Wingo > > Date: Sun, 27 Apr 2014 14:47:40 +0200 > > Subject: [PATCH] New foreign object facility, to replace SMOBs > > > > * libguile/foreign-object.c: > > * libguile/foreign-object.h: > > * module/system/foreign-object.scm: > > * test-suite/standalone/test-foreign-object-c.c: > > * test-suite/standalone/test-foreign-object-scm: New files. > > * test-suite/standalone/Makefile.am: > > Something should be added to the line above. > > > diff --git a/libguile/foreign-object.c b/libguile/foreign-object.c > > new file mode 100644 > > index 0000000..78b017a > > --- /dev/null > > +++ b/libguile/foreign-object.c > > @@ -0,0 +1,187 @@ > > +/* Copyright (C) 2014 Free Software Foundation, Inc. > > + * > > + * This library is free software; you can redistribute it and/or > > + * modify it under the terms of the GNU Lesser General Public License > > + * as published by the Free Software Foundation; either version 3 of > > + * the License, or (at your option) any later version. > > + * > > + * This library is distributed in the hope that it will be useful, but > > + * WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > > + * Lesser General Public License for more details. > > + * > > + * You should have received a copy of the GNU Lesser General Public > > + * License along with this library; if not, write to the Free Software > > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA > > + * 02110-1301 USA > > + */ > > + > > + > > + > > +#ifdef HAVE_CONFIG_H > > +# include > > +#endif > > + > > +#include "libguile/_scm.h" > > +#include "libguile/goops.h" > > +#include "libguile/foreign-object.h" > > + > > + > > + > > + > > +static SCM make_fobj_type_var; > > + > > +static void > > +init_make_fobj_type_var (void) > > +{ > > + make_fobj_type_var = scm_c_private_lookup ("system foreign-object", > > + > "make-foreign-object-type"); > > +} > > + > > +SCM > > +scm_make_foreign_object_type (SCM name, SCM slot_names, > > + scm_t_struct_finalize finalizer) > > +{ > > + SCM type; > > + > > + static scm_i_pthread_once_t once = SCM_I_PTHREAD_ONCE_INIT; > > + scm_i_pthread_once (&once, init_make_fobj_type_var); > > Good! > > > + > > + type = scm_call_2 (scm_variable_ref (make_fobj_type_var), name, > slot_names); > > + > > + if (finalizer) > > + SCM_SET_VTABLE_INSTANCE_FINALIZER (type, finalizer); > > + > > + return type; > > +} > > + > > +void > > +scm_assert_foreign_object_type (SCM type, SCM val) > > +{ > > + if (!SCM_IS_A_P (val, type)) > > + scm_error (scm_arg_type_key, NULL, "Wrong type (expecting ~A): ~S", > > + scm_list_2 (scm_class_name (type), val), scm_list_1 > (val)); > > +} > > + > > +SCM > > +scm_make_foreign_object_1 (SCM type, scm_t_bits val0) > > +{ > > + return scm_make_foreign_object_n (type, 1, &val0); > > +} > > + > > +SCM > > +scm_make_foreign_object_2 (SCM type, scm_t_bits val0, scm_t_bits val1) > > +{ > > + scm_t_bits vals[2] = { val0, val1 }; > > This non-constant initializer depends on C99. We discussed this on IRC, > and IIRC we agreed that we should transition to requiring C99 for 2.2, > but making that change in 2.0 is potentially disruptive. > > > + > > + return scm_make_foreign_object_n (type, 2, vals); > > +} > > + > > +SCM > > +scm_make_foreign_object_3 (SCM type, scm_t_bits val0, scm_t_bits val1, > > + scm_t_bits val2) > > +{ > > + scm_t_bits vals[3] = { val0, val1, val2 }; > > Ditto. > > > + > > + return scm_make_foreign_object_n (type, 3, vals); > > +} > > + > > +SCM > > +scm_make_foreign_object_n (SCM type, size_t n, scm_t_bits vals[]) > > +#define FUNC_NAME "make-foreign-object" > > +{ > > + SCM obj; > > + SCM layout; > > + size_t i; > > + > > + SCM_VALIDATE_VTABLE (SCM_ARG1, type); > > + > > + layout = SCM_VTABLE_LAYOUT (type); > > + > > + if (scm_i_symbol_length (layout) / 2 < n) > > + scm_out_of_range (FUNC_NAME, scm_from_size_t (n)); > > + > > + for (i = 0; i < n; i++) > > + if (scm_i_symbol_ref (layout, i * 2) != 'u') > > + scm_wrong_type_arg_msg (FUNC_NAME, 0, layout, "'u' field"); > > This looks inefficient. How about using 'scm_i_symbol_chars'? > > > + > > + obj = scm_c_make_structv (type, 0, 0, NULL); > > + > > + for (i = 0; i < n; i++) > > + SCM_STRUCT_DATA_SET (obj, i, vals[i]); > > + > > + return obj; > > +} > > +#undef FUNC_NAME > [...] > > Thanks! > Mark > > --047d7b86f7dc3276a504f808f130 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable
Currently only having 256 smob types is enough arguments f= or the additions. This can only be a good thing even if I need to the curre= nt smob for modelling prolog variables (the overhead of 2 words is a bit he= avy if
you only have one data slot). So it is brilliant to dispatch all the multit= ude of larger smob types to the slightly=C2=A0
heavier interface.=

FYI I need need the gc mark interface for my prol= og variables in order to hope for garbage collecting of prolog programs, e.= g. clean the variables bindings in the prolog stack for variables that no l= onger is referenced. It is possible to even skip this if I could probe if a= SCM variable is unreferenced (but still gc protected)

/Stefan



On Sun, Apr 27, 2014 at 6:00 PM, M= ark H Weaver <mhw@netris.org> wrote:
Hi Andy,

Andy Wingo <wingo@pobox.com> w= rites:

> I propose to provide a new interface that will eventually make SMOBs > obsolete. =C2=A0This new interface is based on structs with raw fields= -- the
> 'u' fields. =C2=A0(See
> http://www.gnu.org/software/guile/doc= s/master/guile.html/Vtables.html#Vtables
> for description of 'u' fields. =C2=A0Note that the documentati= on is wrong --
> these fields are indeed traced by the GC.)

Sounds like a good idea, in general.

> Here is the proposed C API:
>
> =C2=A0 =C2=A0 SCM scm_make_foreign_object_type (SCM name, SCM slot_nam= es,
> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 scm_t_struct= _finalize finalizer);

Shouldn't it be 'scm_t_struct_finalizer', with trailing &= #39;r'?

> =C2=A0 =C2=A0 void scm_assert_foreign_object_type (SCM type, SCM val);=
>
> =C2=A0 =C2=A0 SCM scm_make_foreign_object_1 (SCM type, scm_t_bits val0= );
> =C2=A0 =C2=A0 SCM scm_make_foreign_object_2 (SCM type, scm_t_bits val0= ,
> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 scm_t_bits val1); > =C2=A0 =C2=A0 SCM scm_make_foreign_object_3 (SCM type, scm_t_bits val0= ,
> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 scm_t_bits val1, sc= m_t_bits val2);

If we include an interface like this, I think we should have more of<= br> these, but see below.

> =C2=A0 =C2=A0 SCM scm_make_foreign_object_n (SCM type, size_t n, scm_t= _bits vals[]);
>
> =C2=A0 =C2=A0 scm_t_bits scm_foreign_object_ref (SCM obj, size_t n); > =C2=A0 =C2=A0 void scm_foreign_object_set_x (SCM obj, size_t n, scm_t_= bits val);

I'm worried about the type-punning that's implied by this int= erface.
The C standards are now very strict about this sort of thing, and modern compilers are becoming increasingly aggressive about taking advantage of these restrictions to derive assumptions about the code.

For example, having recently researched this, I know that converting
unsigned integers to signed integers is very awkward and potentially
inefficient to do portably, so using 'scm_foreign_object_ref' to ex= tract
a signed integer will be a pain. =C2=A0It would look something like this (untested):

--8<---------------cut here---------------start------------->8---
scm_t_signed_bits
scm_foreign_object_signed_ref (SCM obj, size_t n)
{
=C2=A0 scm_t_bits bits =3D scm_foreign_object_ref (obj, n);

/* GNU C specifies that when casting to a signed integer of width N, the =C2=A0 =C2=A0value is reduced modulo 2^N to be within range of the type. = =C2=A0Neither
=C2=A0 =C2=A0C99 nor C11 make any guarantees about casting an out-of-range = value
=C2=A0 =C2=A0to a signed integer type. =C2=A0*/

#ifndef __GNUC__
=C2=A0 if (bits > SCM_T_SIGNED_BITS_MAX)
=C2=A0 =C2=A0 return -1 - (scm_t_signed_bits) ~bits;
#endif
=C2=A0 return (scm_t_signed_bits) bits;
}
--8<---------------cut here---------------end--------------->8---

Portability is more problematic for pointer types. =C2=A0The C standards ma= ke
no guarantees about the semantics of converting between pointers and
integers, and it's not clear to me how future proof this will be. =C2= =A0One
related issue is that I'd like to leave open the possibility that
'scm_t_bits' might be larger than a pointer.

For slot refs and sets, I suggest that we need to have multiple variants for different types. =C2=A0At the very least, we'll need variants for s= igned
integers, unsigned integers, and pointers.

For constructors, I think we should provide a macro that handles the
conversion from pointer to scm_t_bits. =C2=A0(Converting from signed to
unsigned is portable, so there's no issue there).

> The overhead of a foreign object is two words -- the same as the
> overhead on any struct. =C2=A0(Compare to SMOBs, which have a half-wor= d
> overhead.)

It would be good to think about how we might someday reduce this
overhead in the future, and to make sure we don't make decisions that would prevent us from doing that.

> From a12efcfaae1c65cc703616ea15106a88efba3f55 Mon Sep 17 00:00:00 2001=
> From: Andy Wingo <wingo@pobox.co= m>
> Date: Sun, 27 Apr 2014 14:47:40 +0200
> Subject: [PATCH] New foreign object facility, to replace SMOBs
>
> * libguile/foreign-object.c:
> * libguile/foreign-object.h:
> * module/system/foreign-object.scm:
> * test-suite/standalone/test-foreign-object-c.c:
> * test-suite/standalone/test-foreign-object-scm: New files.
> * test-suite/standalone/Makefile.am:

Something should be added to the line above.

> diff --git a/libguile/foreign-object.c b/libguile/foreign-object.c
> new file mode 100644
> index 0000000..78b017a
> --- /dev/null
> +++ b/libguile/foreign-object.c
> @@ -0,0 +1,187 @@
> +/* Copyright (C) 2014 Free Software Foundation, Inc.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public License=
> + * as published by the Free Software Foundation; either version 3 of<= br> > + * the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful, bu= t
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. =C2=A0See the= GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, write to the Free Softwar= e
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + */
> +
> +
> +=0C
> +#ifdef HAVE_CONFIG_H
> +# =C2=A0include <config.h>
> +#endif
> +
> +#include "libguile/_scm.h"
> +#include "libguile/goops.h"
> +#include "libguile/foreign-object.h"
> +
> +
> +=0C
> +
> +static SCM make_fobj_type_var;
> +
> +static void
> +init_make_fobj_type_var (void)
> +{
> + =C2=A0make_fobj_type_var =3D scm_c_private_lookup ("system fore= ign-object",
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 "make-foreign-object-type");
> +}
> +
> +SCM
> +scm_make_foreign_object_type (SCM name, SCM slot_names,
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0scm_t_struct_finalize finalizer)
> +{
> + =C2=A0SCM type;
> +
> + =C2=A0static scm_i_pthread_once_t once =3D SCM_I_PTHREAD_ONCE_INIT;<= br> > + =C2=A0scm_i_pthread_once (&once, init_make_fobj_type_var);

Good!

> +
> + =C2=A0type =3D scm_call_2 (scm_variable_ref (make_fobj_type_var), na= me, slot_names);
> +
> + =C2=A0if (finalizer)
> + =C2=A0 =C2=A0SCM_SET_VTABLE_INSTANCE_FINALIZER (type, finalizer); > +
> + =C2=A0return type;
> +}
> +
> +void
> +scm_assert_foreign_object_type (SCM type, SCM val)
> +{
> + =C2=A0if (!SCM_IS_A_P (val, type))
> + =C2=A0 =C2=A0scm_error (scm_arg_type_key, NULL, "Wrong type (ex= pecting ~A): ~S",
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 scm_list_2 (scm_cla= ss_name (type), val), scm_list_1 (val));
> +}
> +
> +SCM
> +scm_make_foreign_object_1 (SCM type, scm_t_bits val0)
> +{
> + =C2=A0return scm_make_foreign_object_n (type, 1, &val0);
> +}
> +
> +SCM
> +scm_make_foreign_object_2 (SCM type, scm_t_bits val0, scm_t_bits val1= )
> +{
> + =C2=A0scm_t_bits vals[2] =3D { val0, val1 };

This non-constant initializer depends on C99. =C2=A0We discussed this on IR= C,
and IIRC we agreed that we should transition to requiring C99 for 2.2,
but making that change in 2.0 is potentially disruptive.

> +
> + =C2=A0return scm_make_foreign_object_n (type, 2, vals);
> +}
> +
> +SCM
> +scm_make_foreign_object_3 (SCM type, scm_t_bits val0, scm_t_bits val1= ,
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 scm_t_bits val2)
> +{
> + =C2=A0scm_t_bits vals[3] =3D { val0, val1, val2 };

Ditto.

> +
> + =C2=A0return scm_make_foreign_object_n (type, 3, vals);
> +}
> +
> +SCM
> +scm_make_foreign_object_n (SCM type, size_t n, scm_t_bits vals[])
> +#define FUNC_NAME "make-foreign-object"
> +{
> + =C2=A0SCM obj;
> + =C2=A0SCM layout;
> + =C2=A0size_t i;
> +
> + =C2=A0SCM_VALIDATE_VTABLE (SCM_ARG1, type);
> +
> + =C2=A0layout =3D SCM_VTABLE_LAYOUT (type);
> +
> + =C2=A0if (scm_i_symbol_length (layout) / 2 < n)
> + =C2=A0 =C2=A0scm_out_of_range (FUNC_NAME, scm_from_size_t (n));
> +
> + =C2=A0for (i =3D 0; i < n; i++)
> + =C2=A0 =C2=A0if (scm_i_symbol_ref (layout, i * 2) !=3D 'u')<= br> > + =C2=A0 =C2=A0 =C2=A0scm_wrong_type_arg_msg (FUNC_NAME, 0, layout, &q= uot;'u' field");

This looks inefficient. =C2=A0How about using 'scm_i_symbol_chars'?=

> +
> + =C2=A0obj =3D scm_c_make_structv (type, 0, 0, NULL);
> +
> + =C2=A0for (i =3D 0; i < n; i++)
> + =C2=A0 =C2=A0SCM_STRUCT_DATA_SET (obj, i, vals[i]);
> +
> + =C2=A0return obj;
> +}
> +#undef FUNC_NAME
[...]

=C2=A0 =C2=A0 Thanks!
=C2=A0 =C2=A0 =C2=A0 Mark

--047d7b86f7dc3276a504f808f130--