diff --git a/CHANGELOG b/CHANGELOG index a518af06a..d25ead654 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -53,8 +53,6 @@ - Update bundled libgc-8.2.4 to libgc-8.2.8. -- Remove the feature "small cons" and its build flags - * 24.5.10 changes since 23.9.9 ** Announcement Dear Community, diff --git a/src/c/alloc_2.d b/src/c/alloc_2.d index 7504261b0..08529ad42 100644 --- a/src/c/alloc_2.d +++ b/src/c/alloc_2.d @@ -374,10 +374,16 @@ ecl_cons(cl_object a, cl_object d) ecl_disable_interrupts_env(the_env); obj = GC_MALLOC(sizeof(struct ecl_cons)); ecl_enable_interrupts_env(the_env); +#ifdef ECL_SMALL_CONS + obj->car = a; + obj->cdr = d; + return ECL_PTR_CONS(obj); +#else obj->t = t_list; obj->car = a; obj->cdr = d; return (cl_object)obj; +#endif } cl_object diff --git a/src/configure b/src/configure index 862c8b69b..e7316ab0b 100755 --- a/src/configure +++ b/src/configure @@ -7380,6 +7380,11 @@ printf "%s\n" "#define ECL_EXTERNALIZABLE /**/" >>confdefs.h fi fi +if test ${enable_smallcons} = "yes" ; then + +printf "%s\n" "#define ECL_SMALL_CONS /**/" >>confdefs.h + +fi diff --git a/src/configure.ac b/src/configure.ac index 94de25a25..309c03ea0 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -605,6 +605,9 @@ if test ${enable_boehm} = "no" ; then else ECL_BOEHM_GC fi +if test ${enable_smallcons} = "yes" ; then + AC_DEFINE([ECL_SMALL_CONS], [], [ECL_SMALL_CONS]) +fi ECL_LIBFFI diff --git a/src/doc/manual/developer-guide/objects.txi b/src/doc/manual/developer-guide/objects.txi index 6565f1d6b..dca69e926 100644 --- a/src/doc/manual/developer-guide/objects.txi +++ b/src/doc/manual/developer-guide/objects.txi @@ -63,6 +63,35 @@ type of object. For instance, a cons cell consists of three words: +--------------------+ @end verbatim +@cfindex --enable-small-cons [YES|no] + +Note, that this is one of the possible implementation of +@code{cons}. The second one (currently default) uses the immediate value +for the @code{list} and consumes two words instead of three. Such +implementation is more memory and speed efficient (according to the +comments in the source code): + +@verbatim +/* + * CONSES + * + * We implement two variants. The "small cons" type carries the type + * information in the least significant bits of the pointer. We have + * to do some pointer arithmetics to find out the CAR / CDR of the + * cons but the overall result is faster and memory efficient, only + * using two words per cons. + * + * The other scheme stores conses as three-words objects, the first + * word carrying the type information. This is kept for backward + * compatibility and also because the oldest garbage collector does + * not yet support the smaller datatype. + * + * To make code portable and independent of the representation, only + * access the objects using the common macros below (that is all + * except ECL_CONS_PTR or ECL_PTR_CONS). + */ +@end verbatim + @cppdef cl_object @deftp @cind{} cl_object This is the type of a lisp object. For your C/C++ program, a cl_object diff --git a/src/ecl/configpre.h b/src/ecl/configpre.h index 5ea2536fa..66223eeb1 100644 --- a/src/ecl/configpre.h +++ b/src/ecl/configpre.h @@ -48,6 +48,9 @@ /* ECL_SIGNED_ZERO */ #undef ECL_SIGNED_ZERO +/* ECL_SMALL_CONS */ +#undef ECL_SMALL_CONS + /* ECL_SSE2 */ #undef ECL_SSE2 diff --git a/src/h/config.h.in b/src/h/config.h.in index 2a7f1cce2..e937e23be 100644 --- a/src/h/config.h.in +++ b/src/h/config.h.in @@ -206,6 +206,9 @@ typedef unsigned char ecl_base_char; /* do we want NaNs and Infs */ #undef ECL_IEEE_FP +/* We can use small, two-words conses, without type information */ +#undef ECL_SMALL_CONS + /* Do we use C or C++ compiler to compile ecl? */ #undef ECL_CXX_CORE diff --git a/src/h/object.h b/src/h/object.h index ed0fdc271..ee35bb6be 100644 --- a/src/h/object.h +++ b/src/h/object.h @@ -331,8 +331,43 @@ enum { ECL_INHERITED }; -/* CONSES */ +/* + * CONSES + * + * We implement two variants. The "small cons" type carries the type + * information in the least significant bits of the pointer. We have + * to do some pointer arithmetics to find out the CAR / CDR of the + * cons but the overall result is faster and memory efficient, only + * using two words per cons. + * + * The other scheme stores conses as three-words objects, the first + * word carrying the type information. This is kept for backward + * compatibility and also because the oldest garbage collector does + * not yet support the smaller datatype. + * + * To make code portable and independent of the representation, only + * access the objects using the common macros below (that is all + * except ECL_CONS_PTR or ECL_PTR_CONS). + */ +#ifdef ECL_SMALL_CONS +#define ECL_LISTP(x) (ECL_IMMEDIATE(x) == t_list) +#define ECL_CONSP(x) (LISTP(x) && !Null(x)) +#define ECL_ATOM(x) (Null(x) || !LISTP(x)) +#define ECL_SYMBOLP(x) (Null(x) || ((ECL_IMMEDIATE(x) == 0) && ((x)->d.t == t_symbol))) + +#define ECL_PTR_CONS(x) (cl_object)((char*)(x) + t_list) +#define ECL_CONS_PTR(x) ((struct ecl_cons *)((char *)(x) - t_list)) +#define ECL_CONS_CAR(x) (*(cl_object*)((char *)(x) - t_list)) +#define ECL_CONS_CDR(x) (*(cl_object*)((char *)(x) + sizeof(cl_object) - t_list)) +#define ECL_RPLACA(x,v) (ECL_CONS_CAR(x)=(v)) +#define ECL_RPLACD(x,v) (ECL_CONS_CDR(x)=(v)) + +struct ecl_cons { + cl_object car; /* car */ + cl_object cdr; /* cdr */ +}; +#else #define ECL_LISTP(x) (ECL_IMMEDIATE(x)? Null(x) : ((x)->d.t == t_list)) #define ECL_CONSP(x) ((ECL_IMMEDIATE(x) == 0) && ((x)->d.t == t_list)) #define ECL_ATOM(x) (ECL_IMMEDIATE(x) || ((x)->d.t != t_list)) @@ -348,6 +383,7 @@ struct ecl_cons { cl_object car; /* car */ cl_object cdr; /* cdr */ }; +#endif enum ecl_httest { /* hash table key test function */ ecl_htt_eq, /* eq */ @@ -1088,7 +1124,9 @@ struct ecl_sse_pack { Definition of lispunion. */ union cl_lispunion { - struct ecl_cons cons; /* cons */ +#ifndef ECL_SMALL_CONS + struct ecl_cons cons; /* unoptimized cons */ +#endif struct ecl_bignum big; /* bignum */ struct ecl_ratio ratio; /* ratio */ struct ecl_singlefloat SF; /* single floating-point number */