Page 1 of 1

JIT Compile asm in c backend

Posted: Fri Feb 07, 2025 4:28 am
by idle
I was thinking about how to JIT asm in the c backend and came up with this and cool it works windows x64 c backend

Windows x64 c backend.

Code: Select all



Procedure JIT(asm.s)    
  Protected oldProtection;
  Protected fn,*asm 
  Protected fasmpath.s = #PB_Compiler_Home + "Compilers" + #PS$ + "FAsm.exe" 
  Inputfile.s = GetTemporaryDirectory() + "PBJit.txt"  
  outputfile.s = GetTemporaryDirectory() + "PBJit.bin"  
  fn = CreateFile(-1,outputfile) 
  CloseFile(fn) 
  fn = CreateFile(-1,Inputfile) 
  If fn 
    *asm= UTF8(asm) 
    WriteData(fn,*asm,MemorySize(*asm)) 
    CloseFile(fn) 
    OpenConsole()  
    fasm =  RunProgram(fasmpath,Inputfile,"", #PB_Program_Open | #PB_Program_Read)
    If fasm 
      While ProgramRunning(fasm)
        If AvailableProgramOutput(fasm) 
          PrintN(ReadProgramString(fasm))
        EndIf 
      Wend    
    EndIf    
    FreeMemory(*asm) 
    
    If FileSize(outputfile) 
      fn = OpenFile(-1,outputfile)    
      len = Lof(fn) 
      *asm = AllocateMemory(Len)
      ReadData(fn,*asm,len)
      CloseFile(fn) 
      
      Protected *buffer = VirtualAlloc_(#Null, len, #MEM_COMMIT, #PAGE_READWRITE);
      CopyMemory(*asm,*buffer,len)
      FreeMemory(*asm) ;
      VirtualProtect_(*buffer, len, #PAGE_EXECUTE_READ, @oldProtection)          ;
      ProcedureReturn *buffer 
      
    EndIf 
  EndIf   
      
 EndProcedure 
   
 Prototype FastHash64(*Buffer, Len, Seed.q=0)
 Global *FastHash64.FastHash64
 
 Procedure JiTFastHash64()
         
   ; FastHash64 algorithm by Zilong Tan ported by wilbert
   Protected asm.s 
   asm + "use64 " + #LF$
   asm + "MOV    qword [rsp+8],rcx"+ #LF$
   asm + "MOV    qword [rsp+16],rdx"+ #LF$
   asm + "MOV    qword [rsp+24],r8"+ #LF$
   asm + "PS20=48"+ #LF$
   asm + "SUB    rsp,40"+ #LF$
   
   asm + "p.v_Seed equ rsp+PS20+16" + #LF$
   asm + "p.v_Len equ rsp+PS20+8"+ #LF$
   asm + "p.p_Buffer equ rsp+PS20+0"+ #LF$
      
   asm + "mov r10, 0x2127599bf4325c37" + #LF$ 
   asm + "mov r11, 0x880355f21e6d1965" + #LF$ 
   asm + "mov rdx, [p.p_Buffer]" + #LF$ 
   asm + "mov rcx, [p.v_Len]" + #LF$ 
   asm + "mov rax, rcx" + #LF$       ; h = seed ^ (len * m);
   asm + "imul rax, r11" + #LF$ 
   asm + "xor rax, [p.v_Seed]" + #LF$ 
   asm + "sub rcx, 8" + #LF$ 
   asm + "jc .l1" + #LF$ 
   ; 8 byte loop  
   asm + ".l0: " + #LF$ 
   asm + "mov r8, [rdx]" + #LF$         ; v = *pos++;
   asm + "add rdx, 8" + #LF$ 
   ; -- mix(v) start --
   asm + "mov r9, r8" + #LF$ 
   asm + "shr r9, 23" + #LF$ 
   asm + "xor r8, r9" + #LF$ 
   asm + "imul r8, r10" + #LF$ 
   asm + "mov r9, r8" + #LF$ 
   asm + "shr r9, 47" + #LF$ 
   asm + "xor r8, r9" + #LF$ 
   ; -- mix end --
   asm + "xor rax, r8" + #LF$           ; h ^= mix(v);
   asm + "imul rax, r11" + #LF$         ; h *= m;
   asm + "sub rcx, 8" + #LF$ 
   asm + "jnc .l0" + #LF$ 
   ; remaining bytes
   asm + ".l1: " + #LF$ 
   asm + "add rcx, 8" + #LF$ 
   asm + "jz .l5" + #LF$ 
   asm + "xor r8, r8" + #LF$ 
   asm + "test rcx, 4" + #LF$ 
   asm + "jz .l2" + #LF$ 
   ; get 4 bytes
   asm + "mov r8d, [rdx]" + #LF$ 
   asm + "add rdx, 4" + #LF$ 
   asm + "ror r8, 32" + #LF$ 
   asm + ".l2: " + #LF$ 
   asm + "test rcx, 2" + #LF$ 
   asm + "jz .l3" + #LF$ 
   ; get 2 bytes
   asm + "movzx r9d, word [rdx]" + #LF$ 
   asm + "add rdx, 2" + #LF$ 
   asm + "xor r8, r9" + #LF$ 
   asm + "ror r8, 16" + #LF$ 
   asm + ".l3: " + #LF$ 
   asm + "test rcx, 1" + #LF$ 
   asm + "jz .l4" + #LF$ 
   ; get 1 byte
   asm + "movzx r9d, byte [rdx]" + #LF$ 
   asm + "xor r8, r9" + #LF$ 
   asm + "ror r8, 8" + #LF$ 
   asm + ".l4: ";  + #LF$ 
   asm + "and rcx, 7" + #LF$ 
   asm + "shl rcx, 3" + #LF$ 
   asm + "rol r8, cl" + #LF$ 
   ; -- mix(v) start --
   asm + "mov r9, r8" + #LF$ 
   asm + "shr r9, 23" + #LF$ 
   asm + "xor r8, r9" + #LF$ 
   asm + "imul r8, r10" + #LF$ 
   asm + "mov r9, r8" + #LF$ 
   asm + "shr r9, 47" + #LF$ 
   asm + "xor r8, r9" + #LF$ 
   ; -- mix end --
   asm + "xor rax, r8" + #LF$           ; h ^= mix(v);
   asm + "imul rax, r11" + #LF$         ; h *= m;
   ; -- mix(h) start --
   asm + ".l5: " + #LF$ 
   asm + "mov r9, rax" + #LF$ 
   asm + "shr r9, 23" + #LF$ 
   asm + "xor rax, r9" + #LF$ 
   asm + "imul rax, r10" + #LF$ 
   asm + "mov r9, rax" + #LF$ 
   asm + "shr r9, 47" + #LF$ 
   asm + "xor rax, r9" + #LF$ 
   asm + "add rsp,40"+ #LF$ 
   asm + "ret" + #LF$  
   
   ProcedureReturn JIT(asm)   
   
 EndProcedure
 
  Procedure.q FastHash64C(*buf,len,Seed.q=0)
    Protected result.q  
    ;FastHash64 algorithm by Zilong Tan
    !typedef unsigned long long uint64_t; 
    
    !#define mix(h) ({				      	  \
    !			(h) ^= (h) >> 23;		          \
    !			(h) *= 0x2127599bf4325c37ULL;	\
    !			(h) ^= (h) >> 47; })
    !
    
    !	const uint64_t m = 0x880355f21e6d1965ULL;
    !	const uint64_t *pos = (const uint64_t *)p_buf;
    !	const uint64_t *end = pos + (v_len / 8);
    !	const unsigned char *pos2;
    !	uint64_t h = v_seed ^ (v_len * m);
    !	uint64_t v;
    ! uint64_t result; 
    
    !	while (pos != end) {
    !		v  = *pos++;
    !		h ^= mix(v);
    !		h *= m;
    !	}
    
    !	pos2 = (const unsigned char*)pos;
    !	v = 0;
    
    !	switch (v_len & 7) {
    !	case 7: v ^= (uint64_t)pos2[6] << 48;
    !	case 6: v ^= (uint64_t)pos2[5] << 40;
    !	case 5: v ^= (uint64_t)pos2[4] << 32;
    !	case 4: v ^= (uint64_t)pos2[3] << 24;
    !	case 3: v ^= (uint64_t)pos2[2] << 16;
    !	case 2: v ^= (uint64_t)pos2[1] << 8;
    !	case 1: v ^= (uint64_t)pos2[0];
    !		h ^= mix(v);
    !		h *= m;
    !	}
    !
    !	v_result = mix(h);
    
    ProcedureReturn result 
  EndProcedure  
 
 Global str.s = "Hello JIT function" 
 
 *FastHash64 = JiTFastHash64()
 If *FastHash64 
   Debug *FastHash64(@str,StringByteLength(str)) 
 EndIf 
 
 Debug FastHash64C(@str,StringByteLength(str)) 
 





While this isn't really particularly useful as it is, it wouldn't be to hard to turn it into a compiler tool to embed the binary into a datasection and execute it from the virtualmemory and the same mechanism can be used on linux.
https://burnttoys.blogspot.com/2011/04/ ... ry-on.html

Re: JIT Compile asm in c backend

Posted: Fri Feb 07, 2025 9:16 am
by Skipper
Idle, I really like how you think outside the box. Creative idea, great code to study! :D

Re: JIT Compile asm in c backend

Posted: Fri Feb 07, 2025 11:02 pm
by idle
Skipper wrote: Fri Feb 07, 2025 9:16 am Idle, I really like how you think outside the box. Creative idea, great code to study! :D
turning it into a compiler tool that runs when you compile
parse the source strip into c and asm procedures
call pbcompiler with /ASM flag
extract the generates asm from the assembly, merge any used libs in main source
compile procedure with fasm
emit the binary to datasection in the main source
emit the function prototype and loader
and then compile the result with pbcompilerC

It would take a couple of days to do I expect and scratch an itch. as long as the ASM is in a procedure it would be ok

Re: JIT Compile asm in c backend

Posted: Sun Feb 09, 2025 3:11 pm
by wilbert
idle wrote: Fri Feb 07, 2025 4:28 am I was thinking about how to JIT asm in the c backend and came up with this and cool it works windows x64 c backend
That's nice :D
I was surprised I didn't get a warning about executing something from memory when I tried your code. :shock:

Re: JIT Compile asm in c backend

Posted: Sun Feb 09, 2025 5:02 pm
by skywalk
Whoa! Is this a path to edit and continue within PB IDE?
Hot code reload 8)

