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
int maxStackSize;
only called from within the EE

MethodBody() {}

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. 😉

Comments (5)
  1. Extending GetMethodBody to get the method code is surprisingly easy! I’ve put the code and written some notes on my WIki at . This adds a public byte[] GetIL() method to MethodBody. I haven’t tried calling this for non-IL methods… 🙂

Comments are closed.

Skip to main content