Managed CodeGen

This blog is to introduce some new features about Managed CodeGen in Whidbey. We provided a new way of doing LightWeight CodeGen, added support for emitting Generics in Reflection.Emit and there is some new exciting token handle stories in Reflection going on.

Token Resolution (I)

This is my first post. Let me start by introducing a small program that you can do with Whidbey Reflection.

Here is a small app showing you how you can get all the methods in Assembly A that is referenced by Assembly B. There was no API such as GetReferencedMethods before in Refleciton.

using System;
using System.Reflection;

public class GetRef
{
    public static void Main(string[] args)
    {
        if (args.Length != 2)
        {
            Console.WriteLine("Usage : GetRef hostAsm userAsm");
            return;
        }
        Assembly HostAsm = Assembly.Load(args[0]);
        Assembly UserAsm = Assembly.Load(args[1]);
        Module[] mods = UserAsm.GetModules();
        int c = 1;
        foreach (Module mod in mods)
        {
            Console.WriteLine("Wroking on Module : " + mod);
            try
            {
                while (true)
                {
                    MemberInfo mi = mod.ResolveMember(0x0A000000 | (c++)); // in CLI specification, all member ref tokens start with 0x0A
                    if (mi.Module.Assembly.FullName == HostAsm.FullName)
                        Console.WriteLine("[" + mi.Module.Assembly + "] " + mi);
                }
            }
            catch (ArgumentOutOfRangeException) // when we token gets out of range of what the assembly have, we throw the exception
            {
            }
        }
    }
}

Usage:

getref mscorlib b28423_ILGeneratorNull
Wroking on Module : b28423_ILGeneratorNull.exe
[mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089] Void .ctor(System.String)
[mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089] Void .ctor(DebuggingModes)
[mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089] Void .ctor(Int32)
[mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089] System.Type GetTypeFromHandle(System.RuntimeTypeHandle)
[mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089] System.Reflection.Module get_Module()
[mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089] Void .ctor(System.String, System.Type, System.Type[], System.Reflection.Module, Boolean)
[mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089] System.Delegate CreateDelegate(System.Type)
[mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089] Void WriteLine(System.String)
[mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089] System.String ToString()
[mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089] System.String Concat(System.String, System.String)
[mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089] Void .ctor()

And it is fast, simple and without duplications!

A token is the offset to the metadata table in an module. In a given assembly, we have many token tables for different entities, and here is a list of intersting token tables:

MemberRef : 0x0A

MethodDef : 0x06

MethodSpec : 0x2B

TypeDef : 0x02

TypeRef : 0x01

TypeSpec : 0x1B

Compile the following small program:

using System;
public class A
{
    public static void Main()
    {
        new B<int>().M<String>("Test");
    }
}
public class B<T>
{
    public void M<Z>(Z z)
    {
        Console.WriteLine(z);
    }
}

csc A.cs

ildasm A.exe

and press "Ctrl+M" inside ildasm, you can see all the metadata tables from there.

For example, Type A is a type Def token with offset 2. The token for type A is then 02000002.

A Type Spec means the instantiated generic type used in the assembly. We have B<int>, and its token is 1b000001, while B<T> is a TypeDef whose token is 02000003.

Please note that how to arrange tokens is a decision made by compilers. Compilers don't necessary put consecutive tokens (although I can hardly see why they won't do it) or let the tokens start from 1. For example, I found that in C# the type def token always starts with 2. Also if one program is compiled twice, it is likely the tokens inside will be rearranged. For example, it is possible that the next time I compile the program B<int> becomes 02000002 and type A becomes 02000003. So token is not a reliable way to cache type identity across runs. But once the assembly is loaded, the tokens should be fixed. So during the run, it is safe to think B<int>.MetaDataToken will never change.

 

 

Published Thursday, April 28, 2005 3:47 PM by yirutang

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

junfeng said:

Welcome to the blog world:)
April 28, 2005 10:01 PM
 

Mose from France said:

"So token is not a reliable way to cache type identity across runs."

Did you mean "across compilations" ?

I'm looking for a way to store types/members identities for given assemblies that won't be recompiled, to be able to identifies them in a Reflection-based tool.

Using Metadata seemed a good way to do it...

November 28, 2006 4:40 AM

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required
Submit

© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker