How local variable usage information is maintained in .net clr source code

This excellent answer explains how the GC can collect local variables before the method completes:

Jitter performs two important responsibilities when compiling IL for a method into machine code .... It also generates a table that describes how local variables are used inside the method body. This table has an entry for each argument of the method and a local variable with two addresses. The address where the variable will first save the link to the object. And the address of the machine code instruction where this variable is no longer used .... The "no longer used" address in the table is very important. This makes the garbage collector very efficient. It can collect a reference to an object, even if it is used inside a method and this method has not yet completed execution .

I am wondering what the JIT created internal tables look like and how the "no longer used" addresses are supported in the real clr source code . Can someone show me related code snippets in the newly open source source code of coreclr ?

+5
source share
1 answer

Disclaimer: I am not an expert in CLR or RyuJIT. Perhaps I am completely mistaken in all of this.

I met the following in the chapter of the RyuJIT Runtime Book:

For lvlVars with tracked lifetimes or for an expression containing GC links, we report the range in which the link is in real time. This is done by the emitter, which adds this information to the instruction group and which completes the instruction group when the GC information changes.

The structure that appears to store this information is in jit / jitgcinfo.h and looks like this:

struct varPtrDsc { varPtrDsc * vpdNext; unsigned vpdVarNum; // which variable is this about? unsigned vpdBegOfs ; // the offset where life starts unsigned vpdEndOfs; // the offset where life starts }; 

In the paragraph above, it is clear that these fields are filled in by the "emitter", and I believe that they mean jit / emit.cpp .

The start of the lifetime is set in emitter::emitGCvarLiveSet() ; appropriate exposure (spaces removed for brevity):

 /* Allocate a lifetime record */ desc = new (emitComp, CMK_GC) varPtrDsc; desc->vpdBegOfs = emitCurCodeOffs(addr); #ifdef DEBUG desc->vpdEndOfs = 0xFACEDEAD; #endif desc->vpdVarNum = offs; desc->vpdNext = NULL; 

The end of the lifetime is set in the same way in emitter::emitGCvarDeadSet() :

 /* Record the death code offset */ assert(desc->vpdEndOfs == 0xFACEDEAD); desc->vpdEndOfs = emitCurCodeOffs(addr); 

Finally, the tables are apparently written in jit / gcencode.cpp , in particular in GCInfo::gcMakeVarPtrTable() .

Hope this serves as a starting point if you want to continue exploring.

+4
source

All Articles