Ramsey Nasser

Using Mono.Cecil for code generation

For a long time I had incorrectly assumed that the fantastic Mono.Cecil library could only operate on CLR bytecode on disk. This was a problem for because I wanted to write languages that had REPLs and live coding systems that depended on the ability to generate code in memory at runtime, so I assumed Cecil was not an option. My earlier compilers used the System.Reflection.Emit API to do code generation, with the conspicuous AppDomain.DefineDynamicAssembly and TypeBuilder.CreateType producing runnable code in memory, figuring this was the only way to do it.

It turns out I was way wrong. Cecil does not have a similarly direct API but you can still pull it off. The trick is to write the ModuleDefinition to a MemoryStream and then load those bytes via the Assembly.Load overload that expects a byte array. Here’s the F# implementation from a compiler I am working on.

open System.Reflection
open Mono.Cecil

let writeToMemory (modDef : ModuleDefinition) : Assembly =
    use stream = new MemoryStream()
    modDef.Write(stream)
    Assembly.Load(stream.GetBuffer())

Boom, just like that you have a usable Assembly loaded into your AppDomain. It seems obvious in hindsight but it really kept me away from Cecil for a while — which is a shame because their API is really wonderful!