Adding a new managed class to Rotor (that interacts with the EE)

I haven't actually posted anything technical to this blog yet - so I figured I'd hack
together a piece of source (with the internal help of the CLR devs) that illustrates
something semi-cool, yet can be extended by those that are interested in continuing
the work. The source diff shows how to add a managed class to Rotor that fcall's in
to the runtime and extracts runtime information we wouldn't otherwise have access
to. The diff is here
. I've also included C# code to use the new functionality here

Very brief overview of the diff

The managed class we're adding is called MethodBody, and hangs off the System.Reflection
namespace. The idea is get information about a method's metadata at runtime, in this
case, we're getting the methods maximum stack size, as defined in the ECMA Partition
II spec. We achieve this by reflecting over a method using MethodInfo, getting it's
handle and calling on our new class to do the work. Remember, you'll need to have
a look at the diff to get a complete understanding of what we're trying to do, but
here's the quick overview:

We modify \bcl\sources to include the MethodBody.cs file we're defining below,
so that it can be compiled into mscorlib.dll.



namespace System.Reflection

   using System;

   using System.Runtime.InteropServices;

   using CultureInfo
= System.Globalization.CultureInfo;


   public sealed class MethodBody


private int maxStackSize;

only called from within the EE

private MethodBody() {}

public int MaxStackSize
{ get { return maxStackSize;
} }



We get the MethodBody of a method through the MethodHandle of a MethodInfo object.
MethodHandle is a struct defined in runtimemethodhandle.cs in the bcl\reflection directory.
We add our GetMethodBody() call here:




public extern MethodBody

Then we define the fcall hookup in \vm\ecall.cpp:



ECFunc gCOMMethodHandleFuncs[] =



{FCFuncElement("GetMethodBody", NULL, (LPVOID) COMMember::GetMethodBody)},


Now we define the unmanaged GetMethodBody class:


class MethodBody
: Object



MethodBody() { }

MethodBody(MethodBody &r) {}


      INT32 maxStackSize;



Define where the work will happen:


static FCDECL1(MethodBody*, GetMethodBody,
MethodDesc **ppMethod);

And the real work. The unmanaged implementation of GetMethodBody. This code grabs
what we need, and fills the managed class with all the info, making a working MethodBody
object with the correct MaxStackSize of the method.


FCIMPL1(MethodBody *, COMMember::GetMethodBody,
MethodDesc **ppMethod)


MethodDesc* pMethod = *ppMethod;




TypeHandle thMethodBody(g_Mscorlib.FetchClass(CLASS__METHOD_BODY));

MethodBodyObj = (METHODBODYREF)AllocateObject(thMethodBody.GetMethodTable());

Module* pModule = pMethod->GetModule();

COR_ILMETHOD_DECODER MethodILHeader(pMethod->GetILHeader(), pModule->GetMDImport(),

MethodBodyObj->maxStackSize = MethodILHeader.GetMaxStack();




   return (MethodBody*)OBJECTREFToObject(MethodBodyObj);



Remember, the brief overview is just that, brief. To achieve a working implementation,
you'll need to tell the runtime a bit more about what you're doing. Check out/apply
the diff to have a real look under the hood.

I'd love to see someone extend the MethodBody managed/unmanaged class to retrieve
the method body IL in say... Byte[] array format? Any takers? Feel free to post it
in the comments section. ;)