LCOV - code coverage report
Current view: top level - flamenco/vm/jit - fd_jit.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 9 88 10.2 %
Date: 2024-11-13 11:58:15 Functions: 2 9 22.2 %

          Line data    Source code
       1             : #include "fd_jit_private.h"
       2             : #include <math.h>
       3             : 
       4             : FD_TL fd_vm_t *                  fd_jit_vm;        /* current VM being executed */
       5             : FD_TL fd_sbpf_syscalls_t const * fd_jit_syscalls;  /* current syscall table */
       6             : 
       7             : FD_TL uint  fd_jit_segment_cnt;
       8             : FD_TL uint  fd_jit_mem_sz   [ 2*FD_VM_JIT_SEGMENT_MAX ];
       9             : FD_TL ulong fd_jit_mem_haddr[   FD_VM_JIT_SEGMENT_MAX ];
      10             : FD_TL ulong fd_jit_jmp_buf[8];
      11             : FD_TL ulong fd_jit_segfault_vaddr;
      12             : FD_TL ulong fd_jit_segfault_rip;
      13             : 
      14             : FD_TL jmp_buf fd_jit_compile_abort;
      15             : 
      16             : FD_TL void * fd_jit_code_section_base;
      17             : FD_TL ulong  fd_jit_code_section_sz;
      18             : 
      19             : ulong
      20           6 : fd_jit_est_code_sz( ulong bpf_sz ) {
      21           6 :   if( FD_UNLIKELY( bpf_sz > (1UL<<24) ) ) return 0UL; /* float32 representation limit */
      22           6 :   return FD_JIT_BLOAT_BASE + (ulong)ceilf( (float)bpf_sz * FD_JIT_BLOAT_MAX );
      23           6 : }
      24             : 
      25             : ulong
      26           3 : fd_jit_est_scratch_sz( ulong bpf_sz ) {
      27           3 :   fd_jit_scratch_layout_t layout[1];
      28           3 :   if( FD_UNLIKELY( !fd_jit_scratch_layout( layout, bpf_sz ) ) ) return 0UL;
      29           3 :   return layout->sz;
      30           3 : }
      31             : 
      32             : fd_jit_prog_t *
      33             : fd_jit_prog_new( fd_jit_prog_t *            jit_prog,
      34             :                  fd_sbpf_program_t const *  prog,
      35             :                  fd_sbpf_syscalls_t const * syscalls,
      36             :                  void *                     code_buf,
      37             :                  ulong                      code_bufsz,
      38             :                  void *                     scratch,
      39             :                  ulong                      scratch_sz,
      40           0 :                  int *                      out_err ) {
      41             : 
      42           0 :   memset( jit_prog, 0, sizeof(fd_jit_prog_t) );
      43           0 :   *out_err = FD_VM_ERR_INVAL;
      44             : 
      45           0 :   if( FD_UNLIKELY( setjmp( fd_jit_compile_abort ) ) ) {
      46             :     /* DASM_M_GROW longjmp() here in case of alloc failure */
      47           0 :     *out_err = FD_VM_ERR_FULL;
      48           0 :     return NULL;
      49           0 :   }
      50           0 :   fd_jit_code_section_base = (void *)1; /* an invalid non-NULL pointer */
      51           0 :   fd_jit_code_section_sz   = 0UL;
      52             : 
      53           0 :   uint  text_cnt = (uint)prog->text_cnt;
      54           0 :   ulong bpf_sz   = text_cnt * 8UL;
      55             : 
      56             :   /* Prepare custom scratch allocator for DynASM.
      57             :      Constructors provided by dasm_x86.h heavily rely on realloc() like
      58             :      semantics.  The code below replaces these with pre-allocated
      59             :      regions out of code_buf and uses the redefined DASM_M_GROW to
      60             :      detect out-of-memory conditions. */
      61             : 
      62           0 :   fd_jit_scratch_layout_t layout[1];
      63           0 :   if( FD_UNLIKELY( !fd_jit_scratch_layout( layout, bpf_sz ) ) ) {
      64           0 :     *out_err = FD_VM_ERR_FULL;
      65           0 :     return NULL;
      66           0 :   }
      67           0 :   if( FD_UNLIKELY( layout->sz > scratch_sz ) ) {
      68           0 :     *out_err = FD_VM_ERR_FULL;
      69           0 :     return NULL;
      70           0 :   }
      71             : 
      72           0 :   dasm_State * d = fd_jit_prepare( scratch, layout );
      73             : 
      74           0 :   fd_jit_compile( &d, prog, syscalls );
      75             :   /* above longjmp()'s to fd_jit_compile_abort on failure */
      76             : 
      77           0 :   ulong code_sz;
      78           0 :   dasm_link( &d, &code_sz );
      79           0 :   if( FD_UNLIKELY( code_sz > code_bufsz ) ) {
      80           0 :     *out_err = FD_VM_ERR_FULL;
      81           0 :     return NULL;
      82           0 :   }
      83             : 
      84           0 :   dasm_encode( &d, code_buf );
      85           0 :   jit_prog->entrypoint = fd_jit_get_entrypoint();
      86           0 :   jit_prog->first_rip  = (ulong)code_buf + (ulong)dasm_getpclabel( &d, (uint)prog->entry_pc );
      87           0 :   jit_prog->code_buf   = code_buf;
      88           0 :   jit_prog->code_sz    = code_sz;
      89             : 
      90             :   /* Would ordinarily call dasm_free here, but no need, since all
      91             :      memory was allocated in scratch and is released on function return.  */
      92             :   //dasm_free( &d );
      93             : 
      94           0 :   *out_err = FD_VM_SUCCESS;
      95           0 :   return jit_prog;
      96           0 : }
      97             : 
      98             : void *
      99           0 : fd_jit_prog_delete( fd_jit_prog_t * prog ) {
     100           0 :   (void)prog;
     101           0 :   return NULL;
     102           0 : }
     103             : 
     104             : int
     105           0 : fd_jit_vm_attach( fd_vm_t * vm ) {
     106           0 :   fd_jit_vm       = vm;
     107           0 :   fd_jit_syscalls = vm->syscalls;
     108             : 
     109             :   /* ABIv1 has 6 segments only */
     110           0 :   fd_jit_segment_cnt = 6UL;
     111           0 :   for( ulong j=0UL; j<fd_jit_segment_cnt; j++ ) {
     112           0 :     fd_jit_mem_haddr[ j     ] = vm->region_haddr[ j ];
     113           0 :     fd_jit_mem_sz   [ j*2   ] = vm->region_st_sz[ j ];
     114           0 :     fd_jit_mem_sz   [ j*2+1 ] = vm->region_ld_sz[ j ];
     115           0 :   }
     116             : 
     117           0 :   fd_jit_segfault_vaddr = 0UL;
     118           0 :   fd_jit_segfault_rip   = 0UL;
     119             : 
     120           0 :   return FD_VM_SUCCESS;
     121           0 : }
     122             : 
     123             : void
     124           0 : fd_jit_vm_detach( void ) {
     125           0 :   fd_jit_segment_cnt    = 0U;
     126           0 :   fd_jit_segfault_vaddr = 0UL;
     127           0 :   fd_jit_segfault_rip   = 0UL;
     128           0 : }
     129             : 
     130             : FD_FN_PURE int
     131           0 : fd_jit_vm_compatible( fd_vm_t const * vm ) {
     132           0 :   if( vm->input_mem_regions_cnt != 1             ) return FD_VM_ERR_UNSUP;
     133           0 :   if( vm->input_mem_regions[0].vaddr_offset != 0 ) return FD_VM_ERR_UNSUP;
     134           0 :   return FD_VM_SUCCESS;
     135           0 : }
     136             : 
     137             : int
     138             : fd_jit_exec( fd_jit_prog_t * jit_prog,
     139           0 :              fd_vm_t *       vm ) {
     140           0 :   int err = fd_jit_vm_compatible( vm );
     141           0 :   if( FD_UNLIKELY( err!=FD_VM_SUCCESS ) ) return err;
     142           0 :   fd_jit_vm_attach( vm );
     143           0 :   err = jit_prog->entrypoint( jit_prog->first_rip );
     144           0 :   fd_jit_vm_detach();
     145           0 :   return err;
     146           0 : }
     147             : 
     148             : /* fd_dasm_grow_check gets called when DynASM tries to grow a buffer
     149             :    using realloc().  We stubbed out realloc(), so we just check if the
     150             :    requested buffer is sufficiently large.  If it's not, we abort via
     151             :    longjmp(). */
     152             : 
     153             : void
     154             : fd_dasm_grow_check( void * ptr,
     155           0 :                     ulong  min_sz ) {
     156           0 :   if( FD_UNLIKELY( ptr!=fd_jit_code_section_base ) ) goto fail;
     157           0 :   if( FD_UNLIKELY( min_sz>fd_jit_code_section_sz ) ) goto fail;
     158           0 :   return;
     159           0 : fail:
     160           0 :   FD_LOG_WARNING(( "Aborting JIT compile" ));
     161           0 :   longjmp( fd_jit_compile_abort, 1 );
     162           0 : }

Generated by: LCOV version 1.14