Previous: Implementation Up: Deferred Compilation: The Automation of Run-Time Code Generation Next: Deferred Compilation vs. Partial Evaluation

Costs of Deferred Compilation

The time required to optimize and generate code at run time has been our primary focus, but the time/space tradeoff exploited by deferred compilation has some secondary costs that must be considered in practice.

Code-space reclamation can be a significant cost in programs that pursue aggressive run-time code generation. Conventional garbage collection techniques will likely suffice, although some new strategies may prove profitable because dynamically allocated code objects differ from data objects in both size and lifetime. Garbage collection might be complicated by the fact that run-time-generated code may contain embedded pointers to other data and code objects; this can occur if pointers are inlined like other values during optimization.

Run-time code generation and modification can interact poorly with modern memory hierarchies [KLS92]. Most modern architectures prefetch instructions into an instruction cache and many do not automatically invalidate cache entries when memory writes occur. Cache flushing may therefore be required when dynamically generating or modifying code [Kep91]. The regularity of code-space allocation and initialization may simplify amortizing the cost of such operations. For example, the instruction cache could be flushed after code-space reclamation, and each newly allocated code object could be aligned to a boundary that the instruction prefetch mechanism is guaranteed not to have crossed while executing previously generated code, thus avoiding the invalidation of cached instructions. An architecture with a write buffer or a write-back data cache may require additional work to ensure that recently written instructions are fetched properly.

Another open question is how run-time code generation affects locality. Memory hierarchies offer substantial rewards to programs with highly localized data and instruction access patterns. Deferred compilation reduces locality by creating numerous optimized code blocks instead of executing a more general code block multiple times. Run-time inlining can increase code size significantly, thus decreasing locality. However, run-time dead-code elimination and other optimizations can also reduce code size. Techniques adapted from partial evaluation [Mog88] may also improve data locality by reorganizing data structures based on the staging of a program.

mleone@cs.cmu.edu