Przeglądaj źródła

FFI: Add callback support for ARM.

Mike Pall 14 lat temu
rodzic
commit
03c51fc578
5 zmienionych plików z 258 dodań i 167 usunięć
  1. 56 4
      src/buildvm_arm.dasc
  2. 165 158
      src/buildvm_arm.h
  3. 35 1
      src/lj_ccallback.c
  4. 0 4
      src/lj_errmsg.h
  5. 2 0
      src/lj_target_arm.h

+ 56 - 4
src/buildvm_arm.dasc

@@ -502,22 +502,30 @@ static void build_subroutines(BuildCtx *ctx)
   |    ldr CARG1, [BASE, #-16]		// Get continuation.
   |   mov CARG4, BASE
   |   mov BASE, RB			// Restore caller BASE.
-  |    cmp CARG1, #0
+#if LJ_HASFFI
+  |    cmp CARG1, #1
+#endif
   |   ldr PC, [CARG4, #-12]		// Restore PC from [cont|PC].
-  |    beq >1
   |  ldr CARG3, LFUNC:CARG3->field_pc
   |    mvn INS, #~LJ_TNIL
   |    add CARG2, RA, RC
   |    str INS, [CARG2, #-4]		// Ensure one valid arg.
+#if LJ_HASFFI
+  |    bls >1
+#endif
   |  ldr KBASE, [CARG3, #PC2PROTO(k)]
   |  // BASE = base, RA = resultptr, CARG4 = meta base
-  |   bx CARG1
+  |    bx CARG1
   |
-  |1:  // Tail call from C function.
+#if LJ_HASFFI
+  |1:
+  |  beq ->cont_ffi_callback		// cont = 1: return from FFI callback.
+  |  // cont = 0: tailcall from C function.
   |  ldr CARG3, [BASE, FRAME_FUNC]
   |   sub CARG4, CARG4, #16
   |   sub RC, CARG4, BASE
   |  b ->vm_call_tail
+#endif
   |
   |->cont_cat:				// RA = resultptr, CARG4 = meta base
   |  ldr INS, [PC, #-4]
@@ -2177,6 +2185,50 @@ static void build_subroutines(BuildCtx *ctx)
   |//-----------------------------------------------------------------------
   |//-- FFI helper functions -----------------------------------------------
   |//-----------------------------------------------------------------------
+  |
+  |// Handler for callback functions.
+  |// Saveregs already performed. Callback slot number in [sp], g in r12.
+  |->vm_ffi_callback:
+#if LJ_HASFFI
+  |.type CTSTATE, CTState, PC
+  |  ldr CTSTATE, GL:r12->ctype_state
+  |   add DISPATCH, r12, #GG_G2DISP
+  |  strd CARG12, CTSTATE->cb.gpr[0]
+  |  strd CARG34, CTSTATE->cb.gpr[2]
+  |  ldr CARG4, [sp]
+  |   add CARG3, sp, #CFRAME_SIZE
+  |    mov CARG1, CTSTATE
+  |  lsr CARG4, CARG4, #3
+  |   str CARG3, CTSTATE->cb.stack
+  |    mov CARG2, sp
+  |  str CARG4, CTSTATE->cb.slot
+  |  str CTSTATE, SAVE_PC		// Any value outside of bytecode is ok.
+  |  bl extern lj_ccallback_enter	// (CTState *cts, void *cf)
+  |  // Returns lua_State *.
+  |  ldr BASE, L:CRET1->base
+  |    mv_vmstate CARG2, INTERP
+  |  ldr RC, L:CRET1->top
+  |    mov MASKR8, #255
+  |   ldr LFUNC:CARG3, [BASE, FRAME_FUNC]
+  |    mov L, CRET1
+  |  sub RC, RC, BASE
+  |    lsl MASKR8, MASKR8, #3		// MASKR8 = 255*8.
+  |    st_vmstate CARG2
+  |  ins_callt
+#endif
+  |
+  |->cont_ffi_callback:                 // Return from FFI callback.
+#if LJ_HASFFI
+  |  ldr CTSTATE, [DISPATCH, #DISPATCH_GL(ctype_state)]
+  |   str BASE, L->base
+  |   str CARG4, L->top
+  |  str L, CTSTATE->L
+  |  mov CARG1, CTSTATE
+  |  mov CARG2, RA
+  |  bl extern lj_ccallback_leave	// (CTState *cts, TValue *o)
+  |  ldrd CARG12, CTSTATE->cb.gpr[0]
+  |  b ->vm_leave_unw
+#endif
   |
   |->vm_ffi_call:			// Call C function via FFI.
   |  // Caveat: needs special frame unwinding, see below.

Plik diff jest za duży
+ 165 - 158
src/buildvm_arm.h


+ 35 - 1
src/lj_ccallback.c

@@ -43,6 +43,13 @@ static MSize CALLBACK_OFS2SLOT(MSize ofs)
 #define CALLBACK_MAX_SLOT \
   (((CALLBACK_MCODE_SIZE-CALLBACK_MCODE_HEAD)/(CALLBACK_MCODE_GROUP+4*32))*32)
 
+#elif LJ_TARGET_ARM
+
+#define CALLBACK_MCODE_HEAD		32
+#define CALLBACK_SLOT2OFS(slot)		(CALLBACK_MCODE_HEAD + 8*(slot))
+#define CALLBACK_OFS2SLOT(ofs)		(((ofs)-CALLBACK_MCODE_HEAD)/8)
+#define CALLBACK_MAX_SLOT		(CALLBACK_OFS2SLOT(CALLBACK_MCODE_SIZE))
+
 #elif LJ_TARGET_PPC
 
 #define CALLBACK_MCODE_HEAD		24
@@ -110,6 +117,28 @@ static void callback_mcode_init(global_State *g, uint8_t *page)
   }
   lua_assert(p - page <= CALLBACK_MCODE_SIZE);
 }
+#elif LJ_TARGET_ARM
+static void callback_mcode_init(global_State *g, uint32_t *page)
+{
+  uint32_t *p = page;
+  void *target = (void *)lj_vm_ffi_callback;
+  MSize slot;
+  /* This must match with the saveregs macro in buildvm_arm.dasc. */
+  *p++ = ARMI_SUB|ARMF_D(RID_R12)|ARMF_N(RID_R12)|ARMF_M(RID_PC);
+  *p++ = ARMI_PUSH|ARMF_N(RID_SP)|RSET_RANGE(RID_R4,RID_R11+1)|RID2RSET(RID_LR);
+  *p++ = ARMI_SUB|ARMI_K12|ARMF_D(RID_R12)|ARMF_N(RID_R12)|CALLBACK_MCODE_HEAD;
+  *p++ = ARMI_STR|ARMI_LS_P|ARMI_LS_W|ARMF_D(RID_R12)|ARMF_N(RID_SP)|(CFRAME_SIZE-4*9);
+  *p++ = ARMI_LDR|ARMI_LS_P|ARMI_LS_U|ARMF_D(RID_R12)|ARMF_N(RID_PC);
+  *p++ = ARMI_LDR|ARMI_LS_P|ARMI_LS_U|ARMF_D(RID_PC)|ARMF_N(RID_PC);
+  *p++ = u32ptr(g);
+  *p++ = u32ptr(target);
+  for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
+    *p++ = ARMI_MOV|ARMF_D(RID_R12)|ARMF_M(RID_PC);
+    *p = ARMI_B | ((page-p-2) & 0x00ffffffu);
+    p++;
+  }
+  lua_assert(p - page <= CALLBACK_MCODE_SIZE);
+}
 #elif LJ_TARGET_PPC
 static void callback_mcode_init(global_State *g, uint32_t *page)
 {
@@ -245,7 +274,12 @@ void lj_ccallback_mcode_free(CTState *cts)
 #elif LJ_TARGET_ARM
 
 #define CALLBACK_HANDLE_REGARG \
-  UNUSED(ngpr); UNUSED(maxgpr); goto done;  /* NYI */
+  if (n > 1) ngpr = (ngpr + 1u) & ~1u;  /* Align to regpair. */ \
+  if (ngpr + n <= maxgpr) { \
+    sp = &cts->cb.gpr[ngpr]; \
+    ngpr += n; \
+    goto done; \
+  }
 
 #elif LJ_TARGET_PPC
 

+ 0 - 4
src/lj_errmsg.h

@@ -161,11 +161,7 @@ ERRDEF(FFI_BADIDX,	LUA_QS " cannot be indexed")
 ERRDEF(FFI_WRCONST,	"attempt to write to constant location")
 ERRDEF(FFI_NODECL,	"missing declaration for symbol " LUA_QS)
 ERRDEF(FFI_BADCBACK,	"bad callback")
-#if LJ_TARGET_X86ORX64 || LJ_TARGET_PPC
 ERRDEF(FFI_CBACKOV,	"too many callbacks")
-#else
-ERRDEF(FFI_CBACKOV,	"no support for callbacks (yet)")
-#endif
 ERRDEF(FFI_NYIPACKBIT,	"NYI: packed bit fields")
 ERRDEF(FFI_NYICALL,	"NYI: cannot call this C function (yet)")
 #endif

+ 2 - 0
src/lj_target_arm.h

@@ -139,6 +139,7 @@ typedef enum ARMIns {
   ARMI_S = 0x000100000,
   ARMI_K12 = 0x02000000,
   ARMI_KNEG = 0x00200000,
+  ARMI_LS_W = 0x00200000,
   ARMI_LS_U = 0x00800000,
   ARMI_LS_P = 0x01000000,
   ARMI_LS_R = 0x02000000,
@@ -176,6 +177,7 @@ typedef enum ARMIns {
   ARMI_STRB = 0xe4400000,
   ARMI_STRH = 0xe00000b0,
   ARMI_STRD = 0xe00000f0,
+  ARMI_PUSH = 0xe92d0000,
 
   ARMI_B = 0xea000000,
   ARMI_BL = 0xeb000000,

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików