[Mono-devel-list] New compiler--CIL/CTS questions

Chris Capel chris at iBankTech.NET
Fri Feb 13 20:05:43 EST 2004

Hello, all.

I'm in the planning phases of writing a Lisp compiler for the CLI, and
I'm stuck trying to figure out how to implement dynamic functions
(lambdas and macros, basically) efficiently using CIL, and cooperating
as much as possible with the CTS.  The problem is, I don't see any way
to generate a method at runtime and then call it without using lots and
lots and lots of really slow, excruciatingly non-dynamic reflection.
The best I've managed so far is this:

AssemblyName n = new AssemblyName();
n.Name = "test";
AssemblyBuilder asm =
ModuleBuilder m = asm.DefineDynamicModule("test.exe", "test.exe");
MethodBuilder meth = m.DefineGlobalMethod("MyMethod",
	| MethodAttributes.Public, CallingConventions.Standard,
	typeof(void), null);
ILGenerator il = meth.GetILGenerator();
il.Emit(OpCodes.Ldstr, "Hello world");
il.EmitCall(OpCodes.Call, typeof(Console).GetMethod("WriteLine",
	new Type[] { typeof(string) }),
m.GetMethod("MyMethod").Invoke(null, null);

As you can see, this involves creating a module, or at *least* a type
(although I'm not even sure you can call methods on types in a non-baked
module or create new types in a baked one), for every single new
function you want to run, unless you interpret the function manually.  I
mean, I want to have an interpreter, but there's no question that to be
useful, this has to be a compiled language.  Even if this *wasn't* way
too much overhead, there's the issue that any types you created can't be
cleaned up later.  They're going to stick around in your application
domain until you quit.  Never garbage collected.  Never removed from
memory.  They'll just collect and accrue in your dynamic module until it
bursts.  Also, there's a conspicuous lack of any CIL instructions having
to do with dynamic-anything.  Does it bother anyone besides me that you
couldn't write the CTS using CIL, in anything nearly resembling

The only thing that occurs to me, given my limited knowledge of the CLI,
is to provide, like most other Lisp compilers, a normal interpreted
mode, and require that the compile function be used only at the
module/package/source file level, so that the overhead doesn't become to
great during debugging. But that solution doesn't solve the lambda/macro
problem (can you imagine the compiler creating a new type every time a
macro was expanded?), which is basically the
ever-growing-number-of-types-that-you-can't-get-rid-of problem; it
doesn't even mitigate it that much.  In fact, it's probably not any
better than making Lisp a non-interactive language, just like any old C
family member.

I read a posting on some MIT list that the CLI was too restrictive to
efficiently implement Lisp.  After reading the ECMA CLI spec, and
experimenting with the System.Reflection.Emit classes pertinent, I'm
beginning to agree.  And that's just a big shame.

Chris Capel

More information about the Mono-devel-list mailing list