Introduction
The goal of this second ungraded assignment is to write a threaded version of the virtual machine engine, in order to improve its performance, and then to quantify that improvement. To start this assignment, you can either use your own solution to the first assignment, or our version of minischeme.zip.
Part 1: writing the threaded engine
        Writing the threaded engine amounts to creating a new version
        of the engine module, called for example
        engine_threaded.c. Most of the code for that
        module can be taken directly from the current engine module,
        engine_switch.c. The two parts that must be
        adapted are the representation of instructions and the
        dispatching code.
      
        In the current, switch-based engine, instructions are directly
        represented by their opcode: all structures that describe the
        various forms of instructions (instr_t,
        instr_r_t, instr_rr_t, etc.) start with
        a field of type opcode_t. In a threaded interpreter,
        however, instructions are represented by the address of the code
        that implements them. All structures have to be adapted
        accordingly.
      
        Once this is done, the function that actually runs the code,
        engine_run, must be adapted. As explained in the
        course, a threaded interpreter does not have a dispatching
        loop. Instead, the dispatching code is duplicated at the end
        of every piece of code that implements an instruction. With
        gcc's labels-as-values
        extension, this dispatching code consists in a simple
        computed goto.
      
        A minor problem that you will encounter is that labels are
        local to the function that contains them. Therefore, labels in
        engine_run are not directly visible from the
        functions that emit code (engine_emit,
        engine_emit_r, etc.), which is a problem. One
        solution is to store these labels in a global array,
        initialized when the engine is itself initialised (i.e.
        when engine_setup is called). This initialisation
        can be done by calling engine_run in a special
        mode, during which it copies the addesses of its local labels
        to the global array and returns.
      
Part 2: measuring performances
Once you have written and tested the code, the next step is to measure the performance gain offered by the threaded interpreter, if any. This is relatively tricky, however, because the only way to loop in minischeme is using a recursive function call, which invariably leads to memory exhaustion, as the VM doesn't free memory yet! We suggest that you either write your test program directly in minivm assembly, or that you first compile a minischeme program and then modify it by hand to make sure it runs long enough without consuming memory.
A first small test is available here: test.asm