SignatureResolver (unfinished)

While writing the ILVisualizer for dynamic method late 2005, I'd like to show the local variable information as well; so I started working on the managed signature parser, at least to parse LocalVarSig (Ecma-335 23.2.6). It was 2+ years ago, and never got to a finished state. Now perhaps I will never spend more time on it, so I refreshed the code a bit and you may find it useful for some scenarios.

Here is an example of how to use SignatureResolver to get LocalVarSig in IronPython. The static method SignatureResolver.GetLocalVarSig takes the byte array (the signature blob) and the enclosing method, and returns an array of LocalVar (which includes mainly the runtime type) inside that method.

 # show local variables for every Array.CreateInstance overload methods
import clr
import System
clr.AddReference("ClrTest.Reflection.SignatureResolver")
from ClrTest.Reflection import *

for method in clr.GetClrType(System.Array).GetMember("CreateInstance"):
    body = method.GetMethodBody()   # C# won't allow this
    tok = body.LocalSignatureMetadataToken
    sig = method.DeclaringType.Module.ResolveSignature(tok)
    print "> %s, 0x%x" % (method, tok)
    for lv in SignatureResolver.GetLocalVarSig(sig, method):
        print lv

Next is part of the output showing one Array.CreateInstance method's local variable types. The result is, of course, same as what Reflector tells us in the below picture. "(p)" means the local variable is pinned.

 > System.Array CreateInstance(System.Type, Int32[], Int32[]), 0x11000009
System.RuntimeType 
System.Int32 
System.Int32& (p)
System.Int32& (p)
System.Array 
System.Int32[] 
System.Int32[] 
System.RuntimeTypeHandle 

arraycreateinstanceloc

Yes, I understand the MethodBody.LocalVariables property gives us the similar information; but the dynamic method can not. That was why I wanted to decode the bytes, and to use DynamicScopeTokenResolver to get a meaningful type string. I admit this version of code diverts from its original goal: it only works for RuntimeMethodInfo/RuntimeConstructorInfo, and won't work for dynamic method; but if one day, you are in need of parsing blob, the functions like GetToken/GetInt32Uncompressed could be handy. GetToken basically is the reverse of TypeDefOrRefEncoded (ecma-335: 23.2.8)

 int GetToken() {
    int token = GetInt32Uncompressed();
    return s_mapForTokenType[token & 0x03] | (token >> 2);
}

int GetInt32Uncompressed() {
    byte first = _sig[_pos];

    if (first <= 0x7F) {
        return _sig[_pos++];
    } else if (first <= 0xBF) {
        byte[] bytes = new byte[2];
        bytes[1] = (byte)(_sig[_pos++] - 0x80);
        bytes[0] = _sig[_pos++];
        return BitConverter.ToInt16(bytes, 0);
    } else {
        byte[] bytes = new byte[4];
        bytes[3] = (byte)(_sig[_pos++] - 0xC0);
        bytes[2] = _sig[_pos++];
        bytes[1] = _sig[_pos++]; ;
        bytes[0] = _sig[_pos++];
        return BitConverter.ToInt32(bytes, 0);
    }
}

My SignatureResolver also provide another static method GetMethodRefSig to get MethodRefSig (Ecma-335 22.25 and 23.2.2).

If you are interested in this topic, you may download the attached file, unzip it, and take a look at the source. Also try to use VS2008 to build it.

If you are an IronPython user, you may try the accompanying tests (in IronPython). I compare the SignatureResolver.GetLocalVarSig result with the official reflection API MethodBody.LocalVariables: they are same for all method/constructors from all simple-LoadFrom-successful framework assemblies. If you have ClrTest.Reflection.ILReader.dll (or know how to get one), you can try test_methodrefsig.py, which tests GetMethodRefSig.

As stated in the title, this is *unfinished* and could be buggy.

Disclaimer: THE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES INTENDED OR IMPLIED. USE AT YOUR OWN RISK.

SignatureResolver2008.zip