From: Stanley Etra
Subject: writing self modifying coode
Date: 
Message-ID: <1991Sep20.211820.3784@ait.com>
I am try to determine how to write self-modifying code without
violating CltL2.  The basic scenario is as follows (it is a bit
complicated).

A C function exists that uses an argument vector instead of a variable
length argument list.  

It has the following header information.

  typedef *short ArgVector;

  extern void DigestValues ( ArgVector args, unsigned int nargs);

This is turned into Lucid's Foreign Function Interface as:

  (def-foreign-synonym-type ArgVector (:pointer :signed-16bit))

  (def-foreign-function (digest-values-internal
                          (:name "_DigestValues")
                          (:return-type :null))
    (args ArgVector)
    (nargs :unsigned-32bit))

The user visible construct, DIGEST-VALUES, has a variable length
argument list.  The goal is to write a macro version of DIGEST-VALUES
that allocates the argument vector at read time, and propogates as
many elements of the argument vector that are known at read time.  We
are being anal about effeciency because this function is very time
criticial.  This should be done in a Common Lisp compliant way so it
can be run on any Lisp implementation (we will worry about porting
Lucid's FFI).

Ideally,

  (DIGEST-VALUES 10 20)

should expand into

  (DIGEST-VALUES-INTERNAL '#<FOREIGN-POINTER> 2)

where the contents of the foreign pointer were filled in at expansion
time (and the foreign pointer was allocated in static space).

Similarly,

  (DIGEST-VALUES 10 (FOO))

should exapnd into:

  (PROGN
    (SETF (FOREIGN-AREF '#1=#<FOREIGN-POINTER> 1) (FOO))
    (DIGEST-VALUES-INTERNAL '#1# 2))

were the zeroth value of the vector was set to 10 at macroexpansion
time. 

The second expansion seems to be explicitly outlawed in CltL2 page 115
which states

  ...it is an error to destructively modify any object that appears as
  a constant in executable code...

I find it disappointing that this code can easily be written in C,
with a STATIC declaration, but not in Lisp.  Furthermore, a global
variable cannot be used, because the macro appears in some lexical
environment and there is no way to declare a global variable outside
of that environment.

My only solution so far is to use one level of indirection
through an uninterned symbol and allocate the vector during the first
invocation of the code.  Something like:

  (progn
    (let ((fp (symbol-value '#1=#:G10)))
      (when (null fp)
	(setf fp
	      (setf (symbol-value '#1=#:G10)
		    (let ((fp (malloc-arg-vector 2)))	
		      (setf (foreign-aref fp 0) 10)
		      fp))))
      (setf (foreign-aref fp 1) (foo))
      (digest-values-internal fp 2)))

I am trying to rationalize the fact that modifying the SYMBOL-VALUE of
an uninterned symbol is not considered a destructive modification.  In
other words, a symbol is like a variable not like a structure.  Of
course, this code is treating a symbol like any other structure and
its value as any valid place.  The symbol can be replaced by a cons
cell and SYMBOL-VALUE by CAR.

This rationalization is based on second guessing Cltl2.  My
understanding of the basis for the constant restriction is to allow
Lisp implementors to

1. Put function definitions in read-only space.
2. Perform better constant folding.

I do not believe uninterned symbols are placed in read-only space on
most Lisp implementations, but I do not know if that is a reliable
gaurentee.  Constant folding does not occur with uninterned symbols.

The final, and dissapointing, last choice would be to tag every
expansion with an uninterned symbol, and use EQ hashing to lookup the
foreign pointer based on the tag.

Is this stuff allowed, and if not, how could the desired functionality
be implemented in Common Lisp?

Any feedback would be greatly appreciated.
-- 
--
Stan Etra			AIT, Inc.
914/347-6860			40 Saw Mill River Road
····@ait.com			Hawthorne, New York 10532
From: Barry Margolin
Subject: Re: writing self modifying coode
Date: 
Message-ID: <1991Sep23.010850.17813@Think.COM>
In article <·····················@ait.com> ····@ait.com (Stanley Etra) writes:
>The user visible construct, DIGEST-VALUES, has a variable length
>argument list.  The goal is to write a macro version of DIGEST-VALUES
>that allocates the argument vector at read time

I believe you mean "macroexpansion time", not "read time".  The only user
code that executes at read time is read-macro definitions.

>						, and propogates as
>many elements of the argument vector that are known at read time.  We
>are being anal about effeciency because this function is very time
>criticial.  This should be done in a Common Lisp compliant way so it
>can be run on any Lisp implementation (we will worry about porting
>Lucid's FFI).

...

>  (DIGEST-VALUES 10 (FOO))
>
>should exapnd into:
>
>  (PROGN
>    (SETF (FOREIGN-AREF '#1=#<FOREIGN-POINTER> 1) (FOO))
>    (DIGEST-VALUES-INTERNAL '#1# 2))
>
>were the zeroth value of the vector was set to 10 at macroexpansion
>time. 
>
>The second expansion seems to be explicitly outlawed in CltL2 page 115
>which states
>
>  ...it is an error to destructively modify any object that appears as
>  a constant in executable code...

Of course, since the object you're modifying is of a type not defined by
CLtL, it isn't really subject to CLtL's rules, it's subject only to the
rules of the language implementor.  If Lucid permits you to use SETF of
FOREIGN-AREF on a constant foreign vector, that's all that matters.

>I find it disappointing that this code can easily be written in C,
>with a STATIC declaration, but not in Lisp.  Furthermore, a global
>variable cannot be used, because the macro appears in some lexical
>environment and there is no way to declare a global variable outside
>of that environment.

What makes you say that?  What's wrong with expanding into:

	(progn
	  (defvar #:G10 (malloc-arg-vector 2))
	  (setf (foreign-aref #:g10 1) (foo))
	  (digest-values-internal #:g10 2))

This is essentially equivalent to your version that uses SYMBOL-VALUE; all
the checking is hidden in the expansion of DEFVAR.

On to your secondary question....

>I am trying to rationalize the fact that modifying the SYMBOL-VALUE of
>an uninterned symbol is not considered a destructive modification.  In
>other words, a symbol is like a variable not like a structure.  Of
>course, this code is treating a symbol like any other structure and
>its value as any valid place.  The symbol can be replaced by a cons
>cell and SYMBOL-VALUE by CAR.

It's OK to modify symbols that appear as constants in code.  CLtL probably
has several examples of the form (setf (symbol-value 'foo) 3).  The only
symbols you can't modify the SYMBOL-VALUE of are those described as
"Constant" in CLtL or those defined using DEFCONSTANT.  I think the CL
standard will say this explicitly; it's a known omission in CLtL.
-- 
Barry Margolin, Thinking Machines Corp.

······@think.com
{uunet,harvard}!think!barmar