Instead of pushing and popping every single caller-saved registers,
we can optimize code size (and speed!) by only pushing the one register
we actually care about: RDI (since it holds our VM&).
This means that native calls may clobber every other caller-saved
register, so this is something that you have to be aware of when
emitting native calls in the JIT.
This reduces code size on Kraken/ai-astar.js by 553 KiB and makes
execution time ~6% faster as well! :^)
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 emitting the "restore callee-saved registers and return"
sequence again and again, just emit it once at the end of the generated
code, and have everyone jump to it.
This is a code size optimization that saves 207KiB on Kraken/ai-astar.js
This restores the bytecode interpreter's original call exception
throwing behaviour to the JIT.
This also fixes 8 of the 10 failing test-js tests when running with the
JIT enabled.
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.
Move TabPosition into its own file, and using it into the global
namespace the same way we do for Gfx::Orientation. This unbreaks the gn
build, and out of tree builds.
The backtrace execinfo API takes the number of addresses the result
buffer can hold instead of its size, for some reason. Previously
backtraces larger than 256 frames deep would write past the end of the
result buffer.
All the MOVs in the B8-BF range can use the REX.W prefix, not just B8.
Previously instructions like `48 B9... mov rcx, imm64` were interpreted
as `mov rcx, imm32` because the REX.W prefix was only applied to
`48 B8... mov rax, imm64`.
MAX_GENERATED_VALUES_PER_TEST is now the --randomized_runs flag:
$ ./Build/lagom/bin/TestGenerator --randomized_runs 1000
It's sometimes useful to try larger numbers for it instead of the
default of 100.
MAX_GEN_ATTEMPTS_PER_VALUE is now a constexpr. It's not usually needed
to tweak this value; we can recompile with a different value on the rare
occasion.
unsigned_int(0) doesn't need to draw bits from RandomnessSource.
An expression for getting INT_MAX for u32 didn't need to be
special-cased over the general formula.
This is a follow-up on a few comments
As it turns out, cxx_to_boolean() may return "bool" as other values
than just 0 or 1. This happens when the C++ compiler decides to only
update the AL portion of the RAX return value register instead of
the whole thing.
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.
When we know the value is a positive Int32 less than 0x7fffffff,
it's safe to just add 1 to it and use that as the final result.
This avoids the work of re-adding the INT32_TAG.
Compiler now has a BasicBlockData struct for each BasicBlock. The struct
contains all the stuff that we previously stored with the
Bytecode::BasicBlock.