1
0
mirror of https://github.com/Interlisp/maiko.git synced 2026-01-18 17:07:24 +00:00
Interlisp.maiko/src/gchtfind.c
Nick Briggs cdffa541ef
Remove extra semicolons, convert #define x() {...} to do {...} while (0) style (#444)
* Remove extra semicolons, convert #define x() {...} to do {...} while (0) style

* Fix missing brace in INIT-specific definition of init_kbd_startup
2022-10-05 09:07:17 -07:00

538 lines
22 KiB
C

/* $Id: gchtfind.c,v 1.3 1999/05/31 23:35:31 sybalsky Exp $ (C) Copyright Venue, All Rights Reserved
*/
/************************************************************************/
/* */
/* (C) Copyright 1989-95 Venue. All Rights Reserved. */
/* Manufactured in the United States of America. */
/* */
/************************************************************************/
#include "version.h"
#include "address.h" // for LOLOC
#include "adr68k.h" // for LAddrFromNative
#include "commondefs.h" // for error
#include "gcdata.h" // for GETGC, GCENTRY, ADDREF, DELREF, gc_ovfl
#include "gchtfinddefs.h" // for enter_big_reference_count, htfind, modify_...
#include "gcrdefs.h" // for disablegc1
#include "lispemul.h" // for LispPTR, NIL, state, DLWORDSPER_CELL, ATOM_T
#include "lispmap.h" // for HTCOLL_SIZE
#include "lspglob.h" // for HTcoll, HTbigcount, HTmain
#include "lsptypes.h" // for WORDPTR
#include "storagedefs.h" // for newpage
#define Evenp(num, prim) (((num) % (prim)) == 0)
#ifdef BIGVM
/* HTCOLLMAX should be in half-entries, not in words */
#define HTCOLLMAX ((HTCOLL_SIZE / DLWORDSPER_CELL) - 16)
#else
#define HTCOLLMAX (HTCOLL_SIZE - 16)
#endif /* BIGVM */
/* GetLink gets a new entry from the GC collision table */
#define GetLink(var) \
do { \
GCENTRY linkoff; \
linkoff = GETGC(HTcoll); \
if (linkoff == 0) { \
if ((linkoff = GETGC((GCENTRY *)HTcoll + 1)) >= HTCOLLMAX) { \
disablegc1(NIL); \
return (NIL); \
} \
GETGC((GCENTRY *)HTcoll + 1) = linkoff + 2; \
(var) = (GCENTRY *)(HTcoll + linkoff); \
} else { \
GETGC(HTcoll) = GETGC((GCENTRY *)(HTcoll + linkoff + 1)); \
(var) = (GCENTRY *)(HTcoll + linkoff); \
} \
} while (0)
#ifdef BIGVM
#define HTCNTSHIFT 17 /* amount to shift to get hash table count */
#define HTCNTMASK 0xFFFE0000 /* mask which masks off hash table count */
#define HTCNTSTKMASK 0XFFFF0000 /* mask for hash table count + stack bit */
#define HTSTKMASK 0x10000 /* mask for stack bit only */
#define HTHIMASK \
0x1FFE /* mask of bits which contain high part of \
pointer in hash table FIXME change this \
to 1FFE when pointers really go to \
28 bits. JDS */
#define HTHISHIFT 1 /* high bits in hash table are shifted left 1 */
#else
#define HTCNTSHIFT 10 /* amount to shift to get hash table count */
#define HTCNTMASK 0xFC00 /* mask which masks off hash table count */
#define HTCNTSTKMASK 0XFE00 /* mask for hash table count + stack bit */
#define HTSTKMASK 0x0200 /* mask for stack bit only */
#define HTHIMASK \
0x1FE /* mask of bits which contain high part of pointer \
in hash table */
#define HTHISHIFT 1 /* high bits in hash table are shifted left 1 */
#endif /* BIGVM */
/* NewEntry is a macro for adding a new gc hash table entry;
entry is pointer to hash table entry
hiptr is the high point of the ref-cnted entry, shifted
casep is one of ADDREF, DELREF, etc.
*/
/*
* NewEntry is never called in the course of the reclamation.
* Thus STKREF case is not needed.
*/
#define NewEntry(entry, hiptr, casep, ptr) \
do { \
switch (casep) { \
case ADDREF: \
GETGC(entry) = (hiptr) | (2 << HTCNTSHIFT); /* set count = 2 */ \
IncAllocCnt(1); \
return NIL; /* not new 0 entry */ \
case DELREF: \
GETGC(entry) = hiptr; /* set count = 0 */ \
IncAllocCnt(1); \
return ptr; /* new 0 entry */ \
default: error("GC error: new entry touches stack bit"); \
return NIL; /* NOT REACHED */ \
} \
} while (0)
/*
* RecNewEntry is called in the course of the reclamation.
* Does not maintain the allocation count.
*/
#define RecNewEntry(entry, hiptr, casep, ptr) \
do { \
switch (casep) { \
case ADDREF: \
GETGC(entry) = (hiptr) | (2 << HTCNTSHIFT); /* set count = 2 */ \
return NIL; /* not new 0 entry */ \
case DELREF: \
GETGC(entry) = hiptr; /* set count = 0 */ \
return ptr; /* new 0 entry */ \
case STKREF: /* set refcnt to 1, stack bit to 1 */ \
GETGC(entry) = (hiptr) | (1 << HTCNTSHIFT) | HTSTKMASK; \
return NIL; \
default: error("GC error: new entry when turning off stack bit"); \
return NIL; /* NOT REACHED */ \
} \
} while (0)
/* ModEntry is a macro to modify an old gc hash table entry.
entry is a pointer to the entry
contents holds the old contents
ptr is the pointer being counted
casep is one of ADDREF, DELREF, etc.
remove is a label to go to if the entry will go away
It always return NIL, since cannot be creating a zero-count,
no-stack-bit entry */
/*
* ModEntry is never called in the course of the reclamation.
* Thus STKREF and UNSTKREF cases are not needed.
*/
#define ModEntry(entry, contents, ptr, casep, remove) \
do { \
if (((contents) & HTCNTMASK) == HTCNTMASK) { /* overflow; return non-zero */ \
modify_big_reference_count(entry, casep, ptr); \
return NIL; \
} \
switch (casep) { \
case ADDREF: \
(contents) += (1 << HTCNTSHIFT); \
if (((contents) & HTCNTMASK) == HTCNTMASK) { /* overflow */ \
GETGC(entry) = contents; \
enter_big_reference_count(ptr); \
return NIL; \
} \
if (((contents) & HTCNTSTKMASK) == (1 << HTCNTSHIFT)) { \
DecAllocCnt(1); \
goto remove; /* NOLINT(bugprone-macro-parentheses) */ \
} \
break; \
case DELREF: \
if (((contents) >> HTCNTSHIFT) == 0) error("attempt to decrement 0 reference count"); \
(contents) -= (1 << HTCNTSHIFT); \
if (((contents) & HTCNTSTKMASK) == (1 << HTCNTSHIFT)) { \
DecAllocCnt(1); \
goto remove; /* NOLINT(bugprone-macro-parentheses) */ \
} \
break; \
default: error("GC error: mod entry touches stack bit"); \
} \
GETGC(entry) = contents; \
return NIL; \
} while (0)
/*
* RecModEntry is called in the course of the reclamation.
* Does not maintain the allocation count.
*/
#define RecModEntry(entry, contents, ptr, casep, remove) \
do { \
if (((contents) & HTCNTMASK) == HTCNTMASK) { /* overflow; return non-zero */ \
modify_big_reference_count(entry, casep, ptr); \
return NIL; \
} \
switch (casep) { \
case ADDREF: \
(contents) += (1 << HTCNTSHIFT); \
if (((contents) & HTCNTMASK) == HTCNTMASK) { \
/* overflow */ \
GETGC(entry) = contents; \
enter_big_reference_count(ptr); \
return NIL; \
} \
break; /* check for possibly deleting entry */ \
case DELREF: \
if (((contents) >> HTCNTSHIFT) == 0) error("attempt to decrement 0 reference count"); \
(contents) -= (1 << HTCNTSHIFT); \
break; \
case STKREF: \
GETGC(entry) = (contents) | HTSTKMASK; \
return NIL; \
/* \
case UNSTKREF: \
contents = contents & ~ HTSTKMASK; \
break; \
*/ \
} \
/* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \
if (((contents) & HTCNTSTKMASK) == (1 << HTCNTSHIFT)) goto remove; \
GETGC(entry) = contents; \
return NIL; \
} while (0)
/************************************************************************/
/* */
/* e n t e r _ b i g _ r e f e r e n c e _ c o u n t */
/* */
/* Add a new overflow entry, for a count that won't fit into */
/* the field of a main GC table entry. */
/* */
/************************************************************************/
void enter_big_reference_count(LispPTR ptr) {
struct gc_ovfl *oventry;
LispPTR tmp;
/* this kludge is apparently necessary. Odd pointers are
illegal, but apparently some are reference counted. If you
get an odd pointer, just ignore the low bit */
ptr &= 0xfffffffe;
oventry = (struct gc_ovfl *)HTbigcount;
while (((tmp = oventry->ovfl_ptr) != ATOM_T) && (tmp != NIL))
/* free area ? */
{
if (tmp == ptr) {
error("ERROR : PTR already in overflow table.\n");
oventry->ovfl_cnt += 0x10000; /* "Assure it lives forever" */
return;
} else
++oventry;
}
if (tmp == NIL) {
if (Evenp(LAddrFromNative(oventry + 1), DLWORDSPER_PAGE)) {
if ((UNSIGNED)oventry + 1 >= (UNSIGNED)HTcoll) error("GC big reference count table overflow");
newpage(LAddrFromNative(oventry + 1));
}
}
oventry->ovfl_cnt = MAX_GCCOUNT;
oventry->ovfl_ptr = ptr;
return;
}
/************************************************************************/
/* */
/* m o d i f y _ b i g _ r e f e r e n c e _ c o u n t */
/* */
/* Modify an existing overflow entry. */
/* */
/************************************************************************/
void modify_big_reference_count(LispPTR *entry, DLword casep, LispPTR ptr) {
struct gc_ovfl *oventry;
LispPTR tmp;
/* ditto comment in entry_big_reference_count */
if (ptr & 1) ptr &= 0xfffffffe;
oventry = (struct gc_ovfl *)HTbigcount;
while ((tmp = oventry->ovfl_ptr) != ptr)
if (tmp == NIL) {
error("refcnt previously overflowed, but not found in table.\n");
return;
} else
++oventry; /* increment by size of oventry structure */
switch (casep) {
case ADDREF: ++(oventry->ovfl_cnt); return;
case DELREF:
if (--(oventry->ovfl_cnt) < MAX_GCCOUNT) {
/* fallen below threshold */
((struct hashentry *)GCPTR(entry))->count = MAX_GCCOUNT - 1;
oventry->ovfl_ptr = ATOM_T; /* mark entry unused */
}
return;
case STKREF:
((struct hashentry *)WORDPTR(entry))->stackref = 1;
return;
/*
case UNSTKREF:
((struct hashentry *) WORDPTR(entry))->stackref = 0;
return;
*/
}
}
/************************************************************************/
/* */
/* h t f i n d */
/* */
/* Main entry for Ref-count manipulation: Modify the reference */
/* count for a lisp pointer. */
/* */
/* casep is one of ADDREF, DELREF, STKREF */
/* */
/* ADDREF = add 1 */
/* DELREF = subtract 1 */
/* STKREF = turn on stack bit */
/* UNSTKREF = turn off stack bit */
/* */
/* returns NIL if DELREF and the entry became */
/* refcount = 0, stk bit off (only can happen on a *new* DELREF) */
/* in which case it returns PTR */
/* */
/************************************************************************/
LispPTR htfind(LispPTR ptr, int casep) {
GCENTRY *entry, *link, *prev;
GCENTRY entry_contents, hiptr;
/* if the NOREF bit is on in the type table entry, do
not reference count this pointer. Used for non-reference
counted types like symbols, and also when the GC is
disabled. */
/*
* Following two tests were moved into GCLOOKUP macro
* for efficiency.
*/
/*
if (GetTypeEntry(ptr) & TT_NOREF) return NIL;
*/
/* if *GcDisabled_word is T then do nothing */
/* FS: this test should not be needed (because type table should
be cleared). Also, this test seems to cause an infinite
ucode loop in remimplicitkeyhash on the 386i */
/* if(*GcDisabled_word == ATOM_T) return(NIL); */
/* GC hash table entries have the high 8 bits of the
pointer stored in the middle. Set up hiptr to have
the high bits of the pointer ready to store or test
against */
hiptr = (((UNSIGNED)ptr) >> (16 - HTHISHIFT)) & HTHIMASK;
/* entry points at the place in the main hash table
where this pointer is stored. The 'hash' isn't one really;
it just uses the low bits of the pointer. */
entry = HTmain + (LOLOC(ptr) >> 1);
entry_contents = GETGC(entry);
if (entry_contents == 0) NewEntry(entry, hiptr, casep, ptr);
/* NewEntry returns */
if (entry_contents & 1) { /* low bit means a collision entry */
/* entry_contents-1 removes low bit */
link = HTcoll + (entry_contents - 1);
prev = 0;
goto newlink;
}
if (hiptr == (entry_contents & HTHIMASK)) {
ModEntry(entry, entry_contents, ptr, casep, delentry);
/* ModEntry returns or will go to delentry */
}
/* new collision */
GetLink(link);
GetLink(prev);
GETGC((GCENTRY *)prev + 1) = 0;
GETGC((GCENTRY *)prev) = entry_contents;
GETGC((GCENTRY *)link + 1) = prev - HTcoll;
GETGC((GCENTRY *)entry) = (link - HTcoll) + 1;
NewEntry(link, hiptr, casep, ptr);
/* NewEntry returns */
delentry:
GETGC(entry) = 0;
return NIL;
/* start here when a collision is detected. link is a pointer to
the entry in the collision table, prev is the previous collision
entry or 0 if this is the first one. */
newlink:
entry_contents = GETGC(link);
if (hiptr == (entry_contents & HTHIMASK)) {
ModEntry(link, entry_contents, ptr, casep, dellink);
/* ModEntry returns or goes to dellink */
}
/* collision didn't match */
entry_contents = GETGC((GCENTRY *)link + 1);
if (entry_contents == 0) goto nolink;
/* try the next link in the collision table */
prev = link;
link = HTcoll + entry_contents;
goto newlink;
dellink:
if (prev)
GETGC((GCENTRY *)prev + 1) = GETGC((GCENTRY *)link + 1);
else
GETGC((GCENTRY *)entry) = (GETGC((GCENTRY *)link + 1)) | 1;
FreeLink(link);
link = HTcoll + (GETGC((GCENTRY *)entry)) - 1;
if (GETGC(link + 1) == 0) {
GETGC((GCENTRY *)entry) = GETGC((GCENTRY *)link);
FreeLink(link);
}
return NIL;
nolink: /* no match */
GetLink(link);
GETGC((GCENTRY *)link + 1) = GETGC((GCENTRY *)entry) - 1;
GETGC((GCENTRY *)entry) = (link - HTcoll) + 1;
NewEntry(link, hiptr, casep, ptr);
/* NewEntry will return */
}
/************************************************************************/
/* */
/* r e c _ h t f i n d */
/* */
/* Version of HTFIND used during reclaims (part of GC process) */
/* Same purpose, but doesn't increment the GC count-down, and */
/* DELREF can add 0-refcount entries to the table. */
/* */
/************************************************************************/
LispPTR rec_htfind(LispPTR ptr, int casep) {
GCENTRY *entry, *link, *prev;
GCENTRY entry_contents, hiptr;
/* if the NOREF bit is on in the type table entry, do
not reference count this pointer. Used for non-reference
counted types like symbols, and also when the GC is
disabled. */
/*
* Following two tests were moved into GCLOOKUP macro
* for efficiency.
*/
/*
if (GetTypeEntry(ptr) & TT_NOREF)
return NIL;
*/
/* if *GcDisabled_word is T then do nothing */
/* FS: this test should not be needed (because type table should
be cleared). Also, this test seems to cause an infinite
ucode loop in remimplicitkeyhash on the 386i */
/* if(*GcDisabled_word == ATOM_T) return(NIL); */
/* GC hash table entries have the high 8 bits of the
pointer stored in the middle. Set up hiptr to have
the high bits of the pointer ready to store or test
against */
hiptr = (((unsigned int)ptr) >> (16 - HTHISHIFT)) & HTHIMASK;
/* entry points at the place in the main hash table
where this pointer is stored. The 'hash' isn't one really;
it just uses the low bits of the pointer. */
entry = HTmain + (LOLOC(ptr) >> 1);
entry_contents = GETGC(entry);
if (entry_contents == 0) RecNewEntry(entry, hiptr, casep, ptr);
/* NewEntry returns */
if (entry_contents & 1) { /* low bit means a collision entry */
/* entry_contents-1 removes low bit */
link = HTcoll + (entry_contents - 1);
prev = 0;
goto newlink;
}
if (hiptr == (entry_contents & HTHIMASK)) {
RecModEntry(entry, entry_contents, ptr, casep, delentry);
/* ModEntry returns or will go to delentry */
}
/* new collision */
GetLink(link);
GetLink(prev);
GETGC((GCENTRY *)prev + 1) = 0;
GETGC((GCENTRY *)prev) = entry_contents;
GETGC((GCENTRY *)link + 1) = prev - HTcoll;
GETGC((GCENTRY *)entry) = (link - HTcoll) + 1;
RecNewEntry(link, hiptr, casep, ptr);
delentry:
GETGC(entry) = 0;
return NIL;
/* start here when a collision is detected. link is a pointer to
the entry in the collision table, prev is the previous collision
entry or 0 if this is the first one. */
newlink:
entry_contents = GETGC(link);
if (hiptr == (entry_contents & HTHIMASK)) {
RecModEntry(link, entry_contents, ptr, casep, dellink);
/* ModEntry returns or goes to dellink */
}
/* collision didn't match */
entry_contents = GETGC(link + 1);
if (entry_contents == 0) { goto nolink; }
/* try the next link in the collision table */
prev = link;
link = HTcoll + entry_contents;
goto newlink;
dellink:
if (prev)
GETGC((GCENTRY *)prev + 1) = GETGC((GCENTRY *)link + 1);
else
GETGC((GCENTRY *)entry) = (GETGC((GCENTRY *)link + 1)) | 1;
FreeLink(link);
link = HTcoll + ((GETGC((GCENTRY *)entry)) - 1);
if (GETGC((GCENTRY *)link + 1) == 0) {
GETGC((GCENTRY *)entry) = GETGC((GCENTRY *)link);
FreeLink(link);
}
return NIL;
nolink: /* no match */
GetLink(link);
GETGC((GCENTRY *)link + 1) = GETGC((GCENTRY *)entry) - 1;
GETGC((GCENTRY *)entry) = (link - HTcoll) + 1;
RecNewEntry(link, hiptr, casep, ptr);
}