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 [addNewFCall.diff]. I've also included C# code to use the new functionality here [rotorfcallexamplecs.zip].

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 GetMethodBody();

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(), TRUE);
   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. ;)