Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET 4.5 MethodBuilder.SetMethodBody

In the newest version of the .NET framework, version 4.5, the MethodBuilder class has a method called SetMethodBody that I believe is exactly what I'm looking at as an alternative to using ILGenerator (which is annoying and limited in odd ways). The documentation can be found here, although since .NET 4.5 is not out yet, it is not fully documented. I can supply all but two of the arguments, but the rest I will need help with.

The first that I don't understand is byte[] localSignature, the third argument. MSDN states that it is "An array of bytes that contain the serialized local variable structure. Specify null if the method has no local variables." The trouble is, that's all it says, and I can't find out the format of a "serialized local variable signature." I have tried looking in the ECMA-335 spec, but all I have found is how to specify the local variables in unassembled CIL. If anybody could help me figure this out, it would be much appreciated.

Also, the last argument is IEnumerable<int> tokenFixups, which is "A collection of values that represent offsets in il, each of which specifies the beginning of a token that may be modified. Specify null if the method has no tokens that have to be modified.". I suspect that I won't need to use these, but I'd like to know what they are anyway.

Thanks, Brandon

like image 590
leviathanbadger Avatar asked Mar 10 '12 04:03

leviathanbadger


1 Answers

The real answer to my question was posted as a comment, instead of an answer, so in case anybody else ever has this question... here's the posted answer:

You'll need the SignatureHelper class. Fixups are only for compilers that translate native code to IL, like C++/CLI. – Hans Passant Mar 10 at 13:02

So... in order to get the byte array for the local signatures, you can execute this code:

var sig = SignatureHelper.GetLocalVarSigHelper(this.module);
sig.AddArgument(typeof(int)); //Local #0 is of type int
...
sig.AddArgument(typeof(string)); //Local #n is of type string
var sigArray = sig.GetSignature();

And in order to set the method body on the MethodBuilder, you call

MethodBuilder.SetMethodBody(il, maxStack, sigArray, handlers, fixups);

...where il is a byte[] with valid IL instructions (see this page), maxStack is an integer with the number of spots to reserve on the stack for the method, handlers is an System.Reflection.Emit.ExceptionHandler[], and fixups is a int[] array that can be ignored (with one exception, see below.)

One thing that I disagree with in Hans Passant's comment is that fixups are not only for compilers that translate native code into IL. I discovered when working on this that if you try to emit a call to a MethodBuilder method, it emits the wrong instruction. Looking at ILGenerator in .NET reflector, I found out that they emit a fixup each time they emit a method call. Adding a fixup for each method call indeed fixed this problem. There may be other places where you need to emit a fixup for it to work correctly, but I haven't looked into it much.

like image 151
leviathanbadger Avatar answered Nov 02 '22 23:11

leviathanbadger