Update:

2013/6/20 Mikael <mikael.rcv@gmail.com>


2013/6/20 Marc Feeley <feeley@iro.umontreal.ca>
I will study your implementation soon.  I do have a few comments at this point:

1) It would be nice if there was more information in the resulting list when the reference is not in an object.  For example a string which names the global variable which references the object, a fixnum giving the number of the register which references the object, etc).

Yeah!

Following your suggestion above I made so that instead of non-object references leading to #!unbound , they lead to one of the following symbols:

'register:current-thread
'register:run-queue
'register:gvm-registers
'register:symbol-table
'register:keyword-table
'will-list:nonexecutable
'will-list:executable
'continuation
'rc

..and global variables lead to their name, as a symbol.

And added a variable so that the search is done only during |##resolve-referencing-objects| and the code path is disabled otherwise.

And last, made |##resolve-referencing-objects| return a plain list again as I found a way to do reference graph probing without using weak references.

Example use:

$ gsc
Gambit v4.6.9

> (define a "Hi")
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers a)
> (##resolve-referencing-objects (current-thread))
(register:current-thread
 register:gvm-registers
 register:gvm-registers
 #<thread #1 primordial>
 #<thread #1 primordial>
 #<run-queue #2>
 #<run-queue #2>
 #<run-queue #2>
 #<repl-channel-ports #3>
 #<thread-group #4 primordial>
 #<thread-group #4 primordial>)
> (load "dig-out-gc-roots-graph.scm")
> (define a "Hi")
> (define b (list a a))
> (define c (vector b b))
> (dig-out-gc-roots-graph a)
Digging out the GC roots for object #2...

References to object #2:
#2
  #3 (In work queue)
  #4 (In work queue)
  continuation
  ~#a

References to object #2:
#2
  #3 (In work queue)
  #4
    #5 (In work queue)
    #5 (In work queue)
    ~#b
  continuation
  ~#a

References to object #2:
#2
  #3
    #4 (In work queue)
  #4
    #5 (In work queue)
    #5 (In work queue)
    ~#b
  continuation
  ~#a

References to object #2:
#2
  #3
    #4 (In work queue)
  #4
    #5 (In work queue)
    #5
      ~#c
    ~#b
  continuation
  ~#a

References to object #2:
#2
  #3
    #4 (In work queue)
  #4
    #5 (This object was already found at a lower depth in the graph.)
    #5
      ~#c
    ~#b
  continuation
  ~#a

References to object #2:
#2
  #3
    #4 (This object was already found at a lower depth in the graph.)
  #4
    #5 (This object was already found at a lower depth in the graph.)
    #5
      ~#c
    ~#b
  continuation
  ~#a

Done!
All the objects that refer to this object in total (+ the object itself) are: #2 #4 #5 #3
All the objects that refer to this object closest to the root in total are: #5
>


An interesting oddity, that I don't see any reason for but that doesn't hurt is that references from wills generally is returned as 'will-list:nonexecutable but sometimes as the will object itself - this is only for wills that don't have an active reference from anywhere, such as from a global:

> (import lib/track_leaks)
> (define a "Hi")
> (make-will a (lambda (v) (void)))
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers ~#a will-list:nonexecutable)
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers ~#a will-list:nonexecutable)
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers ~#a will-list:nonexecutable)
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers ~#a #<will #3>)
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers ~#a will-list:nonexecutable)
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers ~#a will-list:nonexecutable)
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers ~#a will-list:nonexecutable)
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers ~#a #<will #3>)
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers ~#a will-list:nonexecutable)
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers ~#a will-list:nonexecutable)
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers ~#a will-list:nonexecutable)
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers ~#a #<will #3>)
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers ~#a will-list:nonexecutable)
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers ~#a will-list:nonexecutable)
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers ~#a will-list:nonexecutable)
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers ~#a #<will #3>)
> 1
1
> 2
2
> 3
3
> 4
4
> (##gc)
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers ~#a #<will #3>)
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers ~#a will-list:nonexecutable)
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers ~#a will-list:nonexecutable)
> (##resolve-referencing-objects a)
(register:gvm-registers register:gvm-registers ~#a will-list:nonexecutable)



Compilation is per the previous email.

I did not include any limiting mechanism on number of max references resolved by ##resolve-referencing-objects , as such usecases are extremely rare anyhow - I mean, how many objects did you ever have so many references to that ##resolve-referencing-objects 's response would occupy tens of megabytes?


Spontaneously this appears stable to me, and thus could be something to commit to the Gambit repo now.

Marc would probably have some suggestions for making the code better and more conformant to Gambit's general code style.



Best regards,
Mikael