src/lj_ccallback.c - luajit-2.0-src

Functions defined

Macros defined

Source code

  1. /*
  2. ** FFI C callback handling.
  3. ** Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h
  4. */

  5. #include "lj_obj.h"

  6. #if LJ_HASFFI

  7. #include "lj_gc.h"
  8. #include "lj_err.h"
  9. #include "lj_tab.h"
  10. #include "lj_state.h"
  11. #include "lj_frame.h"
  12. #include "lj_ctype.h"
  13. #include "lj_cconv.h"
  14. #include "lj_ccall.h"
  15. #include "lj_ccallback.h"
  16. #include "lj_target.h"
  17. #include "lj_mcode.h"
  18. #include "lj_trace.h"
  19. #include "lj_vm.h"

  20. /* -- Target-specific handling of callback slots -------------------------- */

  21. #define CALLBACK_MCODE_SIZE        (LJ_PAGESIZE * LJ_NUM_CBPAGE)

  22. #if LJ_OS_NOJIT

  23. /* Callbacks disabled. */
  24. #define CALLBACK_SLOT2OFS(slot)        (0*(slot))
  25. #define CALLBACK_OFS2SLOT(ofs)        (0*(ofs))
  26. #define CALLBACK_MAX_SLOT        0

  27. #elif LJ_TARGET_X86ORX64

  28. #define CALLBACK_MCODE_HEAD        (LJ_64 ? 8 : 0)
  29. #define CALLBACK_MCODE_GROUP        (-2+1+2+5+(LJ_64 ? 6 : 5))

  30. #define CALLBACK_SLOT2OFS(slot) \
  31.   (CALLBACK_MCODE_HEAD + CALLBACK_MCODE_GROUP*((slot)/32) + 4*(slot))

  32. static MSize CALLBACK_OFS2SLOT(MSize ofs)
  33. {
  34.   MSize group;
  35.   ofs -= CALLBACK_MCODE_HEAD;
  36.   group = ofs / (32*4 + CALLBACK_MCODE_GROUP);
  37.   return (ofs % (32*4 + CALLBACK_MCODE_GROUP))/4 + group*32;
  38. }

  39. #define CALLBACK_MAX_SLOT \
  40.   (((CALLBACK_MCODE_SIZE-CALLBACK_MCODE_HEAD)/(CALLBACK_MCODE_GROUP+4*32))*32)

  41. #elif LJ_TARGET_ARM

  42. #define CALLBACK_MCODE_HEAD                32

  43. #elif LJ_TARGET_ARM64

  44. #define CALLBACK_MCODE_HEAD                32

  45. #elif LJ_TARGET_PPC

  46. #define CALLBACK_MCODE_HEAD                24

  47. #elif LJ_TARGET_MIPS

  48. #define CALLBACK_MCODE_HEAD                24

  49. #else

  50. /* Missing support for this architecture. */
  51. #define CALLBACK_SLOT2OFS(slot)        (0*(slot))
  52. #define CALLBACK_OFS2SLOT(ofs)        (0*(ofs))
  53. #define CALLBACK_MAX_SLOT        0

  54. #endif

  55. #ifndef CALLBACK_SLOT2OFS
  56. #define CALLBACK_SLOT2OFS(slot)                (CALLBACK_MCODE_HEAD + 8*(slot))
  57. #define CALLBACK_OFS2SLOT(ofs)                (((ofs)-CALLBACK_MCODE_HEAD)/8)
  58. #define CALLBACK_MAX_SLOT                (CALLBACK_OFS2SLOT(CALLBACK_MCODE_SIZE))
  59. #endif

  60. /* Convert callback slot number to callback function pointer. */
  61. static void *callback_slot2ptr(CTState *cts, MSize slot)
  62. {
  63.   return (uint8_t *)cts->cb.mcode + CALLBACK_SLOT2OFS(slot);
  64. }

  65. /* Convert callback function pointer to slot number. */
  66. MSize lj_ccallback_ptr2slot(CTState *cts, void *p)
  67. {
  68.   uintptr_t ofs = (uintptr_t)((uint8_t *)p -(uint8_t *)cts->cb.mcode);
  69.   if (ofs < CALLBACK_MCODE_SIZE) {
  70.     MSize slot = CALLBACK_OFS2SLOT((MSize)ofs);
  71.     if (CALLBACK_SLOT2OFS(slot) == (MSize)ofs)
  72.       return slot;
  73.   }
  74.   return ~0u/* Not a known callback function pointer. */
  75. }

  76. /* Initialize machine code for callback function pointers. */
  77. #if LJ_OS_NOJIT
  78. /* Disabled callback support. */
  79. #define callback_mcode_init(g, p)        UNUSED(p)
  80. #elif LJ_TARGET_X86ORX64
  81. static void callback_mcode_init(global_State *g, uint8_t *page)
  82. {
  83.   uint8_t *p = page;
  84.   uint8_t *target = (uint8_t *)(void *)lj_vm_ffi_callback;
  85.   MSize slot;
  86. #if LJ_64
  87.   *(void **)p = target; p += 8;
  88. #endif
  89.   for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
  90.     /* mov al, slot; jmp group */
  91.     *p++ = XI_MOVrib | RID_EAX; *p++ = (uint8_t)slot;
  92.     if ((slot & 31) == 31 || slot == CALLBACK_MAX_SLOT-1) {
  93.       /* push ebp/rbp; mov ah, slot>>8; mov ebp, &g. */
  94.       *p++ = XI_PUSH + RID_EBP;
  95.       *p++ = XI_MOVrib | (RID_EAX+4); *p++ = (uint8_t)(slot >> 8);
  96.       *p++ = XI_MOVri | RID_EBP;
  97.       *(int32_t *)p = i32ptr(g); p += 4;
  98. #if LJ_64
  99.       /* jmp [rip-pageofs] where lj_vm_ffi_callback is stored. */
  100.       *p++ = XI_GROUP5; *p++ = XM_OFS0 + (XOg_JMP<<3) + RID_EBP;
  101.       *(int32_t *)p = (int32_t)(page-(p+4)); p += 4;
  102. #else
  103.       /* jmp lj_vm_ffi_callback. */
  104.       *p++ = XI_JMP; *(int32_t *)p = target-(p+4); p += 4;
  105. #endif
  106.     } else {
  107.       *p++ = XI_JMPs; *p++ = (uint8_t)((2+2)*(31-(slot&31)) - 2);
  108.     }
  109.   }
  110.   lua_assert(p - page <= CALLBACK_MCODE_SIZE);
  111. }
  112. #elif LJ_TARGET_ARM
  113. static void callback_mcode_init(global_State *g, uint32_t *page)
  114. {
  115.   uint32_t *p = page;
  116.   void *target = (void *)lj_vm_ffi_callback;
  117.   MSize slot;
  118.   /* This must match with the saveregs macro in buildvm_arm.dasc. */
  119.   *p++ = ARMI_SUB|ARMF_D(RID_R12)|ARMF_N(RID_R12)|ARMF_M(RID_PC);
  120.   *p++ = ARMI_PUSH|ARMF_N(RID_SP)|RSET_RANGE(RID_R4,RID_R11+1)|RID2RSET(RID_LR);
  121.   *p++ = ARMI_SUB|ARMI_K12|ARMF_D(RID_R12)|ARMF_N(RID_R12)|CALLBACK_MCODE_HEAD;
  122.   *p++ = ARMI_STR|ARMI_LS_P|ARMI_LS_W|ARMF_D(RID_R12)|ARMF_N(RID_SP)|(CFRAME_SIZE-4*9);
  123.   *p++ = ARMI_LDR|ARMI_LS_P|ARMI_LS_U|ARMF_D(RID_R12)|ARMF_N(RID_PC);
  124.   *p++ = ARMI_LDR|ARMI_LS_P|ARMI_LS_U|ARMF_D(RID_PC)|ARMF_N(RID_PC);
  125.   *p++ = u32ptr(g);
  126.   *p++ = u32ptr(target);
  127.   for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
  128.     *p++ = ARMI_MOV|ARMF_D(RID_R12)|ARMF_M(RID_PC);
  129.     *p = ARMI_B | ((page-p-2) & 0x00ffffffu);
  130.     p++;
  131.   }
  132.   lua_assert(p - page <= CALLBACK_MCODE_SIZE);
  133. }
  134. #elif LJ_TARGET_ARM64
  135. static void callback_mcode_init(global_State *g, uint32_t *page)
  136. {
  137.   uint32_t *p = page;
  138.   void *target = (void *)lj_vm_ffi_callback;
  139.   MSize slot;
  140.   *p++ = A64I_LDRLx | A64F_D(RID_X11) | A64F_S19(4);
  141.   *p++ = A64I_LDRLx | A64F_D(RID_X10) | A64F_S19(5);
  142.   *p++ = A64I_BR | A64F_N(RID_X11);
  143.   *p++ = A64I_NOP;
  144.   ((void **)p)[0] = target;
  145.   ((void **)p)[1] = g;
  146.   p += 4;
  147.   for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
  148.     *p++ = A64I_MOVZw | A64F_D(RID_X9) | A64F_U16(slot);
  149.     *p = A64I_B | A64F_S26((page-p) & 0x03ffffffu);
  150.     p++;
  151.   }
  152.   lua_assert(p - page <= CALLBACK_MCODE_SIZE);
  153. }
  154. #elif LJ_TARGET_PPC
  155. static void callback_mcode_init(global_State *g, uint32_t *page)
  156. {
  157.   uint32_t *p = page;
  158.   void *target = (void *)lj_vm_ffi_callback;
  159.   MSize slot;
  160.   *p++ = PPCI_LIS | PPCF_T(RID_TMP) | (u32ptr(target) >> 16);
  161.   *p++ = PPCI_LIS | PPCF_T(RID_R12) | (u32ptr(g) >> 16);
  162.   *p++ = PPCI_ORI | PPCF_A(RID_TMP)|PPCF_T(RID_TMP) | (u32ptr(target) & 0xffff);
  163.   *p++ = PPCI_ORI | PPCF_A(RID_R12)|PPCF_T(RID_R12) | (u32ptr(g) & 0xffff);
  164.   *p++ = PPCI_MTCTR | PPCF_T(RID_TMP);
  165.   *p++ = PPCI_BCTR;
  166.   for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
  167.     *p++ = PPCI_LI | PPCF_T(RID_R11) | slot;
  168.     *p = PPCI_B | (((page-p) & 0x00ffffffu) << 2);
  169.     p++;
  170.   }
  171.   lua_assert(p - page <= CALLBACK_MCODE_SIZE);
  172. }
  173. #elif LJ_TARGET_MIPS
  174. static void callback_mcode_init(global_State *g, uint32_t *page)
  175. {
  176.   uint32_t *p = page;
  177.   void *target = (void *)lj_vm_ffi_callback;
  178.   MSize slot;
  179.   *p++ = MIPSI_SW | MIPSF_T(RID_R1)|MIPSF_S(RID_SP) | 0;
  180.   *p++ = MIPSI_LUI | MIPSF_T(RID_R3) | (u32ptr(target) >> 16);
  181.   *p++ = MIPSI_LUI | MIPSF_T(RID_R2) | (u32ptr(g) >> 16);
  182.   *p++ = MIPSI_ORI | MIPSF_T(RID_R3)|MIPSF_S(RID_R3) |(u32ptr(target)&0xffff);
  183.   *p++ = MIPSI_JR | MIPSF_S(RID_R3);
  184.   *p++ = MIPSI_ORI | MIPSF_T(RID_R2)|MIPSF_S(RID_R2) | (u32ptr(g)&0xffff);
  185.   for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
  186.     *p = MIPSI_B | ((page-p-1) & 0x0000ffffu);
  187.     p++;
  188.     *p++ = MIPSI_LI | MIPSF_T(RID_R1) | slot;
  189.   }
  190.   lua_assert(p - page <= CALLBACK_MCODE_SIZE);
  191. }
  192. #else
  193. /* Missing support for this architecture. */
  194. #define callback_mcode_init(g, p)        UNUSED(p)
  195. #endif

  196. /* -- Machine code management --------------------------------------------- */

  197. #if LJ_TARGET_WINDOWS

  198. #define WIN32_LEAN_AND_MEAN
  199. #include <windows.h>

  200. #elif LJ_TARGET_POSIX

  201. #include <sys/mman.h>
  202. #ifndef MAP_ANONYMOUS
  203. #define MAP_ANONYMOUS   MAP_ANON
  204. #endif

  205. #endif

  206. /* Allocate and initialize area for callback function pointers. */
  207. static void callback_mcode_new(CTState *cts)
  208. {
  209.   size_t sz = (size_t)CALLBACK_MCODE_SIZE;
  210.   void *p;
  211.   if (CALLBACK_MAX_SLOT == 0)
  212.     lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
  213. #if LJ_TARGET_WINDOWS
  214.   p = VirtualAlloc(NULL, sz, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
  215.   if (!p)
  216.     lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
  217. #elif LJ_TARGET_POSIX
  218.   p = mmap(NULL, sz, (PROT_READ|PROT_WRITE), MAP_PRIVATE|MAP_ANONYMOUS,
  219.            -1, 0);
  220.   if (p == MAP_FAILED)
  221.     lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
  222. #else
  223.   /* Fallback allocator. Fails if memory is not executable by default. */
  224.   p = lj_mem_new(cts->L, sz);
  225. #endif
  226.   cts->cb.mcode = p;
  227.   callback_mcode_init(cts->g, p);
  228.   lj_mcode_sync(p, (char *)p + sz);
  229. #if LJ_TARGET_WINDOWS
  230.   {
  231.     DWORD oprot;
  232.     VirtualProtect(p, sz, PAGE_EXECUTE_READ, &oprot);
  233.   }
  234. #elif LJ_TARGET_POSIX
  235.   mprotect(p, sz, (PROT_READ|PROT_EXEC));
  236. #endif
  237. }

  238. /* Free area for callback function pointers. */
  239. void lj_ccallback_mcode_free(CTState *cts)
  240. {
  241.   size_t sz = (size_t)CALLBACK_MCODE_SIZE;
  242.   void *p = cts->cb.mcode;
  243.   if (p == NULL) return;
  244. #if LJ_TARGET_WINDOWS
  245.   VirtualFree(p, 0, MEM_RELEASE);
  246.   UNUSED(sz);
  247. #elif LJ_TARGET_POSIX
  248.   munmap(p, sz);
  249. #else
  250.   lj_mem_free(cts->g, p, sz);
  251. #endif
  252. }

  253. /* -- C callback entry ---------------------------------------------------- */

  254. /* Target-specific handling of register arguments. Similar to lj_ccall.c. */
  255. #if LJ_TARGET_X86

  256. #define CALLBACK_HANDLE_REGARG \
  257.   if (!isfp) {  /* Only non-FP values may be passed in registers. */ \
  258.     if (n > 1) {  /* Anything > 32 bit is passed on the stack. */ \
  259.       if (!LJ_ABI_WIN) ngpr = maxgpr;  /* Prevent reordering. */ \
  260.     } else if (ngpr + 1 <= maxgpr) { \
  261.       sp = &cts->cb.gpr[ngpr]; \
  262.       ngpr += n; \
  263.       goto done; \
  264.     } \
  265.   }

  266. #elif LJ_TARGET_X64 && LJ_ABI_WIN

  267. /* Windows/x64 argument registers are strictly positional (use ngpr). */
  268. #define CALLBACK_HANDLE_REGARG \
  269.   if (isfp) { \
  270.     if (ngpr < maxgpr) { sp = &cts->cb.fpr[ngpr++]; UNUSED(nfpr); goto done; } \
  271.   } else { \
  272.     if (ngpr < maxgpr) { sp = &cts->cb.gpr[ngpr++]; goto done; } \
  273.   }

  274. #elif LJ_TARGET_X64

  275. #define CALLBACK_HANDLE_REGARG \
  276.   if (isfp) { \
  277.     if (nfpr + n <= CCALL_NARG_FPR) { \
  278.       sp = &cts->cb.fpr[nfpr]; \
  279.       nfpr += n; \
  280.       goto done; \
  281.     } \
  282.   } else { \
  283.     if (ngpr + n <= maxgpr) { \
  284.       sp = &cts->cb.gpr[ngpr]; \
  285.       ngpr += n; \
  286.       goto done; \
  287.     } \
  288.   }

  289. #elif LJ_TARGET_ARM

  290. #if LJ_ABI_SOFTFP

  291. #define CALLBACK_HANDLE_REGARG_FP1        UNUSED(isfp);
  292. #define CALLBACK_HANDLE_REGARG_FP2

  293. #else

  294. #define CALLBACK_HANDLE_REGARG_FP1 \
  295.   if (isfp) { \
  296.     if (n == 1) { \
  297.       if (fprodd) { \
  298.         sp = &cts->cb.fpr[fprodd-1]; \
  299.         fprodd = 0; \
  300.         goto done; \
  301.       } else if (nfpr + 1 <= CCALL_NARG_FPR) { \
  302.         sp = &cts->cb.fpr[nfpr++]; \
  303.         fprodd = nfpr; \
  304.         goto done; \
  305.       } \
  306.     } else { \
  307.       if (nfpr + 1 <= CCALL_NARG_FPR) { \
  308.         sp = &cts->cb.fpr[nfpr++]; \
  309.         goto done; \
  310.       } \
  311.     } \
  312.     fprodd = 0/* No reordering after the first FP value is on stack. */ \
  313.   } else {

  314. #define CALLBACK_HANDLE_REGARG_FP2        }

  315. #endif

  316. #define CALLBACK_HANDLE_REGARG \
  317.   CALLBACK_HANDLE_REGARG_FP1 \
  318.   if (n > 1) ngpr = (ngpr + 1u) & ~1u/* Align to regpair. */ \
  319.   if (ngpr + n <= maxgpr) { \
  320.     sp = &cts->cb.gpr[ngpr]; \
  321.     ngpr += n; \
  322.     goto done; \
  323.   } CALLBACK_HANDLE_REGARG_FP2

  324. #elif LJ_TARGET_ARM64

  325. #define CALLBACK_HANDLE_REGARG \
  326.   if (isfp) { \
  327.     if (nfpr + n <= CCALL_NARG_FPR) { \
  328.       sp = &cts->cb.fpr[nfpr]; \
  329.       nfpr += n; \
  330.       goto done; \
  331.     } else { \
  332.       nfpr = CCALL_NARG_FPR/* Prevent reordering. */ \
  333.     } \
  334.   } else { \
  335.     if (!LJ_TARGET_IOS && n > 1) \
  336.       ngpr = (ngpr + 1u) & ~1u/* Align to regpair. */ \
  337.     if (ngpr + n <= maxgpr) { \
  338.       sp = &cts->cb.gpr[ngpr]; \
  339.       ngpr += n; \
  340.       goto done; \
  341.     } else { \
  342.       ngpr = CCALL_NARG_GPR/* Prevent reordering. */ \
  343.     } \
  344.   }

  345. #elif LJ_TARGET_PPC

  346. #define CALLBACK_HANDLE_REGARG \
  347.   if (isfp) { \
  348.     if (nfpr + 1 <= CCALL_NARG_FPR) { \
  349.       sp = &cts->cb.fpr[nfpr++]; \
  350.       cta = ctype_get(cts, CTID_DOUBLE);  /* FPRs always hold doubles. */ \
  351.       goto done; \
  352.     } \
  353.   } else/* Try to pass argument in GPRs. */ \
  354.     if (n > 1) { \
  355.       lua_assert(ctype_isinteger(cta->info) && n == 2);  /* int64_t. */ \
  356.       ngpr = (ngpr + 1u) & ~1u/* Align int64_t to regpair. */ \
  357.     } \
  358.     if (ngpr + n <= maxgpr) { \
  359.       sp = &cts->cb.gpr[ngpr]; \
  360.       ngpr += n; \
  361.       goto done; \
  362.     } \
  363.   }

  364. #define CALLBACK_HANDLE_RET \
  365.   if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
  366.     *(double *)dp = *(float *)dp;  /* FPRs always hold doubles. */

  367. #elif LJ_TARGET_MIPS

  368. #define CALLBACK_HANDLE_REGARG \
  369.   if (isfp && nfpr < CCALL_NARG_FPR) {  /* Try to pass argument in FPRs. */ \
  370.     sp = (void *)((uint8_t *)&cts->cb.fpr[nfpr] + ((LJ_BE && n==1) ? 4 : 0)); \
  371.     nfpr++; ngpr += n; \
  372.     goto done; \
  373.   } else/* Try to pass argument in GPRs. */ \
  374.     nfpr = CCALL_NARG_FPR; \
  375.     if (n > 1) ngpr = (ngpr + 1u) & ~1u/* Align to regpair. */ \
  376.     if (ngpr + n <= maxgpr) { \
  377.       sp = &cts->cb.gpr[ngpr]; \
  378.       ngpr += n; \
  379.       goto done; \
  380.     } \
  381.   }

  382. #define CALLBACK_HANDLE_RET \
  383.   if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
  384.     ((float *)dp)[1] = *(float *)dp;

  385. #else
  386. #error "Missing calling convention definitions for this architecture"
  387. #endif

  388. /* Convert and push callback arguments to Lua stack. */
  389. static void callback_conv_args(CTState *cts, lua_State *L)
  390. {
  391.   TValue *o = L->top;
  392.   intptr_t *stack = cts->cb.stack;
  393.   MSize slot = cts->cb.slot;
  394.   CTypeID id = 0, rid, fid;
  395.   int gcsteps = 0;
  396.   CType *ct;
  397.   GCfunc *fn;
  398.   int fntp;
  399.   MSize ngpr = 0, nsp = 0, maxgpr = CCALL_NARG_GPR;
  400. #if CCALL_NARG_FPR
  401.   MSize nfpr = 0;
  402. #if LJ_TARGET_ARM
  403.   MSize fprodd = 0;
  404. #endif
  405. #endif

  406.   if (slot < cts->cb.sizeid && (id = cts->cb.cbid[slot]) != 0) {
  407.     ct = ctype_get(cts, id);
  408.     rid = ctype_cid(ct->info);  /* Return type. x86: +(spadj<<16). */
  409.     fn = funcV(lj_tab_getint(cts->miscmap, (int32_t)slot));
  410.     fntp = LJ_TFUNC;
  411.   } else/* Must set up frame first, before throwing the error. */
  412.     ct = NULL;
  413.     rid = 0;
  414.     fn = (GCfunc *)L;
  415.     fntp = LJ_TTHREAD;
  416.   }
  417.   /* Continuation returns from callback. */
  418.   if (LJ_FR2) {
  419.     (o++)->u64 = LJ_CONT_FFI_CALLBACK;
  420.     (o++)->u64 = rid;
  421.     o++;
  422.   } else {
  423.     o->u32.lo = LJ_CONT_FFI_CALLBACK;
  424.     o->u32.hi = rid;
  425.     o++;
  426.   }
  427.   setframe_gc(o, obj2gco(fn), fntp);
  428.   setframe_ftsz(o, ((char *)(o+1) - (char *)L->base) + FRAME_CONT);
  429.   L->top = L->base = ++o;
  430.   if (!ct)
  431.     lj_err_caller(cts->L, LJ_ERR_FFI_BADCBACK);
  432.   if (isluafunc(fn))
  433.     setcframe_pc(L->cframe, proto_bc(funcproto(fn))+1);
  434.   lj_state_checkstack(L, LUA_MINSTACK);  /* May throw. */
  435.   o = L->base;  /* Might have been reallocated. */

  436. #if LJ_TARGET_X86
  437.   /* x86 has several different calling conventions. */
  438.   switch (ctype_cconv(ct->info)) {
  439.   case CTCC_FASTCALL: maxgpr = 2; break;
  440.   case CTCC_THISCALL: maxgpr = 1; break;
  441.   default: maxgpr = 0; break;
  442.   }
  443. #endif

  444.   fid = ct->sib;
  445.   while (fid) {
  446.     CType *ctf = ctype_get(cts, fid);
  447.     if (!ctype_isattrib(ctf->info)) {
  448.       CType *cta;
  449.       void *sp;
  450.       CTSize sz;
  451.       int isfp;
  452.       MSize n;
  453.       lua_assert(ctype_isfield(ctf->info));
  454.       cta = ctype_rawchild(cts, ctf);
  455.       isfp = ctype_isfp(cta->info);
  456.       sz = (cta->size + CTSIZE_PTR-1) & ~(CTSIZE_PTR-1);
  457.       n = sz / CTSIZE_PTR/* Number of GPRs or stack slots needed. */

  458.       CALLBACK_HANDLE_REGARG  /* Handle register arguments. */

  459.       /* Otherwise pass argument on stack. */
  460.       if (CCALL_ALIGN_STACKARG && LJ_32 && sz == 8)
  461.         nsp = (nsp + 1) & ~1u/* Align 64 bit argument on stack. */
  462.       sp = &stack[nsp];
  463.       nsp += n;

  464.     done:
  465.       if (LJ_BE && cta->size < CTSIZE_PTR)
  466.         sp = (void *)((uint8_t *)sp + CTSIZE_PTR-cta->size);
  467.       gcsteps += lj_cconv_tv_ct(cts, cta, 0, o++, sp);
  468.     }
  469.     fid = ctf->sib;
  470.   }
  471.   L->top = o;
  472. #if LJ_TARGET_X86
  473.   /* Store stack adjustment for returns from non-cdecl callbacks. */
  474.   if (ctype_cconv(ct->info) != CTCC_CDECL) {
  475. #if LJ_FR2
  476.     (L->base-3)->u64 |= (nsp << (16+2));
  477. #else
  478.     (L->base-2)->u32.hi |= (nsp << (16+2));
  479. #endif
  480.   }
  481. #endif
  482.   while (gcsteps-- > 0)
  483.     lj_gc_check(L);
  484. }

  485. /* Convert Lua object to callback result. */
  486. static void callback_conv_result(CTState *cts, lua_State *L, TValue *o)
  487. {
  488. #if LJ_FR2
  489.   CType *ctr = ctype_raw(cts, (uint16_t)(L->base-3)->u64);
  490. #else
  491.   CType *ctr = ctype_raw(cts, (uint16_t)(L->base-2)->u32.hi);
  492. #endif
  493. #if LJ_TARGET_X86
  494.   cts->cb.gpr[2] = 0;
  495. #endif
  496.   if (!ctype_isvoid(ctr->info)) {
  497.     uint8_t *dp = (uint8_t *)&cts->cb.gpr[0];
  498. #if CCALL_NUM_FPR
  499.     if (ctype_isfp(ctr->info))
  500.       dp = (uint8_t *)&cts->cb.fpr[0];
  501. #endif
  502.     lj_cconv_ct_tv(cts, ctr, dp, o, 0);
  503. #ifdef CALLBACK_HANDLE_RET
  504.     CALLBACK_HANDLE_RET
  505. #endif
  506.     /* Extend returned integers to (at least) 32 bits. */
  507.     if (ctype_isinteger_or_bool(ctr->info) && ctr->size < 4) {
  508.       if (ctr->info & CTF_UNSIGNED)
  509.         *(uint32_t *)dp = ctr->size == 1 ? (uint32_t)*(uint8_t *)dp :
  510.                                            (uint32_t)*(uint16_t *)dp;
  511.       else
  512.         *(int32_t *)dp = ctr->size == 1 ? (int32_t)*(int8_t *)dp :
  513.                                           (int32_t)*(int16_t *)dp;
  514.     }
  515. #if LJ_TARGET_X86
  516.     if (ctype_isfp(ctr->info))
  517.       cts->cb.gpr[2] = ctr->size == sizeof(float) ? 1 : 2;
  518. #endif
  519.   }
  520. }

  521. /* Enter callback. */
  522. lua_State * LJ_FASTCALL lj_ccallback_enter(CTState *cts, void *cf)
  523. {
  524.   lua_State *L = cts->L;
  525.   global_State *g = cts->g;
  526.   lua_assert(L != NULL);
  527.   if (tvref(g->jit_base)) {
  528.     setstrV(L, L->top++, lj_err_str(L, LJ_ERR_FFI_BADCBACK));
  529.     if (g->panic) g->panic(L);
  530.     exit(EXIT_FAILURE);
  531.   }
  532.   lj_trace_abort(g);  /* Never record across callback. */
  533.   /* Setup C frame. */
  534.   cframe_prev(cf) = L->cframe;
  535.   setcframe_L(cf, L);
  536.   cframe_errfunc(cf) = -1;
  537.   cframe_nres(cf) = 0;
  538.   L->cframe = cf;
  539.   callback_conv_args(cts, L);
  540.   return L;  /* Now call the function on this stack. */
  541. }

  542. /* Leave callback. */
  543. void LJ_FASTCALL lj_ccallback_leave(CTState *cts, TValue *o)
  544. {
  545.   lua_State *L = cts->L;
  546.   GCfunc *fn;
  547.   TValue *obase = L->base;
  548.   L->base = L->top;  /* Keep continuation frame for throwing errors. */
  549.   if (o >= L->base) {
  550.     /* PC of RET* is lost. Point to last line for result conv. errors. */
  551.     fn = curr_func(L);
  552.     if (isluafunc(fn)) {
  553.       GCproto *pt = funcproto(fn);
  554.       setcframe_pc(L->cframe, proto_bc(pt)+pt->sizebc+1);
  555.     }
  556.   }
  557.   callback_conv_result(cts, L, o);
  558.   /* Finally drop C frame and continuation frame. */
  559.   L->top -= 2+2*LJ_FR2;
  560.   L->base = obase;
  561.   L->cframe = cframe_prev(L->cframe);
  562.   cts->cb.slot = 0/* Blacklist C function that called the callback. */
  563. }

  564. /* -- C callback management ----------------------------------------------- */

  565. /* Get an unused slot in the callback slot table. */
  566. static MSize callback_slot_new(CTState *cts, CType *ct)
  567. {
  568.   CTypeID id = ctype_typeid(cts, ct);
  569.   CTypeID1 *cbid = cts->cb.cbid;
  570.   MSize top;
  571.   for (top = cts->cb.topid; top < cts->cb.sizeid; top++)
  572.     if (LJ_LIKELY(cbid[top] == 0))
  573.       goto found;
  574. #if CALLBACK_MAX_SLOT
  575.   if (top >= CALLBACK_MAX_SLOT)
  576. #endif
  577.     lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
  578.   if (!cts->cb.mcode)
  579.     callback_mcode_new(cts);
  580.   lj_mem_growvec(cts->L, cbid, cts->cb.sizeid, CALLBACK_MAX_SLOT, CTypeID1);
  581.   cts->cb.cbid = cbid;
  582.   memset(cbid+top, 0, (cts->cb.sizeid-top)*sizeof(CTypeID1));
  583. found:
  584.   cbid[top] = id;
  585.   cts->cb.topid = top+1;
  586.   return top;
  587. }

  588. /* Check for function pointer and supported argument/result types. */
  589. static CType *callback_checkfunc(CTState *cts, CType *ct)
  590. {
  591.   int narg = 0;
  592.   if (!ctype_isptr(ct->info) || (LJ_64 && ct->size != CTSIZE_PTR))
  593.     return NULL;
  594.   ct = ctype_rawchild(cts, ct);
  595.   if (ctype_isfunc(ct->info)) {
  596.     CType *ctr = ctype_rawchild(cts, ct);
  597.     CTypeID fid = ct->sib;
  598.     if (!(ctype_isvoid(ctr->info) || ctype_isenum(ctr->info) ||
  599.           ctype_isptr(ctr->info) || (ctype_isnum(ctr->info) && ctr->size <= 8)))
  600.       return NULL;
  601.     if ((ct->info & CTF_VARARG))
  602.       return NULL;
  603.     while (fid) {
  604.       CType *ctf = ctype_get(cts, fid);
  605.       if (!ctype_isattrib(ctf->info)) {
  606.         CType *cta;
  607.         lua_assert(ctype_isfield(ctf->info));
  608.         cta = ctype_rawchild(cts, ctf);
  609.         if (!(ctype_isenum(cta->info) || ctype_isptr(cta->info) ||
  610.               (ctype_isnum(cta->info) && cta->size <= 8)) ||
  611.             ++narg >= LUA_MINSTACK-3)
  612.           return NULL;
  613.       }
  614.       fid = ctf->sib;
  615.     }
  616.     return ct;
  617.   }
  618.   return NULL;
  619. }

  620. /* Create a new callback and return the callback function pointer. */
  621. void *lj_ccallback_new(CTState *cts, CType *ct, GCfunc *fn)
  622. {
  623.   ct = callback_checkfunc(cts, ct);
  624.   if (ct) {
  625.     MSize slot = callback_slot_new(cts, ct);
  626.     GCtab *t = cts->miscmap;
  627.     setfuncV(cts->L, lj_tab_setint(cts->L, t, (int32_t)slot), fn);
  628.     lj_gc_anybarriert(cts->L, t);
  629.     return callback_slot2ptr(cts, slot);
  630.   }
  631.   return NULL/* Bad conversion. */
  632. }

  633. #endif