FIXNUM
, the pointer
cell, constructed by newnatptr
, allows a Lisp object to be
registered for protection whenever the pointer cell is accessible. The
first argument to newnatptr
is the pointer value; the second
argument is the protected item.
<declaration of newnatptr
>= (U->)
extern LVAL newnatptr _((ALLOCTYPE *p, LVAL v));
Definesnewnatptr
(links are to index).
The address-of
function has been modified to return native pointer
objects. Other pointer-returning functions will also be modified
accordingly. [I have not modified peek
and poke
---I'm
not sure they are of much use in any case.]
To see why protection is needed, consider the function
(defun f (x) (g (array-data-address x)))In the interpreter, the fact that
x
is on the stack protects it
from garbage collection while g
executes. But the compiler
eliminates the current stack frame at the tail call, so if no more
references to the value of x
exist, it may be collected, making
the address in use by g
invalid. Protecting the value of x
in
the pointer object prevents this.
Two functions are provided for examining pointers. pointer-address
returns the address of a pointer object as an integer (a BIGNUM
if
necessary). The function pointer-protected
returns the item in the
protected field of the pointer object. Both these routines are
primarily useful for debugging. These functions are exported from the
SYSTEM
package (currently just a nickname for the XLISP
package). The type of a pointer object is pointer
.
> (use-package "SYSTEM") > T > (setf a (address-of pi)) #<Pointer: #4001f5f8> > (pointer-address a) 1073870328 > (pointer-protected a) 3.141592653589793 > (type-of a) POINTER > (typep a 'pointer) TThe result of the previous
(address-of x)
definition can be
obtained by
(pointer-address (address-of x))This is almost equivalent---for large poinbters this returns a
BIGNUM
instead of a negative FIXNUM
under two's complement.
In addition, the function pointer-increment
can be used to compute
a new pointer with a specified offset from the old pointer. The
function takes two or three arguments,
(pointer-increment p count) (pointer-increment p count size)The new pointer is offset by
count * size
bytes; if count
is
not supplied it defaults to one. The new pointer protects the same
object as the old pointer. Either count
or size
may be
negative.
When a pointer object is saved in a workspace its address value is ignored; when it is restored, the address is set to zero.
cvs diff -D 1/1/98 -D 1/8/98
CONS
representation. The CAR
cell
holds the pointer, cast to an LVAL
. The CDR
cell holds a
reference that is to be protected when the pointer cell is
accessible. The constructor function is newnatptr
.
<definition of newnatptr
>= (U->)
> }
>
> LVAL newnatptr P2C(ALLOCTYPE *, p, LVAL, v)
> {
> LVAL val;
> xlprot1(v);
> val = newnode(NATPTR);
> car(val) = (LVAL) p;
> cdr(val) = v;
> xlpop();
> return val;
Definesnewnatptr
(links are to index).
For the generational collector, the properties of the new type are registered as
<generational GC properties of NATPTR
type>= (U->)
> type_info[NATPTR].allocated = FALSE;
> type_info[NATPTR].has_children = TRUE;
A new case is added to the forward_children
macro to follow the CDR
cell only.
<case for forward_children
macro>= (U->)
> case NATPTR: \
> forward_node(cdr(temp)); \
> break; \
For the mark and sweep collector, the mark loop needs to have a final
else
clause of the form
<additional else
clause for mark-and-sweep>= (U->)
> else if (type == NATPTR) {
> mark(cdr(this));
This code has not been tested since I don't use this collector.
The xldmem.h
header file contains some accessor macros.
<accessor macros for native pointers>= (U->) > /* native pointers *//* L. Tierney */ > /* Use the CONS representation with pointer in the CAR cell */ > #define getnpaddr(x) ((ALLOCTYPE *) car(x)) > #define setnpaddr(x,v) (car(x) = (LVAL) (v)) > #define getnpprot(x) cdr(x) > #define setnpprot(x,v) rplacd(x,v)
Definesgetnpaddr
,getnpprot
,setnpaddr
,setnpprot
(links are to index).
<tag value for NATPTR
>= (U->)
> #define NATPTR 12 /* native pointer */
DefinesNATPTR
(links are to index).
The CONS
-like type tags are renumbered.
<tag value renumbering>= (U->) < #define CONS 12 < #define COMPLEX 13 --- > #define CONS 13 > #define COMPLEX 14 259c267 < #define RATIO 14 --- > #define RATIO 15 261,263c269,271 < #define USTREAM 15 < #define DARRAY 16 < #define RNDSTATE 17 --- > #define USTREAM 16 > #define DARRAY 17 > #define RNDSTATE 18 265c273 < #define BCCLOSURE 18 --- > #define BCCLOSURE 19
Because of this renumbering, renumbering the version has been incremented to 3.51 to invalidate old workspaces.
<version renumbering>= (U->) < #define XLS_MINOR_RELEASE 50 --- > #define XLS_MINOR_RELEASE 51
The CONS
-handling code for workspace saving is modified to only
follow the CDR
for NATPTR
objects.
<modified CONS
case for saving>= (U->)
< writeptr(cvoptr(car(p)));
---
> if (ntype(p) != NATPTR)
> writeptr(cvoptr(car(p)));
The restoration code places a zero in the CAR
field of native
pointer cells.
<modified CONS
case for restoring>= (U->)
< rplaca(p,cviptr(readptr()));
---
> rplaca(p,type==NATPTR ? NULL : cviptr(readptr()));
address-of
function has been modified to return a native
pointer instead of a FIXNUM
.
<changes to xaddrs
>= (U->)
< /* return the address of the node */
< return (cvfixnum((FIXTYPE)val));
---
> /* changed to use native pointer -- L. Tierney */
> return newnatptr(val, val);
The function pointer-address
retrieves the address cell of a
native pointer as an integer. The value is returned as a BIGNUM
if
necessary.
<definition of xnpaddr
>= (U->)
> /* xnpaddr - get the address of a native pointer */
> LVAL xnpaddr(V)
> {
> LVAL p = xlganatptr();
> xllastarg();
> #ifdef BIGNUMS
> if ((unsigned long) getnpaddr(p) > MAXFIX)
> return cvtulongbignum((unsigned long) getnpaddr(p), 0);
> #endif /* BIGNUMS */
> return cvfixnum((FIXTYPE) getnpaddr(p));
> }
Definesxnpaddr
(links are to index).
<function table entries>= (U->) [D->] > { "SYSTEM:POINTER-ADDRESS", S, xnpaddr },
Defines[[pointer-address]]
(links are to index).
The pointer-protect
function retrieves the protected value of a
native pointer cell.
<definition of xnpprot
>= (U->)
> /* xnpprot - get the protected value of a native pointer */
> LVAL xnpprot(V)
> {
> LVAL p = xlganatptr();
> xllastarg();
> return getnpprot(p);
> }
Definesxnpprot
(links are to index).
<function table entries>+= (U->) [<-D->] > { "SYSTEM:POINTER-PROTECTED", S, xnpprot },
Definespointer-protect
(links are to index).
The function pointer-increment
returns a new pointer cell with its
pointer value incremented by the product of the second and third
arguments. [Should the arguments be allowed to be bignums?]
The third argument is optional and defaults to one. The new pointer
protects the same value as the original pointer. Either of the second
and third arguments may be negative.
<definition of xnpincr
>= (U->)
> /* xnpincr - increment native pointer */
> LVAL xnpincr(V)
> {
> LVAL p = xlganatptr();
> long count = getfixnum(xlgafixnum());
> long size = moreargs() ? getfixnum(xlgafixnum()) : 1;
> xllastarg();
> return newnatptr(((char *) p) + count * size, getnpprot(p));
> }
Definesxnpincr
(links are to index).
<function table entries>+= (U->) [<-D] > { "SYSTEM:POINTER-INCREMENT", S, xnpincr },
Definespointer-increment
(links are to index).
A line has to be added to the extern
declarations in xlftab.h
<new declarations in xlftab.h>= (U->) > xnpaddr(V),xnpprot(V),xnpincr(V),
Definesxnpaddr
,xnpincr
,xnpprot
(links are to index).
<declaration of a_ptr
>= (U->)
> XLGLOBAL LVAL a_ptr;
Definesa_ptr
(links are to index).
<definition of a_ptr
>= (U->)
> LVAL a_ptr=NULL;
Definesa_ptr
(links are to index).
<initialization of a_ptr
>= (U->)
> a_ptr = xlenter("SYSTEM:POINTER");
There are new cases in the internal type-of
and typep
to
handle the new type.
<new case in internal type-of
>= (U->)
> case NATPTR: return (a_ptr);
<new case in internal typep
>= (U->)
> if (arg == a_ptr) return NATPTR;
New predicate and argument reading macros are provided in xlisp.h
.
<predicate macro for native pointers>= (U->) > #define natptrp(x) (ntype(x) == NATPTR) /* L. Tierney */
Definesnatptrp
(links are to index).
<argument reader macro for native pointers>= (U->) > #define xlganatptr() (testarg(typearg(natptrp)))
Definesxlganatptr
(links are to index).
The internal hash function xlhash
is modified with a new ending
clause of
<xlhash
changes, part 1>= (U->)
< default: /* all array types */
< for (i = getsize(obj), tot = 0; i-- > 0;)
---
> default:
> if (ntype(obj) >= ARRAY) { /* all array types */
> for (i = getsize(obj), tot = 0; i-- > 0;)
<xlhash
changes, part 2>= (U->)
< return (int)(tot % len);
---
> return (int)(tot % len);
> }
> else
> return 0; /* nothing we can do on this */
This may not be the best choice, but it fixes a fatal bug that made hashing things like random state objects fail.
*print-escape*
is true and is printed as a hexadecimal number if
*print-escape*
is false.
<printing code for native pointers>= (U->) > case NATPTR: /* L. Tierney */ > #ifdef PRINTCIRCLE > if (checkcircle(fptr, vptr)) break; > #endif /* PRINTCIRCLE */ > checkreadable(vptr); > if (flag) { > sprintf(buf, "#<%s: #", "Pointer"); > xlputstr(fptr, buf); > } > sprintf(buf, AFMT, CVPTR(getnpaddr(vptr))); > xlputstr(fptr, buf); > if (flag) > xlputc(fptr, '>'); > break;
The reading code just adds NATPTR
to the cases that do not require
special handling in a circular read. [I'm not sure if this is
right, given #.
constructs, for any of the things in this list for
that matter.]
<extra case for read code>= (U->) > case NATPTR:
<patch file>= Index: objects.c =================================================================== RCS file: /NOKOMIS/users/luke/SRC/xlispstat/objects.c,v retrieving revision 1.21 retrieving revision 1.22 diff -r1.21 -r1.22 1247c1247 < #define FIRST_METHOD_OFFSET 530 --- > #define FIRST_METHOD_OFFSET 540 Index: version.h =================================================================== RCS file: /NOKOMIS/users/luke/SRC/xlispstat/version.h,v retrieving revision 1.43 retrieving revision 1.44 diff -r1.43 -r1.44 2c2 <version renumbering> Index: xldmem.c =================================================================== RCS file: /NOKOMIS/users/luke/SRC/xlispstat/xldmem.c,v retrieving revision 1.30 retrieving revision 1.31 diff -r1.30 -r1.31 221a222,223 <generational GC properties ofNATPTR
type> 919a922,924 <case forforward_children
macro> 2300,2302c2305,2306 < else { < if (is_array_type(type)) < for (i = 0, n = getsize(this); i < n; i++) --- > else if (is_array_type(type)) { > for (i = 0, n = getsize(this); i < n; i++) 2304a2309,2312 > break; > } <additionalelse
clause for mark-and-sweep> 2306a2315,2316 > else > break; 2936a2947,2957 <definition ofnewnatptr
> Index: xldmem.h =================================================================== RCS file: /NOKOMIS/users/luke/SRC/xlispstat/xldmem.h,v retrieving revision 1.14 retrieving revision 1.15 diff -r1.14 -r1.15 202a203,209 <accessor macros for native pointers> > 253a261 <tag value forNATPTR
> 256,257c264,265 <tag value renumbering> 479a488 > <declaration ofnewnatptr
> Index: xlftab.c =================================================================== RCS file: /NOKOMIS/users/luke/SRC/xlispstat/xlftab.c,v retrieving revision 1.27 retrieving revision 1.30 diff -r1.27 -r1.30 324a325,327 <function table entries> 854a858,864 > { NULL, S, xnotimp }, > { NULL, S, xnotimp }, > { NULL, S, xnotimp }, > { NULL, S, xnotimp }, > { NULL, S, xnotimp }, > { NULL, S, xnotimp }, > { NULL, S, xnotimp }, Index: xlftab.h =================================================================== RCS file: /NOKOMIS/users/luke/SRC/xlispstat/xlftab.h,v retrieving revision 1.26 retrieving revision 1.27 diff -r1.26 -r1.27 59a60 <new declarations in xlftab.h> Index: xlglob.c =================================================================== RCS file: /NOKOMIS/users/luke/SRC/xlispstat/xlglob.c,v retrieving revision 1.17 retrieving revision 1.18 diff -r1.17 -r1.18 140a141 <definition ofa_ptr
> Index: xlglob.h =================================================================== RCS file: /NOKOMIS/users/luke/SRC/xlispstat/xlglob.h,v retrieving revision 1.13 retrieving revision 1.14 diff -r1.13 -r1.14 112a113 <declaration ofa_ptr
> Index: xlimage.c =================================================================== RCS file: /NOKOMIS/users/luke/SRC/xlispstat/xlimage.c,v retrieving revision 1.20 retrieving revision 1.21 diff -r1.20 -r1.21 130a131 > case NATPTR: 133c134,135 <modifiedCONS
case for saving> 335a338 > case NATPTR: 338c341 <modifiedCONS
case for restoring> Index: xlinit.c =================================================================== RCS file: /NOKOMIS/users/luke/SRC/xlispstat/xlinit.c,v retrieving revision 1.26 retrieving revision 1.29 diff -r1.26 -r1.29 551a552 <initialization ofa_ptr
> Index: xlisp.h =================================================================== RCS file: /NOKOMIS/users/luke/SRC/xlispstat/xlisp.h,v retrieving revision 1.63 retrieving revision 1.65 diff -r1.63 -r1.65 1377a1378 <predicate macro for native pointers> 1420a1422 <argument reader macro for native pointers> Index: xlprin.c =================================================================== RCS file: /NOKOMIS/users/luke/SRC/xlispstat/xlprin.c,v retrieving revision 1.29 retrieving revision 1.32 diff -r1.29 -r1.32 548a549,562 <printing code for native pointers> Index: xlread.c =================================================================== RCS file: /NOKOMIS/users/luke/SRC/xlispstat/xlread.c,v retrieving revision 1.20 retrieving revision 1.21 diff -r1.20 -r1.21 301a302 <extra case for read code> Index: xlsym.c =================================================================== RCS file: /NOKOMIS/users/luke/SRC/xlispstat/xlsym.c,v retrieving revision 1.20 retrieving revision 1.21 diff -r1.20 -r1.21 322,323c322,324 <xlhash
changes, part 1> 325c326,329 <xlhash
changes, part 2> Index: xlsys.c =================================================================== RCS file: /NOKOMIS/users/luke/SRC/xlispstat/xlsys.c,v retrieving revision 1.21 retrieving revision 1.23 diff -r1.21 -r1.23 117a118 <new case in internaltype-of
> 160a162 <new case in internaltypep
> 635,636c637,638 <changes toxaddrs
> 637a640,670 > <definition ofxnpaddr
> > <definition ofxnpprot
> > <definition ofxnpincr
> >
else
clause for mark-and-sweep>: D1, U2
forward_children
macro>: D1, U2
xaddrs
>: D1, U2
a_ptr
>: D1, U2
newnatptr
>: D1, U2
a_ptr
>: D1, U2
newnatptr
>: D1, U2
xnpaddr
>: D1, U2
xnpincr
>: D1, U2
xnpprot
>: D1, U2
NATPTR
type>: D1, U2
a_ptr
>: D1, U2
CONS
case for restoring>: D1, U2
CONS
case for saving>: D1, U2
type-of
>: D1, U2
typep
>: D1, U2
NATPTR
>: D1, U2
xlhash
changes, part 1>: D1, U2
xlhash
changes, part 2>: D1, U2