Yes I'm finding a lot of complexities while trying to implement a compacting GC. The way I'm planning on doing it is with the "virtual stack" I mentioned previously. Each thread will have such a stack, and each of a function's ref type variables and parameters are really a pointer to a location on this stack like this:
So while the value that is stored in the virtual stack can change as the class is moved around, foo itself never needs to change. When moving classes around, what I will need to do is check each value on each thread's virtual stack and update any pointers that have changed. Still trying to think what will be the most efficient way of doing this, but I believe in concept it will work.
For static ref type variables, I will just create one C function that is hardwired to check each class's static ref variables and call the Mark mentioned in the original post. Also there will be one C function that is hardwired to update any static ref pointers that have changed.
For class ref type variables, each class will have a hardwired function that can be used to update any of it's ref type pointers that could have changed. Something like:
if (m_foo != NULL) m_foo->UpdatePointer(oldPointer, newPointer);
// Do the same for all other class ref types... }
[Sorry, I'm not doing the code blocks again, sometimes C9 loses it's mind and insists that all code should be on one line only. I'll just indent the text for now (which apparently doesn't seem to work either)]
Hmm, now that I think about it, that might not work because classes that are not reachable will never be called. If those classes are not rooted but they are still performing some sort of operations (maybe in some long running loop or a timer callback), their class variables will not be updated. So probably I will need to call UpdatePointer on each class while walking the object heap. In that case the UpdatePointer function will only update its own ref type variables, not call into UpdatePointer for each of its non-null ref objects. So it simplifies to:
On a different topic, I ran into an interesting problem. So I have this concept that I will need to create "pure" classes due to the fact that many of the standard classes make internal calls, which I cannot decompile and create C++ code for. So just as an experiment, I added these lines of code to my C# test app:
var list = new List<int>(); list.Add(1); list.Add(2);
And my C++ code suddenly got hugely bloated with all sorts of seemingly unrelated classes like the CultureInfo, etc with all of their huge amounts of static string resources etc. It seems that List is referencing those classes somewhere directly or indirectly, possibly through its static constructor. So I'm pulling in all of those types and doing a call graph analysis on their static constructors (which I need to call for all types I include), which is probably why it is detecting that all of those need to be included. Also in most cases it eventually hits an internal call and all bets are off.
Not sure how to work around that problem. Maybe I can do a better call graph analysis and only include static variables if the call graph actually references them (I might even do this for all variables - if they are never referenced in the call graph, I think they can be completely ignored, no?).
It won't be fun if I have to create "pure" versions of all the generic types, etc. But remember that the bar in this case is extremenly low: The .Net Micro Framework doesn't even support generics at all, so the fact that I do is already a big advantage given the ultimate goal of creating C++ code that can be compiled for a microcontroller.
Yet another different topic: Right now you can debug your .Net MF code running on a microcontroller using VS, just like any other .Net app (no edit and continue though). Since the .Net MF code is open source, I plan to figure out how it is done and ultimately (far down the line), I'd like to support debugging from VS. I can store as much or as little metadata for each type as I want, so I could make it such that using some VS plugin, I can map a current instance of any type back to the original type in the original .Net code (and pass it's member values to the debugger as well), so I think it should be possible to make a VS debugging plugin. Has anyone had experience with this, and how difficult would such a project be?