Always define page_words_t as 'unsigned short'

And rob 1 bit of that, so it's effectively 15 bits, not 16.
Then free up 2 more bits of 'type' for other use as I tried to do
in rev 938320b209 which was reverted. Taking a different bit in the
PTE should be fine, and the resulting code looks better for it.
This commit is contained in:
Douglas Katzman 2022-08-04 22:18:36 -04:00
parent 1a0a291c06
commit 3bfea7ffd3
7 changed files with 44 additions and 56 deletions

View file

@ -829,9 +829,7 @@ Experimental: interface subject to change."
(let* ((wp (page-protected-p object))
(index (sb-vm:find-page-index
(get-lisp-obj-address object)))
(flags (sb-alien:slot page 'sb-vm::flags))
(type #+little-endian (ldb (byte 6 0) flags)
#+big-endian (ldb (byte 6 2) flags)))
(type (sb-alien:slot page 'sb-vm::flags)))
(list :space space
:generation (sb-alien:slot page 'sb-vm::gen)
:write-protected wp

View file

@ -483,14 +483,9 @@ statistics are appended to it."
;; but if 64-bit then we have to scale the value. Additionally
;; there is a fallback for when even the scaled value is too big.
(sb-vm::start #+64-bit (unsigned 32) #-64-bit signed)
;; On platforms with small enough GC pages, this field
;; will be a short. On platforms with larger ones, it'll
;; be an int. It should probably never be an int.
(sb-vm::words-used (unsigned
#.(if (typep sb-vm::gencgc-page-words '(unsigned-byte 16))
16
32)))
(sb-vm::flags (unsigned 8)) ; in C this is {type, need_zerofill, pinned}
;; Caution: The low bit of WORDS-USED* is a flag bit
(sb-vm::words-used* (unsigned 16)) ; (* in the name is a memory aid)
(sb-vm::flags (unsigned 8)) ; this named 'type' in C
(sb-vm::gen (signed 8))))
(define-alien-variable ("page_table" sb-vm:page-table) (* (struct sb-vm::page)))
(declaim (inline sb-vm:find-page-index))

View file

@ -386,7 +386,8 @@ We could try a few things to mitigate this:
start-page end-page))
(setq end-page start-page)
(loop (setq end-page-bytes-used
(ash (slot (deref page-table end-page) 'words-used) word-shift))
(ash (ash (slot (deref page-table end-page) 'words-used*) -1)
word-shift))
;; See 'page_ends_contiguous_block_p' in gencgc.c
(when (or (< end-page-bytes-used gencgc-page-bytes)
(= (slot (deref page-table (1+ end-page)) 'start) 0))
@ -400,10 +401,7 @@ We could try a few things to mitigate this:
end-page-bytes-used)
most-positive-word)))))
(when (sap> end start)
;; The bits in the 6-bit 'type' field have fixed positions,
;; but the position of the field itself depends on endianness.
(let ((flags (ldb (byte 6 (+ #+big-endian 2))
(slot (deref page-table start-page) 'flags))))
(let ((flags (slot (deref page-table start-page) 'flags)))
;; The GEN slot is declared as (SIGNED 8) which does not satisfy the
;; type restriction on the first argument to LOGBITP.
;; Masking it to 3 bits fixes that, and allows using the other 5 bits
@ -1157,8 +1155,8 @@ We could try a few things to mitigate this:
(setq page-num next-page seen-filler nil))))))))
(let ((i 0))
(loop while (< i total-pages)
do (let ((type (ldb (byte 2 0) (slot (deref page-table i) 'flags))))
(if (= type 3)
do (let ((type (slot (deref page-table i) 'flags)))
(if (= (logand type 7) 7)
(setq i (dump-page i))
(incf i)))))
(let* ((n-pages (count 1 pages))
@ -1227,8 +1225,7 @@ We could try a few things to mitigate this:
;; gen0 conses on MIXED pages, but even that is not enough- pinned conses
;; will promote but keep their MIXED page type. So don't bother with this.
#+use-cons-region
(let* ((flags (slot (deref page-table (find-page-index obj-addr)) 'flags))
(type (ldb (byte 6 (+ #+big-endian 2)) flags))
(let* ((type (slot (deref page-table (find-page-index obj-addr)) 'flags))
(ok (if (consp obj)
(or (= type #b101) ; PAGE_TYPE_CONS
(and (eq (car obj) 0) (eq (cdr obj) 0)))

View file

@ -48,15 +48,16 @@ int gencgc_handle_wp_violation(void*, void*);
# define CONDENSED_PAGE_TABLE 0
#endif
#if GENCGC_PAGE_WORDS > USHRT_MAX
# if GENCGC_PAGE_WORDS > UINT_MAX
/* One bit of page_words_t is the need_zerofill flag.
* That leaves 15 bits to store page_words_used. This can represent
* a page size of up to 64KiB on 32-bit and 128KiB on 64-bit.
* Note that since the allocation quantum is actually 2 words
* the words_used is always an even number, and so technically
* we could store as "dualwords used" to achieve double the range */
#if GENCGC_PAGE_WORDS > 32767
# error "GENCGC_PAGE_WORDS unexpectedly large."
# else
typedef unsigned int page_words_t;
# endif
#else
typedef unsigned short page_words_t;
#endif
typedef unsigned short page_words_t;
/* New objects are allocated to PAGE_TYPE_MIXED or PAGE_TYPE_CONS */
/* If you change these constants, then possibly also change the following
@ -114,14 +115,22 @@ struct page {
/* the number of lispwords of this page that are used. This may be less
* than the usage at an instant in time for pages within the current
* allocation regions. MUST be 0 for unallocated pages.
*/
page_words_t words_used_;
* allocation regions. The 0th bit of the physical uint16 indicates
* that the page needs to be zero-filled for the next use.
* Let the C compiler figure it out, so we can't get it wrong in C.
* But we need to reverse the order of the packed fields depending on
* endianness so that the Lisp side is easier to understand */
#ifdef LISP_FEATURE_BIG_ENDIAN
page_words_t words_used_ : 15;
page_words_t need_zerofill : 1;
#else
page_words_t need_zerofill : 1;
page_words_t words_used_ : 15;
#endif
// !!! If bit positions are changed, be sure to reflect the changes into
// page_extensible_p() as well as ALLOCATION-INFORMATION in sb-introspect
// and WALK-DYNAMIC-SPACE.
unsigned char
/*
* The 4 low bits of 'type' are defined by PAGE_TYPE_x constants.
* 0000 free
@ -129,12 +138,12 @@ struct page {
* ?010 strictly unboxed data
* ?011 mixed boxed/unboxed non-code objects
* ?111 code
* The next two bits are SINGLE_OBJECT and OPEN_REGION */
type :6,
/* Whether the page was used at all. This is the only bit that can
* be 1 on a free page */
need_zerofill :1,
dontuse :1;
* The next two bits are SINGLE_OBJECT and OPEN_REGION.
* The top two can be used for segregating objects by widetag
* which will important once we have "destructors" to run for a
* for a category of object, such as SYMBOL, hypothetically for
* recycling TLS indices or something like that. */
unsigned char type;
/* the generation that this page belongs to. This should be valid
* for all pages that may have objects allocated, even current

View file

@ -220,7 +220,6 @@ static inline void reset_page_flags(page_index_t page) {
if (page_table[page].type == PAGE_TYPE_CODE) set_page_need_to_zero(page, 1);
#endif
page_table[page].type = 0;
page_table[page].dontuse = 0;
gc_page_pins[page] = 0;
// Why can't the 'gen' get cleared? It caused failures. THIS MAKES NO SENSE!!!
// page_table[page].gen = 0;
@ -955,18 +954,8 @@ page_extensible_p(page_index_t index, generation_index_t gen, int type) {
&& page_table[index].gen == gen
&& !gc_page_pins[index];
#else
/* Test the three conditions above as a single comparison.
*
* pin -\
* v vvvvvv -- type
* #b11111111_10111111
* ^
* need_zerofill (ignored)
*
* The flags reside at 1 byte prior to 'gen' in the page structure.
*/
int attributes_match =
(*(int16_t*)(&page_table[index].gen-1) & 0xFFBF) == ((gen<<8)|type);
*(int16_t*)&page_table[index].type == ((gen<<8)|type);
#endif
#ifdef LISP_FEATURE_SOFT_CARD_MARKS
return attributes_match && page_cards_all_marked_nonsticky(index);

View file

@ -41,9 +41,8 @@
(declare (ignore widetag))
(let* ((index
(sb-vm::find-page-index (sb-kernel:get-lisp-obj-address obj)))
(type (ldb (byte 6 (+ #+big-endian 2))
(sb-alien:slot (sb-alien:deref sb-vm::page-table index)
'sb-vm::flags))))
(type (sb-alien:slot (sb-alien:deref sb-vm::page-table index)
'sb-vm::flags)))
;; mask off the SINGLE_OBJECT and OPEN_REGION bits
(when (and (eq (logand type 7) 2) ; PAGE_TYPE_BOXED
;; Cons cells on boxed pags are page filler

View file

@ -33,9 +33,10 @@
#+gencgc
(progn
(defun page-words-used (index)
(ash (slot (deref sb-vm::page-table index) 'sb-vm::words-used*) -1))
(defun page-need-to-zero (index)
(logbitp #+little-endian 6 #+big-endian 1
(slot (deref sb-vm::page-table index) 'sb-vm::flags)))
(oddp (slot (deref sb-vm::page-table index) 'sb-vm::words-used*)))
(defun test-private-consing ()
(let ((conses-per-page ; subtract one for the page header cons
(1- (/ sb-vm:gencgc-page-bytes (* 2 sb-vm:n-word-bytes))))
@ -51,7 +52,7 @@
(push index pages)
(assert (= cons (+ base-address (* 2 sb-vm:n-word-bytes))))
;; words-used should be 4, for 2 conses,
(assert (= (slot (deref sb-vm::page-table index) 'sb-vm::words-used) 4))
(assert (= (page-words-used index) 4))
(dotimes (i (1- conses-per-page))
(setq final (private-list (incf counter))))
(assert (= final (+ base-address sb-vm:gencgc-page-bytes
@ -70,7 +71,7 @@
;; Each of the pages should have zero words used and need-to-zero = 1
(dolist (index pages)
(assert (page-need-to-zero index))
(assert (= (slot (deref sb-vm::page-table index) 'sb-vm::words-used) 0))))))
(assert (= (page-words-used index) 0))))))
#-gencgc
(defun test-private-consing ()