This changes registers to be temporarily stored in wasm locals, across
each complete wasm module. Registers are moved from memory to locals
upon entering the wasm module and moved from locals to memory upon
leaving. Additionally, calls to functions that modify registers are
wrapped between moving registers to memory before and moving back to
locals after. This affects:
1. All non-custom instructions
2. safe_{read,write}_slow, since it may page fault (the slow path of all memory accesses)
3. task_switch_test* and trigger_ud
4. All block boundaries
5. The fallback functions of gen_safe_read_write (read-modify-write memory accesses)
The performance benefits are currently mostly eaten up by 1. and 4. (if
one calculates the total number of read/writes to registers in memory,
they are higher after this patch, as each instructions of typ 1. or 4.
requires moving all 8 register twice). This can be improved later by the
relatively mechanical work of making instructions custom (not
necessarily full code generation, only the part of the instruction where
registers are accessed). Multi-page wasm module generation will
significantly reduce the number of type 4. instructions.
Due to 2., the overall code size has significantly increased. This case
(the slow path of memory access) is often generated but rarely executed.
These moves can be removed in a later patch by a different scheme for
safe_{read,write}_slow, which has been left out of this patch for
simplicity of reviewing.
This also simplifies our code generation for storing registers, as
instructions_body.const_i32(register_offset);
// some computations ...
instruction_body.store_i32();
turns into:
// some computations ...
write_register(register_index);
I.e., a prefix is not necessary anymore as locals are indexed directly.
Further patches will allow getting rid of some temporary locals, as
registers now can be used directly.
Makes the following a block boundary:
- push
- Any non-custom instruction that uses modrm encoding
- Any sse/fpu instruction
This commit affects performance negatively. In order to fix this, the
above instructions need to be implemented using custom code generators
for the memory access.
The generated rust code doesn't call read_imm* functions for custom
instructions now for the memory variant branches when both immediate
values and modrm byte is used
The following files and functions were ported:
- jit.c
- codegen.c
- _jit functions in instructions*.c and misc_instr.c
- generate_{analyzer,jit}.js (produces Rust code)
- jit_* from cpu.c
And the following data structures:
- hot_code_addresses
- wasm_table_index_free_list
- entry_points
- jit_cache_array
- page_first_jit_cache_entry
Other miscellaneous changes:
- Page is an abstract type
- Addresses, locals and bitflags are unsigned
- Make the number of entry points a growable type
- Avoid use of global state wherever possible
- Delete string packing
- Make CachedStateFlags abstract
- Make AnalysisType product type
- Make BasicBlockType product type
- Restore opcode assertion
- Set opt-level=2 in debug mode (for test performance)
- Delete JIT_ALWAYS instrumentation (now possible via api)
- Refactor generate_analyzer.js
- Refactor generate_jit.js
Previously a callback was used to insert the read_imm call after
modrm_resolve. The new api uses two calls, allowing the removal of some
edge cases and deletion of extraneous functions
In order of precedence:
--all generates all tables
--table jit{,0f_16,0f_32} / interpreter{,0f_16,0f_32}
And optionally:
--output-dir /path/to/output (defaults to v86 build directory)
This is in prep to let the make system generate individual tables as required
using this script instead of the script generating all 3.
Have output of generate table files use .c suffix
Remove write_sync_if_changed
The function existed to stop make from recompiling v86*.wasm everytime from
having the tables regenerated. With the upcoming change, this becomes unnecessary.
Correct Makefile to show dependency structure for generate scripts
This gets rid of the old global variable that let us return status flags from
jit_instruction. As a caveat, though, all prefix instructions also need to
return the status / tack it onto the existing status. This could give rise to
subtle bugs if instructions that mean to update the status don't propogate the
return status all the way up the chain.