The IR needs a new instruction of the form:
change_TUB( the_tub, the_new_destination )
I was thinking it could be a call to a backend function to which we pass a reference to the TUB instruction.
- How can the TUB be identified? A first-class pointer to a label? A
global name? How does the IR reference a TUB identifier?
Probably the linker should store the address of the TUB patch point and the corresponding code block reference on the TUB IR instruction.
- How can the new destination of the TUB be identified? A first-class
pointer to a label/function? A global name?
A reference to another basic block. The list of blocks the TUB can possibly go to should probably be determined in advance at IR generation time.
- Who is the code patcher (in other words which part of the system is
doing the code patching)? How is the relevant code patching information passed to the code patcher?
The backend, because it knows the details of the architecture best. Possibly the patched sequences could be pre-generated at IR generation time, and ready to be written at the right offset.
- What is the IR for a global function call? It seems that IR
pseudo-code would be something like:
the_tub_label: tub_branch unoptimized_label unoptimized_label: fn = getprop( globalobj, "f" ) call fn, nbargs=2, arg1, arg2
One basic block would have the generic getprop and call. The other would have the optimized static call or possibly the whole inlined function. The TUB would initially go to the optimized entry, but could go to the unoptimized one as well, and this would be indicated in the IR.
One concern is the code bloat due to the duplication of calls.
We should look at this more. You often talk about code size, including the size of the encodings of specific instructions, but we haven't done any experiments to measure the potential impact this could have.
Also, there are two branches (the TUB and the call) in the optimized and unoptimized versions
Possibly only one branch in the optimized case if the optimized entry point immediately follows.
how can we use TUBs to optimize calls in the case where the number of arguments of the call site matches the number of parameters of the callee (to avoid setup of the argument count parameter and the check of the argument count in the callee)?
We can put any code we want in the block for the optimized case.
As I said in my previous message, we will start with an implementation of the code patching for global function calls in the back-end, allowing us to greatly improve the performance at a low implementation cost. After milestone 2 we can look at code patching at the IR level.
The cost will be about the same for the more flexible system, and I'm pretty sure the implementation will go significantly faster if I help. I suggest we discuss this in person tomorrow.
- Maxime