Hey,
I am a bit confused about the CollectorRegistry.
I am attempting to write a garbage collector for LLVM, and the tiny
example in the docs at
http://llvm.org/releases/2.3/docs/GarbageCollection.html gives this
line:
CollectorRegistry::Add<MyCollector> X("mygc", "My bespoke garbage
collector.");
My question is now: Am I supposed to instantiate my collector
manually, and tell LLVM about it, or can the Registry instantiate it,
and it that case, how to go about that? I haven't been able to deduce
a way to get a pointer to my collector from the doxygen docs or the
header files, so I hope that you can help me here. 
Yours,
Simon
Hi Simon,
The compiler framework will instantiate and call into your Collector subclass automatically as required. The CollectorRegistry::Add<> instance advertises your class to the framework so it can do this. Your Collector class needs to have a default constructor in order to insantiate the Add<> template.
The framework decides which Collector to use based upon the 'gc' attribute of a function:
define void @f() gc "mygc" {
...
}
This string must correspond to the first argument to the CollectorRegistry::Add<> constructor.
The second argument to the constructor is, I think, "purely informational" for collectors. For the related TargetMachineRegistry, the second argument appears in --help output.
Hope that helps,
Gordon
Thank you for that clarification.
The framework decides which Collector to use based upon the 'gc'
attribute of a function:
define void @f() gc "mygc" {
...
}
OK, so for instance if I wanted to be able to use the GC from a C
frontend (presumably by using llvm_gc_allocate?), do the C functions
need this attribute as well?
And if so, can this attribute be applied to functions in bitcode
compiled by llvm-gcc, without modifications to the C compiler or the
output bitcode?
I.e., I use a custom driver program similar to lli that loads in
bitcode and my GC, and executes it, and ideally programs would be able
to use the GC without needing bitcode-level modifications (it's
perfectly ok to have to replace calls to malloc, though).
This string must correspond to the first argument to the
CollectorRegistry::Add<> constructor.
The second argument to the constructor is, I think, "purely
informational" for collectors. For the related TargetMachineRegistry,
the second argument appears in --help output.
Hope that helps,
Gordon
It helps a lot. Thank you for your time. 
Simon
Thank you for that clarification.
The framework decides which Collector to use based upon the 'gc' attribute of a function:
define void @f() gc "mygc" {
...
}
OK, so for instance if I wanted to be able to use the GC from a C frontend (presumably by using llvm_gc_allocate?), do the C functions need this attribute as well?
Yes.
And if so, can this attribute be applied to functions in bitcode compiled by llvm-gcc, without modifications to the C compiler or the output bitcode?
I.e., I use a custom driver program similar to lli that loads in bitcode and my GC, and executes it, and ideally programs would be able to use the GC without needing bitcode-level modifications (it's perfectly ok to have to replace calls to malloc, though).
I would say that accurate GC would generally require considerable cooperation from the front-end compiler, which GCC does not particularly provide. But you could experiment with it. Simply adding a GC attribute to an existing function should generally be harmless (e.g., the inliner will do so inlining a function with GC into a function without), but doing so won't annotate the roots in the function.
— Gordon
I would say that accurate GC would generally require considerable
cooperation from the front-end compiler, which GCC does not
particularly provide. But you could experiment with it. Simply adding
a GC attribute to an existing function should generally be harmless
(e.g., the inliner will do so inlining a function with GC into a
function without), but doing so won't annotate the roots in the
function.
Hm, it seems this will be more interesting than I had initially
expected. I had assumed that the annotation took place at the IR
level, so frontend compilers would not need to be modified. Would this
be a viable alternative in the future?
If not, do you think it would require very significant changes to the
GCC frontend to make it annotate roots on the stack etc.?
I'm thinking along the lines of a command-line option a la:
llvm-gcc --emit-llvm -c myfile.c -o myfile.bc --garbage-collector=mygc
This could be a fun project, if the GCC code is not too hard to modify
like this. 
– Simon
I would say that accurate GC would generally require considerable cooperation from the front-end compiler, which GCC does not particularly provide. But you could experiment with it. Simply adding a GC attribute to an existing function should generally be harmless (e.g., the inliner will do so inlining a function with GC into a function without), but doing so won't annotate the roots in the function.
Hm, it seems this will be more interesting than I had initially expected. I had assumed that the annotation took place at the IR level, so frontend compilers would not need to be modified. Would this be a viable alternative in the future?
Unlikely.
If not, do you think it would require very significant changes to the GCC frontend to make it annotate roots on the stack etc.?
I'm thinking along the lines of a command-line option a la:
llvm-gcc --emit-llvm -c myfile.c -o myfile.bc --garbage-collector=mygc
This could be a fun project, if the GCC code is not too hard to modify like this. 
Indeed, llvm-gcc can emit llvm.gcroot, but the source program must request it. Someone at Apple starting working with LLVM did this for fun circa January, IIRC. Unclear whether it's useful.
— Gordon
Indeed, llvm-gcc can emit llvm.gcroot, but the source program must
request it. Someone at Apple starting working with LLVM did this for
fun circa January, IIRC. Unclear whether it's useful.
Interesting! Do you know/remember who, and if his/her patches went
into mainline llvm-gcc?
It could be fun to see if I can do anything useful with it.
- Simon
I forgot I still needed an answer to my original question. 
So, I have to implement llvm_gc_initialize, llvm_gc_allocate, and
llvm_gc_collect (llvm_cg_walk_gcroots is provided by the Collector
framework, right?) -- in those methods, how do I access the Collector
object instantiated by LLVM?
(It appears I do have to implement them myself, since otherwise there
are unresolved symbols when I call them directly from my IR)
- Simon
I forgot I still needed an answer to my original question. 
So, I have to implement llvm_gc_initialize, llvm_gc_allocate, and llvm_gc_collect
Yes. Your implementation of the llvm_gc_* functions should be compiled into a library and linked with your executable.
(llvm_cg_walk_gcroots is provided by the Collector framework, right?)
An implementation of llvm_cg_walk_gcroots compatible with ShadowStackCollector is provided in the llvm/runtime directory. You can copy it into your runtime.
in those methods, how do I access the Collector object instantiated by LLVM?
I'm not sure the purpose of doing so—llvm::Collector (poorly named; I'm open to suggestions) exists only in the compiler, not at runtime in the compiled program. You should need access to it at runtime no more than you might need access to an instance of llvm::TargetMachine.
— Gordon
Maybe I don't understand the architecture correctly.
This means that the implementation of my collector's data structures
(in this case, a few heaps) is supposed to be independent on the
subclassed llvm::Collector?
I had initially implemented it as
class SimonCollector : public llvm::Collector
{
public:
// ... virtual methods from llvm::Collector
void* allocate(...) { /* my allocator */ }
void collect() { /* ... */ }
// etc.
};
but actually allocate, collect, etc. aren't supposed to be there, but
in some separate structure that is accessed by both my llvm::Collector
subclass (or rather, the assembly generated in the lowering passes)
and llvm_gc_*?
If that is the case, then I agree, it's a poor name -- at least it got
me confused. 
It's hard to come up with good alternatives, though. Hmm.
I looked a bit at the ShadowStackCollector class, and suddenly it
makes much more sense. But I fail to find any implementations of
llvm_gc_allocate and friends?
- Simon
2008/7/26 Gordon Henriksen <gordonhenriksen@me.com>:
I’m not sure the purpose of doing so—llvm::Collector (poorly named; I’m open to suggestions) exists only in the compiler, not at runtime in the compiled program. You should need access to it at runtime no more than you might need access to an instance of llvm::TargetMachine.
Maybe I don’t understand the architecture correctly.
This means that the implementation of my collector’s data structures (in this case, a few heaps) is supposed to be independent on the subclassed llvm::Collector?
That’s correct. llvm::Collector exists to coordinate the compiler and generate code compatible with your GC runtime library. It is not itself part of your GC runtime library.
I had initially implemented it as
class SimonCollector : public llvm::Collector
{
public:
// … virtual methods from llvm::Collector
void* allocate(…) { /* my allocator / }
void collect() { / … */ }
// etc.
};
but actually allocate, collect, etc. aren’t supposed to be there, but in some separate structure that is accessed by both my llvm::Collector subclass (or rather, the assembly generated in the lowering passes) and llvm_gc_*?
Yes.
If that is the case, then I agree, it’s a poor name – at least it got me confused.
It’s hard to come up with good alternatives, though. Hmm.
I looked a bit at the ShadowStackCollector class, and suddenly it makes much more sense. But I fail to find any implementations of llvm_gc_allocate and friends?
llvm_gc_* are optional interfaces. If you want your allocation routines to look different, then you’re free to do so. I consider that section of the document deprecated to obsolete.
That said, they’re not implemented by the Collector class, so you shouldn’t expect to find them anywhere under llvm/lib. I believe the semispace example in llvm/runtime provides implementations of these interfaces, however.
— Gordon
Thank you so much for your help! I now have a much clearer idea of how
to proceed. 
This just keeps getting more interesting.
- Simon
I have a few additional questions, that aren't immediately crucial:
1) The implementation of EscapeEnumerator in ShadowStackCollector.cpp
doesn't seem to handle setjmp/longjmp. I could also imagine this would
be a bit complicated to implement reliably (even though setjmp.h does
not guarantee that the stack is intact when returning as the result of
a longjmp). Has this case been considered?
2) In ShadowStackCollector a linked list is used to keep track of the
roots, which seems sensible (quick insertion and deletion, but slow
lookup, but collections are rare), but I suppose this list would
quickly be corrupted if more than one thread would use the garbage
collector at the same time. One solution would be to use thread local
storage for the linked lists (pthread_getspecific or similar). Is this
conclusion correct, and does the proposed solution sound like a really
bad idea to you?
- Simon 