DAsmJit, pronounced as "The Awesome JIT", is a x86 assembler for Delphi and FPC. It's a port from the asmjit project.
DAsmJit takes x86 assembly and then generates the machine code for it. This will enable you to compile functions at runtime and use them as if they're native Delphi functions. This way you can create optimized functions for specific CPU's (MMX, SSE, SSE2 support etc.). For more information I would like to forward you to the original project.
I decided to port a jit project to Delphi, because I couldn't find one. I've chosen for asmjit, because it was the smallest library I could find. Unfortunately, the author is working on a revamped version (version 1.0) of the library which comes with a lot of changes and I don't know if I'll update this project accordingly.. However, the current version is stable and does what it is supposed to
Here's an example on how to use the Assembler class:
pascal Code:procedure TForm1.dbg(s: string);
begin
Memo1.Lines.Text := Memo1.Lines.Text + s;
end;
procedure TForm1.Button1Click(Sender: TObject);
type
IncProc = function(i: Integer): Integer;
var
a: TAssembler;
b: IncProc;
p: Pointer;
begin
a := TAssembler.Create;
a.Logger := TCallBackLogger.Create(@dbg);
//a.inc_(nax);
a.push(nbx);
a.mov(nbx, imm(5));
a.imul(nbx);
a.sub(nax, imm(50));
a.pop(nbx);
a.ret;
p := a.Make;
b := IncProc(p);
ShowMessage(IntToStr(b(5)));
TMemoryManager.Global.FreeAddress(p);
a.Logger.Free;
a.Free;
end;
And how to use the compiler class:
pascal Code:procedure TForm1.Button8Click(Sender: TObject);
type
MyFn = procedure(a, b: Integer; c: PBoolean);
const
args: array[0..2] of UInt32 = (VARIABLE_TYPE_SYSINT, VARIABLE_TYPE_SYSINT, VARIABLE_TYPE_PTR);
var
c: TCompiler;
f: TFunction;
src0, src1, dst0: TPtrRef;
p: Pointer;
b: MyFn;
x: Boolean;
begin
c := TCompiler.Create;
c.Logger := TCallBackLogger.Create(@dbg);
f := c.NewFunction_(CALL_CONV_BORLANDFASTCALL, @args, 3);
src0.Create(f.Argument(0));
src1.Create(f.Argument(1));
dst0.Create(f.Argument(2));
c.cmp(src0.c, src1.c);
c.setz(byte_ptr(dst0.c));
c.EndFunction;
p := c.Make;
b := MyFn(p);
b(1, 1, @x);
ShowMessage('1, 1 = ' + IntToStr(Integer(x)));
TMemoryManager.Global.FreeAddress(p);
c.Logger.Free;
c.Free;
end;
The compiler class handles things like calling convention, function prolog/epilog and variables. This way it's easier to create portable code.
I've also ported the example project MathPresso the author wrote. It is a simple mathematical expression evaluator that compiles the expression into SSE code. It's pretty fast (most of the time it's faster than compiled Delphi code). Unfortunately, because there are only 8 SSE registers there is a limit to the difficulty of the expression.
In the future I'd like to write my own expression evaluator with it and I want it to produce code equal to Delphi or even better (SSE/MMX optimizations). Maybe I will also try to keep this up to date with the c++ version, if version 1.0 turns out to be a great improvement.
It should compile on both Delphi and Lazarus. I haven't tried it with 64 bit nor Linux. 64 bit should work, but for Linux I need to know the correct FPC equivalents to the c++ code.
~Nielsie95