🤖 AI Summary
This study addresses whether a programming language can fully simulate its own execution without support from a host interpreter or compiler, arguing that Turing completeness alone is insufficient to faithfully reproduce runtime behaviors such as control flow, exceptions, callbacks, and memory usage. To this end, the paper introduces the notion of “simulation completeness,” distinguishing between source-level and compiled-code-level simulation and defining both weak and strong forms. It establishes a dual framework of requirements from both the language and simulator perspectives. Through conceptual modeling, semantic analysis, and empirical investigation using languages like Erlang, the work develops the first formal classification system and structured terminology in this domain, offering theoretical foundations and practical guidance for language design, secure sandboxing, decompilation, and reflective execution.
📝 Abstract
We study when a programming language can emulate programs written in that same language without delegating the guest program back to the host evaluator or compiler. We call this property emulation-completeness. The central observation is that Turing-completeness by itself is not enough: a self-emulator must not only compute the guest program's result, but must also account for the guest-visible state on which realistic programs depend, including control flow, exceptions, callbacks, timing, memory usage, and runtime metadata such as stack traces or line numbers.
This paper is a systematization paper. Its contribution is not a new emulator implementation, but a precise vocabulary and a structured taxonomy for reasoning about self-emulation. We distinguish source-level evaluation from compiled-code emulation, define syntactic and compiled-code emulation-completeness, and separate weak from strong emulation-completeness according to how much observable runtime behavior must be preserved. We then organize the requirements into two classes: language-side requirements, which determine whether the guest semantics can be represented explicitly inside the language, and emulator-side requirements, which determine whether the resulting emulator can faithfully mask or reproduce relevant observations.
The discussion is grounded by concrete examples, including publicly documented details from Erlang, where argument limits, bitstring pattern matching, and message reception expose subtle mismatches between direct execution and self-emulation. The resulting framework is intended as guidance for language designers, implementers of evaluators and emulators, and researchers interested in secure sandboxing, decompilation, and reflective execution.