while True:
instr = decode_instruction(pc)
execute_instruction(instr)
Where execute instruction is usually a big switch that has every opcode on it, or, in my case, is a call to a function in a table whose indices are opcodes.The problem is you decode the same instructions many times (in a loop, for instance). A slight more elaborated version is like this:
while True:
if not pc in cached_code:
block = generate_block(pc)
cached_code[pc] = block
run_from_cache(pc)
The generate_block function decodes and generates code for every instruction until it finds a jump. When it finds it, it finishes up that block, which is then added to the cache.Now, whenever there is a jump to an address that is in the cache, the cached code can be executed directly.
Finally, the captures up to three backwards jumps thing:
My first try was to have the cached code just be a regular function call without loops. So a block of code is executed and then control is given back to the main loop.
But a significant number of jumps have targets that are inside the same block of code (anything you run on a loop, for instance). So, to get better performance, I generate, for my block of code, a function that has a loop in it.
It has a rather characteristic look:
function code_block(cs) { // cs is the "cpu state"
var count = 0;
cs.next_pc = BLOCK_START;
block_loop: while(++count < 3) {
count++;
block_choice: switch(cs.next_pc) {
case BLOCK_START: cs.r0 = cs.r0 ^cs.r0;
case BLOCK_START+4: // regular instructions fall through
case CONDITIONAL_BRANCH_ADDR:
if(branch_condition) {
cs.next_pc = BRANCH_TARGET;
break block_choice; // this captures backwards jumps targeting the block
}
case UNCONDITIONAL_BRANCH_ADDR:
cs.next_pc = BRANCH_TARGET;
default: break block_loop;
}
}
}
The "captures up to three backwards jumps things" is controlled by the ++count < 3 loop condition. 3 was obtained by trial and error and looks like a good number for my machine (I could, for instance, put 100 in there, but then my javascript functions would take too much time to return and the javascript engines don't like this).