Translating Managed Pointers
This document discusses .NET managed pointers and how they can be supported on Parrot.
About .NET Managed Pointers
A managed pointer holds the address of a local variable or parameter on the stack, a field from an object or an element in an array. These can be used with a number of instructions that load and store data indirectly, that is using the address in the pointer. The "managed" part means that a number of limitations are placed upon the pointer. Namely, in verifiable code, the location the pointer references can only be set by a limited number of instructions and can not be modified by user code. This means that the pointer will always point to a valid location so the safety of the VM can not be comprimised.
Parrot Issues
Parrot, at the time of writing, lacks a straightforward way to implement managed pointers. One issue is that there is no official and documented way to obtain references to or the addresses of registers, fields of objects or array elements. Another is that post-translation, there is nothing to distinguish a register holding a reference, so verification as used in .NET does not help with regard to protecting the Parrot VM at runtime. Further complications arise with regard to references to arrays and objects as even if undocumented knowledge of internals are used there is still no clean way to get the address of an element or field, and also while the location of a PMC stays constant, the data that it holds need not, thus meaning the pointer is potentially invalidated at some point. Registers are somewhat to get the address of, but present a security issue - if the managed reference exists beyond lifetime of the register frame that it has a pointer into, whatever is in memory at that location at a later time can be written over.
The Basics
A managed pointer is represented by a ManagedPointer PMC, specifically a dynamic PMC written specifically for the .NET translator rather than provided by the Parrot core. Beneath it will be a structure containing details of the pointer (conceptually, the location it points to), however it will not be possible to set or modify this from outside of the PMC. This will ensure one of the safety properties of managed pointers hold. There will also need to be a flag that states what kind of location the pointer is pointing at (This is not needed by a standard .NET VM, but a standard .NET VM Parrot is not.)
Managed pointers to array elements
As the index of the array element being referenced is always known at the time the pointer is created, the pointer can be emulated by storing the index and a pointer to the array PMC, then using the PMC v-table methods to get and set the value. The array PMC needs to be marked live when the garbage collector visits the managed pointer PMC, so the object holding the referenced field can not disappear.
Managed pointers to fields
Similar to the array case, the name of the field along with a pointer to the object PMC can be stored and used to implement indirect access to the field. The object PMC needs to be marked live for GC purposes too.
Managed pointers to registers
This covers managed pointers to local variables and paramters, which are all stored in registers. The current method that is being executed will have a Parrot_Context structure associated with it. This structure contains data relating to the method state and references its register frame. It also has a reference count relating to how many items are currently using it. It would be much more convenient if it was actually elligible for garbage collection, then it could be marked live just as arrays and objects that are referenced are. It appears that this is the long term goal, but for now it can't work.
Instead, when a managed pointer is created it takes a pointer to the current context and increment its reference count. This count is be decremented in the destructor for the managed pointer PMC. The type and number of the register the pointer is referencing also needs to be stored. This mechanism should ensure that the safety of the VM by preventing register frames that are still referenced from vanishing. Admittedly, this is somewhat evil and is certainly playing with parts of the internals liable to change. However, it works.
Implementation
The managed pointer PMC has the following underlying structure.
struct dotnet_managed_ptr { int type; /* The type of managed pointer this is. */ union ref { PMC* pmc; /* For arrays, fields. */ Parrot_Context *ctx; /* For registers. */ } union tag { int index; /* For arrays. */ STRING *name; /* For field name. */ struct reg_info { /* For registers. */ int number; int reg_type; } } }