I have a few things baking in the oven, but unfortunately not a great deal of time during which to work on them.
A quick little thing I began working on is an AOP-ish framework for IL munging. I've been able to hack together some really neat stuff in a relatively short amount of time using AbsIL. My first cut is in C#, but I would like to take a stab at writing the whole thing in OCaml/F#. I've used a variety of Java AOP frameworks in the past, but I never found one I really fell in love with.
What I've done thus far is, by using an external configuration file, created a simple set of controlled IL refactorings to wrap and redirect method calls and bodies. Essentially, there are two primary modes I'm worrying about at first: callsite interception, and method body interception. The fact that IL is a stack-based language leads to some interesting possibilities. For example, I have one mode that replaces calls to certain methods with another of a similar signature. This is actually quite straightforward and requires little work to the IL leading up to or after a method call.
Consider this IL:
IL_0000: ldstr "**mcall:Add({0}, {1})"
IL_0005: ldc.i4.2
IL_0006: newarr [mscorlib]System.Object
IL_000b: stloc.1
IL_000c: ldloc.1
IL_000d: ldc.i4.0
IL_000e: ldarg.1
IL_000f: box [mscorlib]System.Int32
IL_0014: stelem.ref
IL_0015: ldloc.1
IL_0016: ldc.i4.1
IL_0017: ldarg.2
IL_0018: box [mscorlib]System.Int32
IL_001d: stelem.ref
IL_001e: ldloc.1
IL_001f: call void [mscorlib]System.Console::WriteLine(string,
object[])
To mutate this so that we call an intercepting method of the same signature rather than Console.WriteLine, we merely change line 001f. The stack transition is the same (string, object[]) -> (nil). Moreover, I have a neat little hack that enables wrapping interceptors “around“ method calls. We simply write a new method that takes string and object[] parameters and returns void, but which also takes a delegate of the signature of Console.WriteLine. This might be a bit difficult to follow, but this enables our intercepting method to delegate to the original method in a very controlled fashion (if it wishes to do so). Rather than illustrating in IL, consider some code:
void SomeMethod()
{
Console.WriteLine(“One, two, three, four: {0}, {1}, {2}, {3}“, 1, 2, 3, 4);
}
We can easily munge the IL for this to be:
void SomeMethod()
{
InterceptingMethod(new Intercepted(Console.WriteLine), “One, two, three, four: {0}, {1}, {2}, {3}“, 1, 2, 3, 4);
}
delegate void Intercepted(string s, params object[] o);
void InterceptingMethod(Intercepted i, string s, params object[] o)
{
Console.WriteLine(“Before method call...“);
i(s, o);
Console.WriteLine(“After method call...“);
}
Assuming the intercepting code provides the delegate, it's just a matter of creating the delegate at the right place on the stack... (a bit tricky if we need to find the right point to insert it at the beginning, but this is easily avoidable if it comes at the end of the parameter list... not easily conceptualized with the above C# signature because of the syntactic sugar of 'params', but remember it's just an array in IL). We then substitute the intercepting method, just as with the first example presented.
This is obviously not terribly flexible, as you'd need a new interceptor for each unique method signature. I'm working on that, and will likely get around it by passing detailed context which can easily be “applied“ to accomplish the delegate call as above.
Just outputting text to the console probably isn't very interesting, but there is a wealth of possibilities to what we could do instead. I would enumerate them now, I'm sure you can imagine. :) And of course more interesting things can be provided to the interceptor in addition to the delegate. For example, detailed captures of any locals at the time a method call is made, the arguments passed to a method, and so on. I'm creating a standard type which will capture all of this. There is a cost, of course, so you will have to opt in to receive it.
This is just one of many interesting patterns. I must say: I love AbsIL. :) The OM is a bit whacky and odd if you're working in C# (Reflector is your friend) but extremely powerful once you get used to it. Of course, I suppose a hardcore geek would be doing this in OCaml...
Of course, my Scheme compiler and interpreter is on the top of my stack. Still plugging away, but it's taking a bit longer than I had expected. I've been speaking with some folks at MS that have written compilers, and they echoed what I am finding: it takes much longer than you would first expect. :)
My DesignByContractInC# thing is still around, but I just haven't had a chance to really dive deep into it. Through some experimentation, I've found the SSCLI C# compiler isn't quite as pluggable/extensible as I had originally hoped.