Simple Reflector Addin: Count Box Instructions

Sooner or later I'm going to stop writing these simple tutorials and put some better content out here ... but until then, here is a simple walk through of creating a Reflector addin that will count the number of box instructions used in a method.

The majority of the code is the standard addin glue (IPackage implementation and a command button with event handler) ... things I'm sure you've seen before.  Somethings that you might not have seen before:

  • Adding the command button to the context menu for a method declaration by adding to the "Browser.MethodDeclaration" command bar
  • Using the AssemblyBrowser's ActiveItem property to get the item that is currently selected in the AssemblyBrowser (tree view)
  • Searching through a method's instructions for a specific IL instruction (in this case 0x8c for box)

In order to get this simple addin working, here is all you need to do:

  1. Create a new dll project and name it something like "BoxCount"
  2. Set a reference to Reflector.exe
  3. Set a reference to System.Windows.Forms
  4. Paste the following in your class code and compile:
using System;
using Reflector;
using Reflector.CodeModel;
using System.Windows.Forms;
 
namespace Reflector.Addin
{
    public class BoxCountPackage : IPackage
    {
        private ICommandBarManager commandBarManager;
        private ICommandBarSeparator separator;
        private ICommandBarButton button;
        private IAssemblyBrowser assemblyBrowser;
 
        public void Load(IServiceProvider serviceProvider)
        {
            this.assemblyBrowser = (IAssemblyBrowser)serviceProvider.GetService(typeof(IAssemblyBrowser));
            this.commandBarManager = (ICommandBarManager)serviceProvider.GetService(typeof(ICommandBarManager));
            this.separator = this.commandBarManager.CommandBars["Browser.MethodDeclaration"].Items.AddSeparator();
            this.button = this.commandBarManager.CommandBars["Browser.MethodDeclaration"].Items.AddButton("Count Box Instructions",
                new EventHandler(this.Button_Click));
        }
 
        public void Unload()
        {
            this.commandBarManager.CommandBars["Browser.MethodDeclaration"].Items.Remove(this.button);
            this.commandBarManager.CommandBars["Browser.MethodDeclaration"].Items.Remove(this.separator);
 
        }
 
        private void Button_Click(object sender, EventArgs e)
        {
            IMethodDeclaration methodDef = this.assemblyBrowser.ActiveItem as IMethodDeclaration;
            if (methodDef != null)
            {
                ShowBoxCount(methodDef);
            }
        }
 
        private void ShowBoxCount(IMethodDeclaration methodDef)
        {
            string message = string.Format("{0} box instructions found.", GetBoxCount(methodDef));
            MessageBox.Show(message);
        }
 
        private int GetBoxCount(IMethodDeclaration methodDef)
        {
            int boxCount = 0;
 
            IMethodBody methodBody = methodDef.Body as IMethodBody;
            if (methodBody != null)
            {
                foreach (IInstruction instruction in methodBody.Instructions)
                {
                    if (instruction.Value != null && instruction.Code == 0x8c)
                    {
                        boxCount++;
                    }
                }
            }
 
            return boxCount;
        }
    }
}

Once you have the addin built and added to your Reflector (View->Add-ins...) you need to test it. 

Create a Console app with the following code and compile:

using System;
 
namespace Boxing
{
    class Program
    {
        static void Main(string[] args)
        {
            int i = 2;
            int i2 = 4;
            Console.WriteLine(i + " test");
            Console.WriteLine(i + " test" + i2);
        }
    }
}

If you look at the IL code generated by for the sample app it looks something like this (note it has 3 box instructions):

.method private hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 3
    .locals init (
        [0] int32 i,
        [1] int32 i2)
    L_0000: nop 
    L_0001: ldc.i4.2 
    L_0002: stloc.0 
    L_0003: ldc.i4.4 
    L_0004: stloc.1 
    L_0005: ldloc.0 
    L_0006: box int32
    L_000b: ldstr " test"
    L_0010: call string [mscorlib]System.String::Concat(object, object)
    L_0015: call void [mscorlib]System.Console::WriteLine(string)
    L_001a: nop 
    L_001b: ldloc.0 
    L_001c: box int32
    L_0021: ldstr " test"
    L_0026: ldloc.1 
    L_0027: box int32
    L_002c: call string [mscorlib]System.String::Concat(object, object, object)
    L_0031: call void [mscorlib]System.Console::WriteLine(string)
    L_0036: nop 
    L_0037: ret 
}

If you add the sample console app to the assembly browser in Reflector and right click on the Main method you should have a context menu item of "Count Box Instructions" like shown below:

image

When you click on the menu item, you should now get a message box like the following:

image

Now you have a simple addin that will count the box instructions in a method for you.

posted on Monday, November 05, 2007 8:27 PM

Feedback

# New and Notable 201

SOA Nick has his fourth post in a series on the impact of the business operating model on Service Oriented
11/6/2007 8:38 AM | Sam Gentile

# Links from the Sharpside [11.06.07]

Links from the Sharpside [11.06.07]
11/6/2007 8:53 PM | Tales from the SharpSide

# re: Simple Reflector Addin: Count Box Instructions

To pinpoint box/unbox use, you can also use the tool NDepend and write the CQL query:

SELECT METHODS WHERE IsUsingBoxing OR IsUsingUnboxing
3/8/2008 7:01 AM | Patrick Smacchia

Post Comment

Title  
Name  
Url
Comment   
Please enter the following code into the box below to stop spammers

  
Enter Code Here *