apt1002 / mijit

Experimental JIT compiler generator
https://github.com/apt1002/mijit/
25 stars 4 forks source link

Prologue and epilogue #20

Closed apt1002 closed 3 years ago

apt1002 commented 3 years ago

Allow code::Machines to define a "prologue" (code to execute on entry to Mijit) and an "epilogue" (code to execute on exit). I propose the following design:

Having prologue and epilogue code is helpful for the following reasons:

In principle, the Machine could have a separate prologue and epilogue tailored for each State, but I think that would be more annoying than useful. It would also provide places for obscure bugs to lurk. Instead, I suggest that we have just one prologue and epilogue, shared by all States, as described above.

I am content to impose a limit of 64 values() because they are expensive; they are marshalled to/from the Save every time you enter or exit Mijit. Only one persistent Value is actually needed: the pointer to the Save. The others are just a Register-allocation hint, i.e. an optimisation. If you are using more than 64, you're not using them right.

apt1002 commented 3 years ago

An analysis of goals:

  1. We want the Slots (unbounded in number) to be on the stack.
  2. We want the Registers and Slots to be dead when Mijit is not running.
  3. We want some Registers and Slots to be live in the root Machine::States, and we want to specify the live set in an ergonomic way.
  4. We want to allow the Machine to choose the Save data structure used to persist the state of the VM when Mijit is not running.
  5. We want to minimise the marshalling code that gets run on entry to and exit from Mijit.

Goal 1 deserves an issue of its own (#26) which also covers goal 2.

The combination of goals 2 and 3 motivates the prologue and epilogue code, whose purpose it to marshal data between the persistent state and the live set.

Goal 4 does not require any support from Mijit beyond providing a single persistent pointer to the prologue and epilogue code. The Machine can use it as a pointer to a Save if it wants; Mijit does not need to understand. So Machine::Save is an unnecessary concept.

Goal 5 essentially boils down to sharing between the persistent state and the live set. This can be done by reference, e.g. via the pointer to the Save. However, it is cheap and probably useful to provide some state that is shared "by value" too. I propose a constant-sized array of words (Globals?) that can be accessed as Values (alongside Registers and Slots) but which are always live and which persist when Mijit is not running. This is a mild generalisation of the single persistent pointer required by goal 4.

In summary, I propose the following design: