Changes between Version 4 and Version 5 of WatchedObjects


Ignore:
Timestamp:
Oct 13, 2009, 11:43:44 PM (10 years ago)
Author:
rme
Comment:

DWIM-y watch; update example accordingly

Legend:

Unmodified
Added
Removed
Modified
  • WatchedObjects

    v4 v5  
    2525the objects currently being watched.
    2626
     27=== DWIM ===
     28
     29WATCH operates at a fairly low level; it is not possible to avoid
     30the details of the internal representation of objects.
     31
     32Nevertheless, as a convenience, WATCHing a standard-instance, a
     33hash-table, or a multi-dimensional or non-simple CL array will watch
     34the underlying slot-vector, hash-table-vector, or data-vector,
     35respectively.
     36
    2737=== Discussion ===
    2838
    2939WATCH can monitor any memory-allocated lisp object.
    3040
    31 In Clozure CL a memory-allocated object is either a cons cell or
     41In Clozure CL, a memory-allocated object is either a cons cell or
    3242a uvector.
    3343
     
    3848
    3949If a memory-allocated object isn't a cons cell, then it is a
    40 vector-like object called a uvector.
    41 
    42 A uvector is a memory-allocated lisp object whose first word is a
    43 header that describes the object's type and the number of elements
    44 that it contains.
     50vector-like object called a uvector. A uvector is a memory-allocated
     51lisp object whose first word is a header that describes the object's
     52type and the number of elements that it contains.
    4553
    4654So, a hash table is a uvector, as is a string, a standard instance,
     
    4856
    4957Some CL objects, like strings and other simple vectors, map in a
    50 straightforward way onto the uvector representation.  Simply watching
    51 the object directly is sufficient in these simple cases.
     58straightforward way onto the uvector representation.  It is easy
     59to understand what happens in such cases.  The uvector
     60index corresponds directly to the vector index:
    5261
    5362{{{
     
    7079written to.
    7180
    72 An example might make this clearer.  Suppose we have a
    73 standard-instance.  It turns out that it is represented by uvector of
    74 three elements.  One of those
    75 elements is an object called a slot-vector.  To monitor writes to the
    76 slots of a standard-instance, it is necessary to watch the
    77 slot-vector, not the standard-instance itself.
     81As mentioned above, watch knows about arrays, hash-tables,
     82and standard-instances, and will automatically watch the
     83appropriate data-containing element.
     84
     85An example might make this clearer.
    7886
    7987{{{
     
    8492*A-FOO*
    8593? (watch *a-foo*)
    86 NIL
    87 ;;; Note that this doesn't catch the write..
     94#<SLOT-VECTOR #xDB00D>
     95;;; Note that WATCH has watched the internal slot-vector object
    8896? (setf (slot-value *a-foo* 'slot-a) 'foo)
    89 FOO
    90 ;;; note use of internal accessor to get at the slot-vector
    91 ? (watch (ccl::instance-slots *a-foo*))
    92 NIL
    93 ? (setf (slot-value *a-foo* 'slot-a) 'foo)
    94 > Error: Write to watched uvector #<SLOT-VECTOR #xD600D> at index 1
     97> Error: Write to watched uvector #<SLOT-VECTOR #xDB00D> at index 1
    9598>        Faulting instruction: (movq (% rsi) (@ -5 (% r8) (% rdi)))
    9699> While executing: %MAYBE-STD-SETF-SLOT-VALUE-USING-CLASS, in process listener(1).
     
    99102}}}
    100103
     104Looking at a backtrace would presumably show what object and slot name
     105were written.
     106
    101107Note that even though the write was to slot-a, the uvector index was 1
    102108(not 0).  This is because the first element of a slot-vector is a
    103 pointer to the instance that owns the slots.
    104 
    105 {{{
    106 #!comment
    107 === DWIM ===
    108 
    109 WATCH operates at a fairly low level; it is not possible to avoid
    110 the details of the internal representation of objects.
    111 
    112 Nevertheless, as a convenience, WATCHing a standard-instance, a
    113 hash-table, or a multi-dimensional or non-simple CL array will watch
    114 the underlying slot-vector, hash-table-vector, and data-vector,
    115 respectively.
     109pointer to the instance that owns the slots.  We can retrieve that
     110to look at the object that was modified:
     111
     112{{{
     1131 > (uvref (write-to-watched-object-object *break-condition*) 0)
     114#<FOO #x30004113502D>
     1151 > (describe *)
     116#<FOO #x30004113502D>
     117Class: #<STANDARD-CLASS FOO>
     118Wrapper: #<CLASS-WRAPPER FOO #x300041135EBD>
     119Instance slots
     120SLOT-A: #<Unbound>
     121SLOT-B: #<Unbound>
     122SLOT-C: #<Unbound>
     1231 >
    116124}}}
    117125
     
    146154
    147155=== Restarts ===
    148 Two restarts are provided: one will skip over the faulting write instruction,
     156Two restarts are provided: one will skip over the faulting write instruction
    149157and proceed;  the other offers to unwatch the object and continue.
    150158
     
    178186
    179187{{{
    180 ? (defvar *f* (make-array '(2 3) :element-type 'double-float))
     188?  (defvar *f* (make-array '(2 3) :element-type 'double-float))
    181189*F*
    182 ;;; Find the underlying data vector
    183 ? (ccl::array-data-and-offset *f*)
     190? (watch *f*)
    184191#(0.0D0 0.0D0 0.0D0 0.0D0 0.0D0 0.0D0)
    185 0
    186 ? (watch *)
    187 #(0.0D0 0.0D0 0.0D0 0.0D0 0.0D0 0.0D0)
     192;;; Note that the above vector is the underlying data-vector for the array
    188193? (setf (aref *f* 1 2) pi)
    189194> Error: Write to watched uvector #<VECTOR 6 type DOUBLE-FLOAT, simple> at index 5
     
    192197> Type :POP to abort, :R for a list of available restarts.
    193198> Type :? for other options.
    194 }}}
    195 
    196 Note the the uvector index in the report is the row-major index of the
     1991 >
     200}}}
     201
     202In this case, uvector index in the report is the row-major index of the
    197203element that was written to.
    198204
     
    203209of the elements are stored pairwise in this vector.
    204210
     211One problem with trying to monitor hash tables for writes is that the
     212underlying hash-table-vector is replaced with an entirely new one when
     213the hash table is rehashed.
     214A previously-watched hash-table-vector will not be the used by the hash table
     215after rehashing, and writes to the new vector will not be caught.
     216
    205217{{{
    206218? (defvar *h* (make-hash-table))
    207 #<HASH-TABLE :TEST EQL size 0/60 #x3000412BF96D>
     219*H*
    208220? (setf (gethash 'noise *h*) 'feep)
    209221FEEP
    210 ? (watch (ccl::nhash.vector *h*))
    211 NIL
     222? (watch *h*)
     223#<HASH-TABLE-VECTOR #xDD00D>
     224;;; underlying hash-table-vector
    212225? (setf (gethash 'noise *h*) 'ding)
    213 > Error: Write to watched uvector #<HASH-TABLE-VECTOR #xD500D> at index 35
     226> Error: Write to watched uvector #<HASH-TABLE-VECTOR #xDD00D> at index 35
    214227>        Faulting instruction: (lock)
    215228>          (cmpxchgq (% rsi) (@ (% r8) (% rdx)))
     
    2232361 > :b
    224237*(1A109F8) : 0 (%STORE-NODE-CONDITIONAL ???) NIL
    225  (1A10A50) : 1 (LOCK-FREE-PUTHASH NOISE #<HASH-TABLE :TEST EQL size 1/60 #x30004117F4ED> DING) 653
    226  (1A10AC8) : 2 (CALL-CHECK-REGS PUTHASH NOISE #<HASH-TABLE :TEST EQL size 1/60 #x30004117F4ED> DING) 229
     238 (1A10A50) : 1 (LOCK-FREE-PUTHASH NOISE #<HASH-TABLE :TEST EQL size 1/60 #x30004117D47D> DING) 653
     239 (1A10AC8) : 2 (CALL-CHECK-REGS PUTHASH NOISE #<HASH-TABLE :TEST EQL size 1/60 #x30004117D47D> DING) 229
    227240 (1A10B00) : 3 (TOPLEVEL-EVAL (SETF (GETHASH # *H*) 'DING) NIL) 709
    228241 ...