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.
This commit is contained in:
Douglas Katzman 2023-07-06 11:24:22 -04:00
parent 303e68681e
commit a822ffb50d
5 changed files with 177 additions and 221 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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_ */

View file

@ -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