Skip to content
Felix S. Klock II edited this page Jul 28, 2013 · 1 revision

( Compare to CompileOnEval )

There is a parameter, load-evaluator, which controls what procedure will be used to evaluate the expressions that are read during a load of a file f. Normally load-evaluator is just an alias of (evaluator); that is, you use the main system evaluator as the evaluator for load.

For CommonLarceny, however, we have decided to have the standard evaluator be the interpreter (the interpret procedure), and the load-evaluator be an eval procedure, eval/clr, that first compiles the input to .il bytecode, emits it to a dynamically allocated Assembly, and then invokes the resulting procedure.

  • There is one corner case here: the compiler can't actually handle certain literals such as procedure objects, and so the backend will die saying that there's no way to emit il to load a procedure constant. But fasl files are essentially just scheme files with an extended syntax that includes procedure literals; so how can CompileOnLoad work if its going to try to compile every expression it reads while loading?
  • The answer to this corner case is that CompileOnLoad does not try to compile every expression it reads while loading; it pattern matches for certain expressions (namely ones that start with ((.common-patch-procedure ...) ...), and delegates them to the interpreter.

The reason that we are not using eval/clr for all evaluations is that the CommonLanguageRuntime does not garbage collect the dynamically generated/loaded representations of classes, and therefore every time you do one of these dynamic code generations, you allocate storage that will not be collected; this is a memory leak. While we think that such a memory leak will be acceptable if you only incur it on each file load, having every single ReadEvalPrintLoop interaction leak storage is probably unacceptable.

Note that if we ever get a JvmBackend going, we can probably do CompileOnEval there, because the JavaVirtualMachine does garbage collect unreachable classes.

(A potential solution for the DotNetBackend is to do something with finalizers/destructors and AppDomains; AppDomains and their associated classes apparently can be explicitly unloaded from memory, thus plugging the memory leak. PnkFelix has not investigated this option seriously, because he read somewhere that invocations across different AppDomains incur a large overhead, which may prohibit this approach for us.)

Clone this wiki locally