On 07.07.2011 08:31, Nate Fries wrote:> On 7/6/2011 6:24 PM, Talin wrote: >> The LLVM code generators and analysis passes have a much more >> thorough knowledge of SSA value lifetimes than frontends do, and >> therefore could avoid spilling and reloading of values when it wasn't >> needed. > Although this would indeed be nice, it is not done by similar > platforms in practice. I have investigated [very] briefly into whether > the CLR or JVM implement garbage collection in their IR, and it does > not seem that they do (meaning, the CLR/JVM implementation itself is > responsible for garbage collection, not the code generated by the > CLR/Java language compilers).I'm not sure this is a valid comparison. CLR and JVM IRs are typed, and by nature of those VMs, *all* pointers on the stack and in registers are automatically GC roots. Unlike LLVM, the JVM (and I think the CLR) doesn't even have a concept of a non-GC pointer. Sebastian -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20110707/789d671e/attachment.html>
For the past few years, my group in Intel Labs has been working on a project similar to LLVM and C--, and perhaps our experience in handling roots and stack walking could be useful in deciding how LLVM should evolve in the GC area. Our project is called Pillar (you can see our paper "Pillar: A Parallel Implementation Language" in Languages and Compilers for Parallel Computing 2008 for a general overview). Pillar is a generic language and runtime designed to support managed languages and parallel languages although most of our work so far has been on the managed side. We've implemented a JVM and a functional language on top of Pillar so it has evidenced some generality. In the Pillar language, we have a generalized ref (similar to llvm.gcroot) data type that encompases different kinds of pointers and types into the managed heap. This could be regular pointers, a couple varieties of interior pointers, or user-defined pointer types. The underlying compiler then generates per-callsite stack maps. Those stack maps can indicate when a live ref (local or parameter) is at a known offset from the start of the frame and can also indicate when a live ref is present in a register. If we want to enumerate the refs of a call stack, we call a runtime function, prtYoungestActivation, and that gives us back a stack iterator for the sequence of activations. The iterator contains the value for esp and pointers to the memory locations where ebp, eip, edi, esi, and ebx were last saved to the stack. (For architectures other than 32-bit x86, the register-specific contents of the activation would of course be defined differently.) In the eip case, this is saved for every activation as part of the call sequence and so provides you with the ability to determine which call site you are at. The other registers may have been saved by the current frame or a subsequent frame. The stack iterator also contains a virtual frame number that basically allows an unwinder to see logical activations instead of physical activations that may combine multiple logical activations via inlining. You can then call another runtime function, prtEnumerateRootsOfActivation, to ask for the roots associated with the given stack iterator's current activation to be enumerated. To this function, you pass a PrtRseInfo struct that contains a callback that gets invoked once per live ref found and a opaque environment variable passed (unexamined) onto the callback function. To go to the next activation on the call stack, you then call the runtime's prtNextActivation. There are routines to determine when you've got to the bottom of the call stack as well. In addition, there are routines for performing other (non-GC) operations the stack iterator's activation, such as looking up data associated with the SPAN construct (taken from C--) or exception handlers. We have a couple of associated constructs in this regard. The first is the concept of code regions. We can define regions of code and define different owners for each region. A typical configuration is for most code to be in a region associated with our compiler, another region for code implemented in the Pillar runtime, and another region for code implemented in our GC. You first register a code info manager with the Pillar runtime and then associate regions of code with that manager. When you register, you provide a set of callback functions to enumerate roots, unwind to the next activation, etc. So, the Pillar compiler's code info manager uses a callback that consults the previously generated stack maps in order to enumerate roots. The GC could optimize its barriers and provide its own code info manager to handle enumerating roots in those barriers. Thoughts? Todd Below are the relevant portions from our runtime's include files. /* This is essentially a pointer-sized integer. */ typedef char *PrtRegister; /* These are used to document function parameters to indicate whether they are IN, OUT, or INOUT. */ #define PRT_IN #define PRT_OUT #define PRT_INOUT /* *********************************************************************************************** * Basic constants, definitions, and types. *********************************************************************************************** */ /* These are tags that the GC uses to interpret roots that are enumerated. Some tags require additional parameters that need to be passed in as well. The interface includes a single argument that can be used directly for a single parameter, or treated as an array or struct pointer if multiple parameters are required. Several tags are predefined for the compiler's benefit, but the high-level language is free to use them as well. "Default": The root points to the canonical object address (usually the base). No additional parameters are used, and the argument is ignored. "Offset": The root is at a known offset from the canonical object address. Subtract the int-type parameter from the root to get the canonical object address. Example: the root points to a specific field of an object. "Base": The root is related to an object whose canonical address is found as the ref-type parameter. Example: the root points to some array element contained within the object. Any tag value starting from UserDefined and beyond can be defined and used by the high-level language and its associated GC implementation. */ typedef enum { PrtGcTagDefault = 0, PrtGcTagOffset = 1, PrtGcTagBase = 2, PrtGcTagUserDefined = 3 } PrtGcTag; /* Points to executable code. It is "unsigned char *" so that arithmetic is valid. */ typedef unsigned char *PrtCodeAddress; /* Points to a sequence of data bytes. It is "unsigned char *" so that arithmetic is valid. */ typedef unsigned char *PrtDataPointer; /* Forward declarations of nonexistent structures, to avoid typedef'ing to void*. */ struct PrtCimSpecificDataStruct; struct PrtCodeInfoManagerStruct; /* * The context for stack frames that is used during stack walking. We use pointers in place of * direct values to support root set enumeration. */ struct PrtStackIterator { /* Stack pointer, eip, and frame pointer */ PrtRegister esp; PrtRegister *ebpPtr; PrtCodeAddress *eipPtr; /* Callee-save registers */ PrtRegister *ediPtr; PrtRegister *esiPtr; PrtRegister *ebxPtr; /* The Pillar compiler may inline several "virtual" frames into a single "physical" frame. However, the stack iterator should maintain the illusion that no inlining was done. This field keeps track of which virtual frame we are at within the physical frame. The value 0 means the newest, innermost frame, and the value is incremented when doing a virtual unwind within the same physical frame. */ unsigned virtualFrameNumber; }; /* struct PrtStackIterator */ /* * Type of procedures called once for each enumerated root. "rootAddr" is the address of a pointer-sized field * containing either a reference to a heap object or a managed pointer. "env" is an (opaque to Pillar) value * that the client passed in a PrtRseInfo structure in the call */ typedef void (*PrtRseCallback)(void *env, void **rootAddr, PrtGcTag tag, void *parameter); struct PrtRseInfo { PrtRseCallback callback; /* invoked for each enumerated root */ void *env; /* opaque value to be passed in each call to the callback function */ }; /* struct PrtRseInfo */ /* ********************************************************************************************************** * Stack iteration functions ********************************************************************************************************** */ /* * Create a stack iterator for the current task. "si" points to client-allocated storage. */ void prtYoungestActivation(PRT_OUT struct PrtStackIterator *si); /* Go to the activation previous to (older than) the current one. */ void prtNextActivation(PRT_INOUT struct PrtStackIterator *si); /* Return True iff no activations remain on the stack. */ #define prtIsActivationPastEnd(si) (((si)->eipPtr == NULL)? PrtTrue : PrtFalse) /* Return the ip for the current activation. */ #define prtGetActivationIP(si) ((PrtCodeAddress)((si)->eipPtr ? *(si)->eipPtr : 0)) /* Convenience function for updating all writable fields of a stack iterator at once. The advantage of using this consistently is that if the PrtStackIterator ever changes, this function can be changed accordingly, and all calls to it can be easily found and modified. */ void prtSetStackIteratorFields(PRT_OUT struct PrtStackIterator *context, PRT_IN PrtCodeAddress *eipPtr, PRT_IN PrtRegister esp, PRT_IN PrtRegister *ebxPtr, PRT_IN PrtRegister *ebpPtr, PRT_IN PrtRegister *esiPtr, PRT_IN PrtRegister *ediPtr, PRT_IN unsigned virtualFrameNumber); /* * Returns the value associated with the smallest span tagged with "key" and containing the program point * where "si" is suspended. Returns (PrtDataPointer)NULL if there is no such span. */ PrtDataPointer prtGetSpanDescriptor(PRT_IN struct PrtStackIterator *si, PRT_IN unsigned key); /* Enumerate the roots of a frame given by the specified stack iterator. */ void prtEnumerateRootsOfActivation(PRT_IN struct PrtStackIterator *si, PRT_IN struct PrtRseInfo *rootSetInfo); /* *********************************************************************************************** * Code Info Manager functions *********************************************************************************************** */ typedef struct PrtCodeInfoManagerStruct *PrtCodeInfoManager; /* Type of client-specified data that a client can associate with each code range with a prtCodeInfoManager. */ typedef struct PrtCimSpecificDataStruct *PrtCimSpecificDataType; /* * A set of callback functions implemented by a producer of managed code (e.g., a JIT or static compiler) that the PRT * can call as part of its implementation of stack walking, root set enumeration, exception handling, etc. These are * used to define a CodeInfoManager. */ struct PrtCodeInfoManagerFunctions { /* Returns a string describing the current frame. */ char * ( *cimGetStringForFrame)(PRT_IN struct PrtStackIterator *si, PRT_OUT char *buffer, PRT_IN size_t bufferSize, PRT_IN PrtCimSpecificDataType opaqueData); /* Modifies si to hold information about the frame previous to the current one. Returns True if this was successful, and False if not. opaqueData is the same as the opaqueData that was passed to Pillar when the CIM registered this code region. */ void ( *cimGetPreviousFrame)(PRT_INOUT struct PrtStackIterator *si, PRT_IN PrtCimSpecificDataType opaqueData); /* Enumerates the live GC roots of the current stack frame. The activation is guaranteed to be suspended at a call site. */ void ( *cimEnumerateRoots)(PRT_IN struct PrtStackIterator *si, PRT_IN struct PrtRseInfo *rootSetInfo, PRT_IN PrtCimSpecificDataType opaqueData); /* Returns the value associated with the smallest span tagged with "key" and containing the program point where "si" is suspended. "opaqueData" is the same data that the CIM passed to Pillar when it registered the code region containing si's program point. Returns (PrtDataPointer)NULL if there is no such span. */ PrtDataPointer ( *cimGetSpanDescriptor)(PRT_IN struct PrtStackIterator *si, PRT_IN unsigned key, PRT_IN PrtCimSpecificDataType opaqueData); }; /* struct PrtCodeInfoManagerFunctions */ /* Creates a new PrtCodeInfoManager and registers a set of callback functions belonging to it. */ PrtCodeInfoManager prtRegisterCodeInfoManager(PRT_IN const char *theCimName, PRT_IN struct PrtCodeInfoManagerFunctions theCimFns); /* * Register the block of code in [start..end] with the given PrtCodeInfoManager. * Returns True on success and False on failure (e.g., if the code's region overlaps that of already-registered code). * The opaqueData parameter is associated with this code region and passed back to the Cim during each of the calls * to the Cim for this code region. */ void prtAddCodeRegion(PRT_IN PrtCodeInfoManager theCim, PRT_IN PrtCodeAddress start, PRT_IN PrtCodeAddress end, PRT_IN PrtCimSpecificDataType opaqueData); -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20110707/a531975c/attachment.html>
On 7/7/2011 4:50 AM, Sebastian Redl wrote:> On 07.07.2011 08:31, Nate Fries wrote: >> On 7/6/2011 6:24 PM, Talin wrote: >>> The LLVM code generators and analysis passes have a much more >>> thorough knowledge of SSA value lifetimes than frontends do, and >>> therefore could avoid spilling and reloading of values when it >>> wasn't needed. >> Although this would indeed be nice, it is not done by similar >> platforms in practice. I have investigated [very] briefly into >> whether the CLR or JVM implement garbage collection in their IR, and >> it does not seem that they do (meaning, the CLR/JVM implementation >> itself is responsible for garbage collection, not the code generated >> by the CLR/Java language compilers). > I'm not sure this is a valid comparison. CLR and JVM IRs are typed, > and by nature of those VMs, *all* pointers on the stack and in > registers are automatically GC roots. Unlike LLVM, the JVM (and I > think the CLR) doesn't even have a concept of a non-GC pointer. > > Sebastian > > > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdevPerhaps you are right to point that out. I can't claim to be an expert in compiler/language/GC design here. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20110707/ac80648f/attachment.html>
My thoughts are many, and inline below: On Thu, Jul 7, 2011 at 10:55 AM, Anderson, Todd A <todd.a.anderson at intel.com> wrote:> For the past few years, my group in Intel Labs has been working on a > project similar to LLVM and C--, and perhaps our experience in handling > roots and stack walking could be useful in deciding how LLVM should evolve > in the GC area. Our project is called Pillar (you can see our paper > "Pillar: A Parallel Implementation Language" in Languages and Compilers for > Parallel Computing 2008 for a general overview). Pillar is a generic > language and runtime designed to support managed languages and parallel > languages although most of our work so far has been on the managed side. > We've implemented a JVM and a functional language on top of Pillar so it has > evidenced some generality.**** > > ** ** > > In the Pillar language, we have a generalized ref (similar to llvm.gcroot) > data type that encompases different kinds of pointers and types into the > managed heap. This could be regular pointers, a couple varieties of > interior pointers, or user-defined pointer types. The underlying compiler > then generates per-callsite stack maps. Those stack maps can indicate when > a live ref (local or parameter) is at a known offset from the start of the > frame and can also indicate when a live ref is present in a register.**** > > ** >I assume that by interior pointer you mean a pointer to the inside of another object?> ** > > If we want to enumerate the refs of a call stack, we call a runtime > function, prtYoungestActivation, and that gives us back a stack iterator for > the sequence of activations. The iterator contains the value for esp and > pointers to the memory locations where ebp, eip, edi, esi, and ebx were last > saved to the stack. (For architectures other than 32-bit x86, the > register-specific contents of the activation would of course be defined > differently.) In the eip case, this is saved for every activation as part > of the call sequence and so provides you with the ability to determine which > call site you are at. The other registers may have been saved by the > current frame or a subsequent frame. The stack iterator also contains a > virtual frame number that basically allows an unwinder to see logical > activations instead of physical activations that may combine multiple > logical activations via inlining.**** > > ** >That all makes sense. I would say that your framework is at a somewhat higher level than I would expect LLVM to support - by that, I mean that ideally it should be possible to use the primitives that LLVM supplies to build exactly what you have described. My own use case has slightly different requirements, and as a result I could not adopt your framework as it is - but I see no reason why I should not be able to use the same LLVM primitives to build what I need. The main difference has to do with the handling of disjoint types in my language. For example, if I declare a variable using the following syntax: var a:String or float or int; What the compiler generates is a data structure that looks like this (as it would appear in C): struct { int disc:2; // 0 = String, 1 = int, 2 = float union { String * s; int i; float f; }; }; The garbage collector needs to examine the 'disc' field in order to know whether to trace 's' or not. The way I handle this is by treating the entire structure as a root, rather than just the pointer field, so that what the garbage collector sees is a pointer to the beginning of the struct. I suspect that register maps wouldn't be able to handle this case very well. SInce the data structure can't fit into a single register, it would have to be 'sliced' - half in one register and half in another - and the register map would need some way to communicate to the collector which half of the struct is in which register. (Or worse, what if only one half was in a register and the other half on the stack?) I'm guessing that the right answer is "don't do that" - meaning, don't allow this data structure to be sliced in that way, at least not during a safe point. ** You can then call another runtime function, prtEnumerateRootsOfActivation, to ask for the roots associated with the given stack iterator's current activation to be enumerated. To this function, you pass a PrtRseInfo struct that contains a callback that gets invoked once per live ref found and a opaque environment variable passed (unexamined) onto the callback function. To go to the next activation on the call stack, you then call the runtime's prtNextActivation. There are routines to determine when you've got to the bottom of the call stack as well. In addition, there are routines for performing other (non-GC) operations the stack iterator's activation, such as looking up data associated with the SPAN construct (taken from C--) or exception handlers.**** In my own case, I don't have an iterator for roots within a single activation, rather I have a static data structure that describes how to find all of the roots within the call frame. One of my design goals is to minimize the number of function calls required to trace a pointer, so the different parts of my code accept whole stack maps as arguments instead of single pointers. However, the LLVM approach to generating stack maps is flexible enough to handle either case - your GCStrategy plugin gets a list of all stack roots for each safe point, and you can transform that into whatever data structures you need. We have a couple of associated constructs in this regard. The first is the concept of code regions. We can define regions of code and define different owners for each region. A typical configuration is for most code to be in a region associated with our compiler, another region for code implemented in the Pillar runtime, and another region for code implemented in our GC. You first register a code info manager with the Pillar runtime and then associate regions of code with that manager. When you register, you provide a set of callback functions to enumerate roots, unwind to the next activation, etc. So, the Pillar compiler's code info manager uses a callback that consults the previously generated stack maps in order to enumerate roots. The GC could optimize its barriers and provide its own code info manager to handle enumerating roots in those barriers.**** ** ** Thoughts?**** ** ** Todd**** ** ** ** ** Below are the relevant portions from our runtime’s include files.**** ** ** ** ** /* This is essentially a pointer-sized integer. */**** typedef char *PrtRegister;**** ** ** /* These are used to document function parameters to indicate whether they are IN, OUT, or INOUT. */**** #define PRT_IN**** #define PRT_OUT**** #define PRT_INOUT**** ** ** /***** *********************************************************************************************** **** * Basic constants, definitions, and types.**** *********************************************************************************************** **** */**** ** ** /* These are tags that the GC uses to interpret roots that are enumerated.** ** Some tags require additional parameters that need to be passed in as well.**** The interface includes a single argument that can be used directly for a** ** single parameter, or treated as an array or struct pointer if multiple*** * parameters are required.**** Several tags are predefined for the compiler's benefit, but the high-level**** language is free to use them as well.**** "Default": The root points to the canonical object address (usually the base).**** No additional parameters are used, and the argument is ignored.**** "Offset": The root is at a known offset from the canonical object address.**** Subtract the int-type parameter from the root to get the canonical**** object address. Example: the root points to a specific field of**** an object.**** "Base": The root is related to an object whose canonical address is found as**** the ref-type parameter. Example: the root points to some array element**** contained within the object.**** Any tag value starting from UserDefined and beyond can be defined and used**** by the high-level language and its associated GC implementation. **** */**** typedef enum { PrtGcTagDefault = 0, PrtGcTagOffset = 1, PrtGcTagBase = 2, PrtGcTagUserDefined = 3 } PrtGcTag;**** ** ** /* Points to executable code. It is "unsigned char *" so that arithmetic is valid. */**** typedef unsigned char *PrtCodeAddress;**** ** ** /* Points to a sequence of data bytes. It is "unsigned char *" so that arithmetic is valid. */**** typedef unsigned char *PrtDataPointer;**** ** ** /* Forward declarations of nonexistent structures, to avoid typedef'ing to void*. */**** struct PrtCimSpecificDataStruct;**** struct PrtCodeInfoManagerStruct;**** ** ** /***** * The context for stack frames that is used during stack walking. We use pointers in place of **** * direct values to support root set enumeration.**** */**** struct PrtStackIterator **** {**** /* Stack pointer, eip, and frame pointer */**** PrtRegister esp;**** PrtRegister *ebpPtr;**** PrtCodeAddress *eipPtr;**** /* Callee-save registers */**** PrtRegister *ediPtr;**** PrtRegister *esiPtr;**** PrtRegister *ebxPtr;**** /* The Pillar compiler may inline several "virtual" frames into a single "physical" frame.**** However, the stack iterator should maintain the illusion that no inlining was done.**** This field keeps track of which virtual frame we are at within the physical frame.**** The value 0 means the newest, innermost frame, and the value is incremented when**** doing a virtual unwind within the same physical frame. */**** unsigned virtualFrameNumber;**** }; /* struct PrtStackIterator */**** ** ** /***** * Type of procedures called once for each enumerated root. "rootAddr" is the address of a pointer-sized field**** * containing either a reference to a heap object or a managed pointer. "env" is an (opaque to Pillar) value **** * that the client passed in a PrtRseInfo structure in the call**** */**** typedef void (*PrtRseCallback)(void *env, void **rootAddr, PrtGcTag tag, void *parameter);**** ** ** struct PrtRseInfo **** {**** PrtRseCallback callback; /* invoked for each enumerated root */**** void *env; /* opaque value to be passed in each call to the callback function */**** }; /* struct PrtRseInfo */**** ** ** /***** ********************************************************************************************************** **** * Stack iteration functions**** ********************************************************************************************************** **** */**** ** ** /* **** * Create a stack iterator for the current task. "si" points to client-allocated storage.**** */**** void prtYoungestActivation(PRT_OUT struct PrtStackIterator *si);**** ** ** /* Go to the activation previous to (older than) the current one. */**** void prtNextActivation(PRT_INOUT struct PrtStackIterator *si);**** ** ** /* Return True iff no activations remain on the stack. */**** #define prtIsActivationPastEnd(si) (((si)->eipPtr == NULL)? PrtTrue : PrtFalse)**** ** ** /* Return the ip for the current activation. */**** #define prtGetActivationIP(si) ((PrtCodeAddress)((si)->eipPtr ? *(si)->eipPtr : 0))**** ** ** /* Convenience function for updating all writable fields of a stack iterator at once.**** The advantage of using this consistently is that if the PrtStackIterator* *** ever changes, this function can be changed accordingly, and all calls to* *** it can be easily found and modified.**** */**** void prtSetStackIteratorFields(PRT_OUT struct PrtStackIterator *context,**** PRT_IN PrtCodeAddress *eipPtr,**** PRT_IN PrtRegister esp,**** PRT_IN PrtRegister *ebxPtr,**** PRT_IN PrtRegister *ebpPtr,**** PRT_IN PrtRegister *esiPtr,**** PRT_IN PrtRegister *ediPtr,**** PRT_IN unsigned virtualFrameNumber);**** ** ** /* **** * Returns the value associated with the smallest span tagged with "key" and containing the program point **** * where "si" is suspended. Returns (PrtDataPointer)NULL if there is no such span. **** */ **** PrtDataPointer prtGetSpanDescriptor(PRT_IN struct PrtStackIterator *si, PRT_IN unsigned key);**** ** ** /* Enumerate the roots of a frame given by the specified stack iterator. */* *** void prtEnumerateRootsOfActivation(PRT_IN struct PrtStackIterator *si, PRT_IN struct PrtRseInfo *rootSetInfo);**** ** ** /* **** *********************************************************************************************** **** * Code Info Manager functions **** *********************************************************************************************** **** */**** ** ** typedef struct PrtCodeInfoManagerStruct *PrtCodeInfoManager;**** /* Type of client-specified data that a client can associate with each code range with a prtCodeInfoManager. */**** typedef struct PrtCimSpecificDataStruct *PrtCimSpecificDataType;**** ** ** /* **** * A set of callback functions implemented by a producer of managed code (e.g., a JIT or static compiler) that the PRT**** * can call as part of its implementation of stack walking, root set enumeration, exception handling, etc. These are**** * used to define a CodeInfoManager.**** */**** struct PrtCodeInfoManagerFunctions {**** /* Returns a string describing the current frame. */**** char * ( *cimGetStringForFrame)(PRT_IN struct PrtStackIterator *si,**** PRT_OUT char *buffer,**** PRT_IN size_t bufferSize,**** PRT_IN PrtCimSpecificDataType opaqueData);**** /* Modifies si to hold information about the frame previous to the current one. Returns True if this was successful,**** and False if not. opaqueData is the same as the opaqueData that was passed to Pillar when the CIM registered **** this code region. */**** void ( *cimGetPreviousFrame)(PRT_INOUT struct PrtStackIterator *si, *** * PRT_IN PrtCimSpecificDataType opaqueData);**** /* Enumerates the live GC roots of the current stack frame. The activation is guaranteed to be**** suspended at a call site. */**** void ( *cimEnumerateRoots)(PRT_IN struct PrtStackIterator *si, **** PRT_IN struct PrtRseInfo *rootSetInfo, **** PRT_IN PrtCimSpecificDataType opaqueData);**** /* Returns the value associated with the smallest span tagged with "key" and containing the program point **** where "si" is suspended. "opaqueData" is the same data that the CIM passed to Pillar when it registered **** the code region containing si's program point. Returns (PrtDataPointer)NULL if there is no such span. */**** PrtDataPointer ( *cimGetSpanDescriptor)(PRT_IN struct PrtStackIterator *si, **** PRT_IN unsigned key, **** PRT_IN PrtCimSpecificDataType opaqueData);**** }; /* struct PrtCodeInfoManagerFunctions */**** ** ** ** ** /* Creates a new PrtCodeInfoManager and registers a set of callback functions belonging to it. */**** PrtCodeInfoManager prtRegisterCodeInfoManager(PRT_IN const char *theCimName, PRT_IN struct PrtCodeInfoManagerFunctions theCimFns);**** ** ** /***** * Register the block of code in [start..end] with the given PrtCodeInfoManager. **** * Returns True on success and False on failure (e.g., if the code's region overlaps that of already-registered code).**** * The opaqueData parameter is associated with this code region and passed back to the Cim during each of the calls **** * to the Cim for this code region.**** */**** void prtAddCodeRegion(PRT_IN PrtCodeInfoManager theCim, **** PRT_IN PrtCodeAddress start, **** PRT_IN PrtCodeAddress end, **** PRT_IN PrtCimSpecificDataType opaqueData);**** ** ** _______________________________________________ LLVM Developers mailing list LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev -- -- Talin -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20110707/87a6bc84/attachment.html>
> Unlike LLVM, the JVM (and I think the CLR) doesn't even have a concept ofa non-GC pointer. .NET has native pointers that are pointers pointing outside the managed heap. Cheers, Jon. From: llvmdev-bounces at cs.uiuc.edu [mailto:llvmdev-bounces at cs.uiuc.edu] On Behalf Of Sebastian Redl Sent: 07 July 2011 09:51 To: llvmdev at cs.uiuc.edu Subject: Re: [LLVMdev] Improving Garbage Collection On 07.07.2011 08:31, Nate Fries wrote: On 7/6/2011 6:24 PM, Talin wrote: The LLVM code generators and analysis passes have a much more thorough knowledge of SSA value lifetimes than frontends do, and therefore could avoid spilling and reloading of values when it wasn't needed. Although this would indeed be nice, it is not done by similar platforms in practice. I have investigated [very] briefly into whether the CLR or JVM implement garbage collection in their IR, and it does not seem that they do (meaning, the CLR/JVM implementation itself is responsible for garbage collection, not the code generated by the CLR/Java language compilers). I'm not sure this is a valid comparison. CLR and JVM IRs are typed, and by nature of those VMs, *all* pointers on the stack and in registers are automatically GC roots. Unlike LLVM, the JVM (and I think the CLR) doesn't even have a concept of a non-GC pointer. Sebastian