I've been thinking a lot about the managing of vp->sp in such a way that we guard the stack with it as a top mark of the stack meaning everything below that mark should be scanned for gc protection. My hypothesis now is that we can keep changing this stack mark quite seldom but at right places and use a special system to make sure that we keep protecting the stack in the right way.
The ordinary logic for a instruction with a dst is to check the dst against vp->sp, if it's below vp->sp we use vp->sp as the upper mark and if it's above it we use dst as the upper mark. The idea is that the only time. This is then used to temporary cahnge e.g. vp->sp = dst over a c-call that may start the gc. The other sources of of gc'ing is when we jump back up the stack I solved that by adding a sp field in the branch instruction relating to if's, a pure br will not use a sp field but for those we will model when needed by an instruction sp.set!. Also return and call semantics also can go into gc and they are handed specially.
Note that we only need to protect and setup the sp-set! level at the start of the loop, typically the inner loops will be free of this instruction and therefore I expect the overhead to be minimal. Also when we translate to native code the overhead will be minimal. To note with is that with this tool we do not need to cleat fields after a let (we use sp-set!) in stead and also at the initial start we do not need to clear the frame.