From a822ffb50dba95c0ddb0ba923295c8d6325a2a31 Mon Sep 17 00:00:00 2001 From: Douglas Katzman Date: Thu, 6 Jul 2023 11:24:22 -0400 Subject: [PATCH] Improve header layering Rearranging lispobj.h and runtime.h to put object-representation-related macros in the former makes genesis/gc-tables.h self-contained, i.e. having no need for pthreads.h and signal.h and and everything that runtime.h pulls in. I thought fixnump.h stemmed from one of my early failed attempts to do this but, no, it was here since 2004. Just fold it into lispobj.h now. --- src/runtime/fixnump.h | 20 ---- src/runtime/gc-internal.h | 2 - src/runtime/lispobj.h | 177 ++++++++++++++++++++++++++++++++++ src/runtime/runtime.h | 194 -------------------------------------- tests/genheaders.test.sh | 5 - 5 files changed, 177 insertions(+), 221 deletions(-) delete mode 100644 src/runtime/fixnump.h diff --git a/src/runtime/fixnump.h b/src/runtime/fixnump.h deleted file mode 100644 index 756e2eaa4..000000000 --- a/src/runtime/fixnump.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * This software is part of the SBCL system. See the README file for - * more information. - * - * This software is derived from the CMU CL system, which was - * written at Carnegie Mellon University and released into the - * public domain. The software is in the public domain and is - * provided with absolutely no warranty. See the COPYING and CREDITS - * files for more information. - */ - -#ifndef _FIXNUMP_H -#define _FIXNUMP_H - -static inline int fixnump(lispobj obj) -{ - return((obj & FIXNUM_TAG_MASK) == 0); -} - -#endif diff --git a/src/runtime/gc-internal.h b/src/runtime/gc-internal.h index c1d3ad65d..ea09ef72b 100644 --- a/src/runtime/gc-internal.h +++ b/src/runtime/gc-internal.h @@ -149,8 +149,6 @@ void gencgc_apply_code_fixups(struct code *old_code, struct code *new_code); #define gencgc_apply_code_fixups(ignore1,ignore2) #endif -#include "fixnump.h" - #if N_WORD_BITS == 32 # define SIMPLE_ARRAY_WORD_WIDETAG SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG #elif N_WORD_BITS == 64 diff --git a/src/runtime/lispobj.h b/src/runtime/lispobj.h index 1f5f7bc4d..f8f22e88e 100644 --- a/src/runtime/lispobj.h +++ b/src/runtime/lispobj.h @@ -6,4 +6,181 @@ typedef intptr_t sword_t; typedef uintptr_t uword_t; typedef uword_t lispobj; +#include "sbcl.h" + +static inline int fixnump(lispobj obj) +{ + return((obj & FIXNUM_TAG_MASK) == 0); +} + +static inline int header_widetag(lispobj obj) +{ + return obj & WIDETAG_MASK; +} + +static inline uword_t HeaderValue(lispobj obj) +{ + return obj >> N_WIDETAG_BITS; +} + +/* Is the Lisp object obj something with immediate nature (e.g. a + * fixnum or character or unbound marker)? */ +static inline int +is_lisp_immediate(lispobj obj) +{ + int widetag; + return (fixnump(obj) + || ((widetag = header_widetag(obj)) == CHARACTER_WIDETAG) +#if N_WORD_BITS == 64 + || (widetag == SINGLE_FLOAT_WIDETAG) +#endif + || (widetag == UNBOUND_MARKER_WIDETAG)); +} + +static inline int lowtag_of(lispobj obj) +{ + return obj & LOWTAG_MASK; +} + +static inline int widetag_of(lispobj* obj) +{ +#ifdef LISP_FEATURE_BIG_ENDIAN + return ((unsigned char*)obj)[N_WORD_BYTES-1]; +#else + return *(unsigned char*)obj; +#endif +} + +static inline int listp(lispobj obj) { + return lowtag_of(obj) == LIST_POINTER_LOWTAG; +} +static inline int instancep(lispobj obj) { + return lowtag_of(obj) == INSTANCE_POINTER_LOWTAG; +} +static inline int functionp(lispobj obj) { + return lowtag_of(obj) == FUN_POINTER_LOWTAG; +} +static inline int other_pointer_p(lispobj obj) { + return lowtag_of(obj) == OTHER_POINTER_LOWTAG; +} +static inline int simple_vector_p(lispobj obj) { + return other_pointer_p(obj) && + widetag_of((lispobj*)(obj-OTHER_POINTER_LOWTAG)) == SIMPLE_VECTOR_WIDETAG; +} + +/* Convert from a lispobj with type bits to a native (ordinary + * C/assembly) pointer to the beginning of the object. */ +static inline lispobj * +native_pointer(lispobj obj) +{ + return (lispobj *) ((uintptr_t) (obj & ~LOWTAG_MASK)); +} + +/* inverse operation: create a suitably tagged lispobj from a native pointer. */ +static inline lispobj +make_lispobj(void *o, int low_tag) +{ + return (lispobj)o | low_tag; +} + +#define make_fixnum(n) ((uword_t)(n) << N_FIXNUM_TAG_BITS) + +static inline sword_t +fixnum_value(lispobj n) +{ + return (sword_t)n >> N_FIXNUM_TAG_BITS; +} + +/* Is the Lisp object obj something with pointer nature (as opposed to + * e.g. a fixnum or character or unbound marker)? */ +static inline int is_lisp_pointer(lispobj obj) +{ +#ifdef LISP_FEATURE_PPC64 + return (obj & 5) == 4; +#elif N_WORD_BITS == 64 + return (obj & 3) == 3; +#else + return obj & 1; +#endif +} + +static inline int is_cons_half(lispobj obj) +{ + if (fixnump(obj) || is_lisp_pointer(obj)) return 1; + int widetag = header_widetag(obj); + return widetag == CHARACTER_WIDETAG || +#if N_WORD_BITS == 64 + widetag == SINGLE_FLOAT_WIDETAG || +#endif + widetag == UNBOUND_MARKER_WIDETAG; +} + +/* Each size category is designed to allow for some flag bits, and the payload + * length in words, which is always an odd number so that total word count is even. + * There are three size categories for most non-vector objects, + * differing in how many flag bits versus size bits there are. + */ + +/* The largest payload count is expressed in 23 bits. These objects + * can't reside in immobile space as there is no room for generation bits. + * All sorts of objects fall into this category, but mostly due to inertia. + * There are no non-vector boxed objects whose size should be so large. + * Header: size | tag + * ----- ------ + * 23 bits | 8 bits + */ +#define BOXED_NWORDS(obj) ((HeaderValue(obj) & 0x7FFFFF) | 1) + +/* Medium-sized payload count is expressed in 15 bits. Objects in this category + * may reside in immobile space: CLOSURE, FUNCALLABLE-INSTANCE. + * The single data bit is used as a closure's NAMED flag. + * + * Header: gen# | data | size | tag + * ----- ----- ------- ------ + * 8 bits | 1 bit | 15 bits | 8 bits + */ +#define SHORT_BOXED_NWORDS(obj) ((HeaderValue(obj) & SHORT_HEADER_MAX_WORDS) | 1) + +/* Tiny payload count is expressed in 8 bits. Objects in this size category + * can reside in immobile space: SYMBOL, FDEFN. + * Header: gen# | flags | size | tag + * ----- ------ ------ ------ + * 8 bits 8 bits 8 bits | 8 bits + * FDEFN flag bits: 1 bit for statically-linked + * SYMBOL flag bits: 1 bit for present in initial core image + */ +#define TINY_BOXED_NWORDS(obj) ((HeaderValue(obj) & 0xFF) | 1) + +// other_immediate_lowtag_p is the least strict of the tests for whether a word +// is potentially an object header, merely checking whether the bits fit the general +// pattern of header widetags without regard for whether some headered object type +// could in fact have those exact low bits. Specifically, this falsely returns 1 +// for UNBOUND_MARKER_WIDETAG, CHARACTER_WIDETAG, and on 64-bit machines, +// SINGLE_FLOAT_WIDETAG; as well as unallocated and unused widetags (e.g. LRA on x86) +// none of which denote the start of a headered object. +// The ambiguous cases are for words would start a cons - the three mentioned above. +// Other cases (NO_TLS_VALUE_MARKER_WIDETAG and other things) do not cause a problem +// in practice because they can't be the first word of a lisp object. +static inline int other_immediate_lowtag_p(lispobj header) +{ + /* These lowtags are spaced 4 apart throughout the lowtag space. */ + return (lowtag_of(header) & 3) == OTHER_IMMEDIATE_0_LOWTAG; +} + +// widetag_lowtag encodes in the sign bit whether the byte corresponds +// to a headered object, and in the low bits the lowtag of a tagged pointer +// pointing to this object, be it headered or a cons. +extern unsigned char widetag_lowtag[256]; +#define LOWTAG_FOR_WIDETAG(x) (widetag_lowtag[x] & LOWTAG_MASK) + +// is_header() and is_cons_half() are logical complements when invoked +// on the first word of any lisp object. However, given a word which is +// only *potentially* the first word of a lisp object, they can both be false. +// In ambiguous root detection, is_cons_half() is to be used, as it is the more +// stringent check. The set of valid bit patterns in the low byte of the car +// of a cons is smaller than the set of patterns accepted by !is_header(). +static inline int is_header(lispobj potential_header_word) { + return widetag_lowtag[potential_header_word & WIDETAG_MASK] & 0x80; +} + #endif diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index d18d68e4c..048047978 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -143,104 +143,6 @@ void dyndebug_init(void); #define OBJ_FMTX PRIxPTR -static inline int -lowtag_of(lispobj obj) -{ - return obj & LOWTAG_MASK; -} - -static inline int -widetag_of(lispobj* obj) -{ -#ifdef LISP_FEATURE_BIG_ENDIAN - return ((unsigned char*)obj)[N_WORD_BYTES-1]; -#else - return *(unsigned char*)obj; -#endif -} -static inline int -header_widetag(lispobj obj) -{ - return obj & WIDETAG_MASK; -} - -static inline uword_t -HeaderValue(lispobj obj) -{ - return obj >> N_WIDETAG_BITS; -} - -static inline int listp(lispobj obj) { - return lowtag_of(obj) == LIST_POINTER_LOWTAG; -} -static inline int instancep(lispobj obj) { - return lowtag_of(obj) == INSTANCE_POINTER_LOWTAG; -} -static inline int functionp(lispobj obj) { - return lowtag_of(obj) == FUN_POINTER_LOWTAG; -} -static inline int other_pointer_p(lispobj obj) { - return lowtag_of(obj) == OTHER_POINTER_LOWTAG; -} -static inline int simple_vector_p(lispobj obj) { - return other_pointer_p(obj) && - widetag_of((lispobj*)(obj-OTHER_POINTER_LOWTAG)) == SIMPLE_VECTOR_WIDETAG; -} - -/* Is the Lisp object obj something with pointer nature (as opposed to - * e.g. a fixnum or character or unbound marker)? */ -static inline int -is_lisp_pointer(lispobj obj) -{ -#ifdef LISP_FEATURE_PPC64 - return (obj & 5) == 4; -#elif N_WORD_BITS == 64 - return (obj & 3) == 3; -#else - return obj & 1; -#endif -} - -#include "fixnump.h" - -/* Is the Lisp object obj something with immediate nature (e.g. a - * fixnum or character or unbound marker)? */ -static inline int -is_lisp_immediate(lispobj obj) -{ - int widetag; - return (fixnump(obj) - || ((widetag = header_widetag(obj)) == CHARACTER_WIDETAG) -#if N_WORD_BITS == 64 - || (widetag == SINGLE_FLOAT_WIDETAG) -#endif - || (widetag == UNBOUND_MARKER_WIDETAG)); -} - -/* Convert from a lispobj with type bits to a native (ordinary - * C/assembly) pointer to the beginning of the object. */ -static inline lispobj * -native_pointer(lispobj obj) -{ - return (lispobj *) ((uintptr_t) (obj & ~LOWTAG_MASK)); -} - -/* inverse operation: create a suitably tagged lispobj from a native - * pointer or integer.*/ -static inline lispobj -make_lispobj(void *o, int low_tag) -{ - return (lispobj)o | low_tag; -} - -#define make_fixnum(n) ((uword_t)(n) << N_FIXNUM_TAG_BITS) - -static inline sword_t -fixnum_value(lispobj n) -{ - return (sword_t)n >> N_FIXNUM_TAG_BITS; -} - #include "align.h" #if defined(LISP_FEATURE_WIN32) @@ -258,51 +160,6 @@ fixnum_value(lispobj n) #endif typedef int boolean; -// other_immediate_lowtag_p is the least strict of the tests for whether a word -// is potentially an object header, merely checking whether the bits fit the general -// pattern of header widetags without regard for whether some headered object type -// could in fact have those exact low bits. Specifically, this falsely returns 1 -// for UNBOUND_MARKER_WIDETAG, CHARACTER_WIDETAG, and on 64-bit machines, -// SINGLE_FLOAT_WIDETAG; as well as unallocated and unused widetags (e.g. LRA on x86) -// none of which denote the start of a headered object. -// The ambiguous cases are for words would start a cons - the three mentioned above. -// Other cases (NO_TLS_VALUE_MARKER_WIDETAG and other things) do not cause a problem -// in practice because they can't be the first word of a lisp object. -static inline boolean -other_immediate_lowtag_p(lispobj header) -{ - /* These lowtags are spaced 4 apart throughout the lowtag space. */ - return (lowtag_of(header) & 3) == OTHER_IMMEDIATE_0_LOWTAG; -} - -// widetag_lowtag encodes in the sign bit whether the byte corresponds -// to a headered object, and in the low bits the lowtag of a tagged pointer -// pointing to this object, be it headered or a cons. -extern unsigned char widetag_lowtag[256]; -#define LOWTAG_FOR_WIDETAG(x) (widetag_lowtag[x] & LOWTAG_MASK) - -// is_header() and is_cons_half() are logical complements when invoked -// on the first word of any lisp object. However, given a word which is -// only *potentially* the first word of a lisp object, they can both be false. -// In ambiguous root detection, is_cons_half() is to be used, as it is the more -// stringent check. The set of valid bit patterns in the low byte of the car -// of a cons is smaller than the set of patterns accepted by !is_header(). -static inline int is_header(lispobj potential_header_word) { - return widetag_lowtag[potential_header_word & WIDETAG_MASK] & 0x80; -} - -static inline int -is_cons_half(lispobj obj) -{ - if (fixnump(obj) || is_lisp_pointer(obj)) return 1; - int widetag = header_widetag(obj); - return widetag == CHARACTER_WIDETAG || -#if N_WORD_BITS == 64 - widetag == SINGLE_FLOAT_WIDETAG || -#endif - widetag == UNBOUND_MARKER_WIDETAG; -} - /* KLUDGE: As far as I can tell there's no ANSI C way of saying * "this function never returns". This is the way that you do it * in GCC later than version 2.5 or so. */ @@ -365,55 +222,4 @@ extern struct lisp_startup_options lisp_startup_options; #define NO_SANITIZE_MEMORY #endif -/// Object sizing macros. One of these days I'd like to rationalize -/// all our headers making them more intuitive as to which need be -/// included to get access to various things. -/// For the time being, this file makes as much sense as anything else. - -/// These sizing macros return the number of *payload* words, -/// exclusive of the object header word. Payload length is always -/// an odd number so that total word count is an even number. - -/* Each size category is designed to allow 1 bit for a GC mark bit, - * possibly some flag bits, and the payload length in words. - * There are three size categories for most non-vector objects, - * differing in how many flag bits versus size bits there are. - * The GC mark bit is always in bit index 31 of the header regardless of - * machine word size. Bit index 31 is chosen for consistency between 32-bit - * and 64-bit machines. It is a natural choice for 32-bit headers by avoiding - * intererence with other header fields. It is also chosen for 64-bit headers - * because the upper 32 bits of headers for some objects are already occupied - * by other data: symbol TLS index, instance layout, etc. - */ - -/* The largest payload count is expressed in 23 bits. These objects - * can't reside in immobile space as there is no room for generation bits. - * All sorts of objects fall into this category, but mostly due to inertia. - * There are no non-vector boxed objects whose size should be so large. - * Header: size | tag - * ----- ------ - * 23 bits | 8 bits - */ -#define BOXED_NWORDS(obj) ((HeaderValue(obj) & 0x7FFFFF) | 1) - -/* Medium-sized payload count is expressed in 15 bits. Objects in this category - * may reside in immobile space: CLOSURE, FUNCALLABLE-INSTANCE. - * The single data bit is used as a closure's NAMED flag. - * - * Header: gen# | data | size | tag - * ----- ----- ------- ------ - * 8 bits | 1 bit | 15 bits | 8 bits - */ -#define SHORT_BOXED_NWORDS(obj) ((HeaderValue(obj) & SHORT_HEADER_MAX_WORDS) | 1) - -/* Tiny payload count is expressed in 8 bits. Objects in this size category - * can reside in immobile space: SYMBOL, FDEFN. - * Header: gen# | flags | size | tag - * ----- ------ ------ ------ - * 8 bits 8 bits 8 bits | 8 bits - * FDEFN flag bits: 1 bit for statically-linked - * SYMBOL flag bits: 1 bit for present in initial core image - */ -#define TINY_BOXED_NWORDS(obj) ((HeaderValue(obj) & 0xFF) | 1) - #endif /* _SBCL_RUNTIME_H_ */ diff --git a/tests/genheaders.test.sh b/tests/genheaders.test.sh index 8003c3b3d..eac443860 100755 --- a/tests/genheaders.test.sh +++ b/tests/genheaders.test.sh @@ -39,13 +39,8 @@ if [ -r $TEST_DIRECTORY/array.h ] then for i in $TEST_DIRECTORY/*.h do - case $i in - */gc-tables.h) ;; # fails to compile by itself (FIXME) - *) echo "#include \"$i\"" > ${src} ./run-compiler.sh -I../src/runtime -c -o ${obj} ${src} - ;; - esac done fi