[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

I think there is a bug in the reader decoder



I am getting some very strange behavior when using a standard accessor
generic function because it sometimes never returns from the access.  After
a lot of debugging I was able to figure out why, sort of...
When tracing DCODE-CACHE-MISS I noticed that is was being called
again and again, always returning the same value (a number).  I think that
I may have figured out why the generic function is in the infinite loop.  Below
is the code that is used to build the generic function...
(the standard reader decoder -- from file dcode.lisp):

(define-function-template all-std-class-readers-dcode
			  (cache-size cache-mask)
			  '(.GENERIC-FUNCTION. .CACHE. .NEXT-SCAN-LIMIT.)
  (let ()
    `(function
       (lambda (arg)
	 (declare (optimize (speed 3) (safety 0)))
	 (let ((value nil))
	   (all-std-class-accessors-dcode-internal
	     nil
	     index
	     ,cache-size
	     ,cache-mask
	     #'all-std-class-readers-tertiary-miss
	     #'make-all-std-class-readers-dcode
X	     (progn
X	       (setq value (%svref (iwmc-class-static-slots arg) index))
X	       (if (eq value ',*slot-unbound*)
X		   (go miss)
X		   (return-from accessor-dcode value)))
	     (return-from accessor-dcode (slot-value arg index))))))))

If you expand this, the argument labeled with the X's is the "fast-form"
argument to the macro ALL-STD-CLASS-ACCESSORS-DCODE-INTERNAL.  This is
the form that you call when you have a "hit" in the cache.  

Looking at this code, it seems strange that the slot being unbound
is treated like a "miss".  After all the slot could actually
be unbound.  Therefore the contents of the slot would be equal to whatever
*slot-unbound* is set to.  But not knowing all of the details of caching 
in PCL this might be the correct course of events.  

However, if we DO go to the MISS tag (see code below), we call
DCODE-CACHE-MISS, which in this case returns the number of the slot.
(It seems as if DCODE-CACHE-MISS returns either the slot-name or the
slot-position).

      miss
	 (progn
	   (unlock-cache)
	   (setq ,index
		 (dcode-cache-miss
		   .GENERIC-FUNCTION.
		   ,tertiary-miss
		   .CACHE.
		   ,cache-size
		   ,cache-mask
		   2		;line size
		   1		;nkeys
		   .NEXT-SCAN-LIMIT.
		   (< ,cache-size
		      *all-std-class-accessors-max-cache-size*)
		   ,dcode-constructor
		   wrapper
		   ,@(and writerp '(new-value))
		   arg))
	   (cond ((eq ,index '..no-applicable-method..)
		  (return-from accessor-dcode
		    (no-applicable-method .GENERIC-FUNCTION. arg)))
		 ((not (symbolp ,index))
		  (go hit))
		 (t
		  (return-from accessor-dcode ,slow-form)))))))))))

Finally, this COND is executed.  Since index is not ..no-applicable-method..
and it IS a number, we go to HIT.  The slot is again accessed, it
is still equal to whatever *slot-unbound* is equal to, so we jump
to MISS, and this continues forever.....

Unfortunately, this doesn't seem to happen if I just create a class
on the fly, and then execute the accessor function.  

Additional information:,
	1. A method for SLOT-UNBOUND is defined for the root object
	type in our hierarchy.  It sets the slot to nil.

	2. We are using defconstructors.

I don't know if these facts will be useful.....

I finally gave up because I couldn't understand why slot-unbound
isn't called from the "fast-form" but instead the slot being unbound
is treated like a miss in the cache.  Does this make sense to anyone
out there?

On a lighter note, I'm surprised that nobody notice that Dec. 7
PCL should be called "Pearl Harbor Day PCL".  I guess everybody
has become George Bush......