This is in preparation for making LibJIT support multiple architectures.
Assembler will now be typedefed to the specific assembler
for a particular architecture.
Additionally, there's now JIT_ARCH_SUPPORTED which is defined on
architectures which LibJIT supports.
This makes JS::JIT::Compiler less architecture-specific
and unifies aligning the stack into a single operation,
where previously we were doing it separately for preserved registers
and for stack arguments.
Flip the order from save-registers,enter and leave,restore-registers
to enter,save-register and restore-registers,leave.
This way the return address is next to the saved frame pointer like
unwinding routines expect.
This makes the code a bit more readable and in conjunction with the
ModRM helper should prevent some operand ordering bugs.
This also includes one incidental bugfix:
`sign_extend_32_to_64_bits`, was not setting the `REX.R` bit when
appropriate,
And one size obvious optimization:
We may now elide the REX prefix on `xor eax, eax` as storing to a 32 bit
register clears the upper 32 bit of said register, which is wanted here.
This also widens the argument coverage of some helpers, to allow
memory offsets, this also consolidates the displacement size choosing.
This also stops us from some out argument ordering bugs, as we now just
need to look up the correct calling convention and call the correct
function.
Since all conditional instructions use a certain number of bits to
encode the condition type (from my observation of `Jcc`, `SETcc` and
`CMOVcc`), let's abuse that to deduplicate some code!
This adds a `Condition` enum that defines the type of condition we are
jumping based on, whose underlying values are the values that must be
encoded to trigger each condition.
The `test` instruction will have the same result as `cmp` when
comparing to zero, so let's always emit that code. This has no effect
until the following commit.
Instead of JIT::Assembler making the decision for everyone and forcing
out every caller-saved register in the ABI onto the stack, we now leave
that decision to users of JIT::Assembler.
Instead of adjusting the stack pointer before/after making native calls,
just make sure we come out of enter() with the stack pointer aligned
for making calls.
This is strictly a code size reduction. :^)
This replaces the existing sized immediate operands with a unified
immediate operand that leaves the size handling to the assembler,
instead of the user.
This has 2 benefits:
1. The user doesn't need to know which specific operand size the
instruction expects when using it
2. The assembler automatically chooses the minimal operand size that
fits the given value, resulting in smaller code size without any
additional effort from the user. While the change is small, it still
has a noticeable effect on performance (since it increases the I$ hit
rate), resulting in 5% speedup on kraken a-star.
If a mov instruction is meant to be patchable, we don't want to rewrite
it as a xor, since that removes the slot where we'd patch in the right
value later.
Also, make sure to set both size bits in the REX prefix for xoring a
register with itself.