Re: JIT Compile asm in c backend

Posted: Sun Feb 09, 2025 7:33 pm
by idle
skywalk wrote: Sun Feb 09, 2025 5:02 pm Whoa! Is this a path to edit and continue within PB IDE?
Hot code reload 8)
I actually want it for my database engine and yes it opens up interesting options.

Re: JIT Compile asm in c backend

Posted: Sun Feb 09, 2025 7:44 pm
by idle
wilbert wrote: Sun Feb 09, 2025 3:11 pm
idle wrote: Fri Feb 07, 2025 4:28 am I was thinking about how to JIT asm in the c backend and came up with this and cool it works windows x64 c backend
That's nice :D
I was surprised I didn't get a warning about executing something from memory when I tried your code. :shock:
It would probably increase av alerts but it's totally valid, it's how jits work.

Re: JIT Compile asm in c backend

Posted: Mon Feb 10, 2025 8:50 pm
by idle
skywalk wrote: Sun Feb 09, 2025 5:02 pm Whoa! Is this a path to edit and continue within PB IDE?
Hot code reload 8)
Hot reload would be a very cool feature when a bug is encountered the debugger halts with error, you correct and hit continue and it reruns the procedure, I could have used that the other day where I was getting a bug 3/4 the way of processing files and it was taking an eternity to run with the debugger.

Re: JIT Compile asm in c backend

Posted: Tue Feb 11, 2025 12:55 am
by skywalk
Hate to say it, but I used that feature debugging large VB6 apps. Changing a simple state variable, modify logic of an if..endif, and not having to stop and recompile was a big time saver.

Re: JIT Compile asm in c backend

Posted: Tue Feb 11, 2025 3:43 am
by idle
skywalk wrote: Tue Feb 11, 2025 12:55 am Hate to say it, but I used that feature debugging large VB6 apps. Changing a simple state variable, modify logic of an if..endif, and not having to stop and recompile was a big time saver.
I'd forgotten that.