What is sljit?
The sljit is a stack-less platform independent JIT compiler, or perhaps a platform
independent assembler is even a better name. Since it is a stack-less
implementation, the arguments of sljit LIR (low-level intermediate representation)
instructions are either machine registers or memory locations. The memory addressing
modes are similar to x86, but simplified a little. It can be an absolute address, a
base register with an immediate offset, or a sum of a base and a left shifted offset
register. This approach is very effective for byte-code interpreters since
their machine independent byte code (middle level representation) typically contains
instructions which either can be easly translated to machine code, or not worth to
translate them at all.
Interpreter byte-code instruction examples
pop - pop from stack
Very easy to implement in sljit level, since it just decrease
the stack pointer by 1.
add - add
Fast case for integer addition, and slow case for anything else.
resolve - resolve an identifier
Not suitable to do it in JIT level, just call a nativ C++ helper function.
Pattern matching: JIT-ing regular expressions
PCRE-sljit combines the well known PCRE regular expression library
with the performance boost provided by sljit, creating a lightning fast,
PERL compatible backtracking engine. More about this project
can be found here. Comparing the PCRE-sljit
with other engines can be found here.
Different CPU architectures are ... really different. Software ABI (function call,
stack handling mechanism) could make the problem even more difficult. The goal of
this poject to find a platform independent assembler, which is both platform
independent (enough), and all architectures can be supported without considerable
overhead (fewest instructions possible). Thus, we can expect high performance from
the resulting code on all supported CPUs.
What a JIT ...
... can do
decrease the number of executed instructions, which speeds up the
execution. You can embed constants and constant pointers into the JIT
code, so you don't need to access them before use (eliminates several loads).
However, its trade-off is the extra memory space consumed by the jitted
code. On embedded systems, large amount of JIT-ed code might decrease the
efficiency of the instruction cache.
... can't do
miracles. JIT is a good thing if you know what you are doing.
My practical experiences
JIT is kind of a code inlining (static compiler optimization).
It basically has the same disadvantages as well.
focus on the most frequently executed part of your program.
(Profiling can help) Never translate complicated algorithms to
machine code. Do that in C/C++ level.
ARM 32 (ARM-v5, ARM-v7 and Thumb2 instruction sets)
MIPS 32 (III, R1)
MIPS 64 (III, R1)
The execution can be continued from any LIR instruction
In other words, jump into and out of the code is safe.
Target of (conditional) jump and call instructions can be
dynamically modified during the execution of the code.
Constants can be modified during the execution of the code.
Fast, non-ABI compilant function call (when a JIT code calls
anoher JIT code). Requires only a few machine instructions.
Move with update instructions. It means the base register is updated
before the actual load or store.
Limited number of registers (only 10, max 5 temporary and max 5 general)
Limited number of float registers (only 4 double registers)
More about the project
The source package contains a readme, which describes how to add sljit to
an existing project. The details about the sljit LIR (low-level intermediate
representation) is found in sljitLir.h, which is the only file, you need to
know to use sljit.
I have limited access to various software tools and hardware, which makes
testing difficult. You could help me by trying sljit with various compilers
(ARM RVCT) and various CPUs, especially mips and sparc.
Please join to the forums at sourceforge or send me private mail through
sourceforge. My account name is dark100.
|Last modification: 5.4.2014|