sq_ffi.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. #ifdef WITH_FFI
  2. #include "squirrel.h"
  3. #include <ffi.h>
  4. #include <string.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include "sqstdblobimpl.h"
  8. #include "sqstdblob.h"
  9. #ifdef WIN32
  10. #include <windows.h>
  11. #define CLOSE_LIB(lib) (FreeLibrary((HINSTANCE)lib) != 0)
  12. #ifdef _WIN32_WCE
  13. #define OPEN_LIB(lib) (void*)LoadLibraryA(lib)
  14. #define GET_SYM(lib, sn) GetProcAddressA((HINSTANCE)lib, sn)
  15. #else
  16. #define OPEN_LIB(lib) (void*)LoadLibrary(lib)
  17. #define GET_SYM(lib, sn) (void*)GetProcAddress((HINSTANCE)lib, sn)
  18. #endif
  19. typedef void* (WINAPI*cPtrFuncVarArg)(...);
  20. #else
  21. #include <dlfcn.h>
  22. #define CLOSE_LIB(lib) (::dlclose(lib) == 0)
  23. #define OPEN_LIB(lib) ::dlopen(lib,RTLD_LAZY)
  24. #define GET_SYM(lib, sn) ::dlsym(lib, sn)
  25. typedef void*(*cPtrFuncVarArg)(...);
  26. #endif
  27. static const SQChar *FFI_LIB_TAG = _SC("FFI_LIB");
  28. static const SQChar *FFI_LIB_LIB_TAG = _SC("FFI_LIB_LIB");
  29. static const SQChar *FFI_LIB_FUNC_TAG = _SC("FFI_LIB_FUNC");
  30. static const SQChar *FFI_LIB_VAR_TAG = _SC("FFI_LIB_VAR");
  31. //Code adapted from https://github.com/pfalcon/squirrel-modules
  32. /** Stores a delegate table on registry by key */
  33. static inline void sq_create_delegate_table(HSQUIRRELVM vm, SQRegFunction *methods, const SQChar *key)
  34. {
  35. sq_pushstring(vm, key, -1);
  36. sq_newtable(vm);
  37. sq_insert_reg_funcs(vm, methods);
  38. sq_setonregistrytable(vm);
  39. }
  40. static inline void sq_push_delegate_table(HSQUIRRELVM vm, const SQChar *key)
  41. {
  42. sq_pushstring(vm, key, -1);
  43. sq_getonregistrytable(vm);
  44. }
  45. static SQInteger sq_ffi_load(HSQUIRRELVM v)
  46. {
  47. const SQChar *fname;
  48. sq_getstring(v, 2, &fname);
  49. void *mod = OPEN_LIB(fname);
  50. if (!mod)
  51. return sq_throwerror(v, "Cannot load library");
  52. sq_pushuserpointer(v, mod);
  53. void **p = (void**)sq_newuserdata(v, sizeof(mod));
  54. *p = mod;
  55. sq_push_delegate_table(v, FFI_LIB_LIB_TAG);
  56. sq_setdelegate(v, -2);
  57. return 1;
  58. }
  59. static SQInteger sq_ffi_sym(HSQUIRRELVM v)
  60. {
  61. void *mod;
  62. const SQChar *symname;
  63. sq_getuserpointer(v, 2, &mod);
  64. sq_getstring(v, 3, &symname);
  65. void *sym = GET_SYM(mod, symname);
  66. printf("GET_SYM(%s) = %p\n", symname, sym);
  67. if (!sym)
  68. return sq_throwerror(v, "Cannot find symbol");
  69. void **p = (void**)sq_newuserdata(v, sizeof(sym));
  70. *p = sym;
  71. return 1;
  72. }
  73. static ffi_type *char2ffi_type(char c)
  74. {
  75. switch (c) {
  76. case 'b':
  77. return &ffi_type_schar;
  78. case 'B':
  79. return &ffi_type_uchar;
  80. case 'i':
  81. return &ffi_type_sint;
  82. case 'I':
  83. return &ffi_type_uint;
  84. case 'l':
  85. return &ffi_type_slong;
  86. case 'L':
  87. return &ffi_type_ulong;
  88. case 'f':
  89. return &ffi_type_float;
  90. case 'd':
  91. return &ffi_type_double;
  92. case 'P':
  93. case 'A':
  94. case 's':
  95. return &ffi_type_pointer;
  96. case 'v':
  97. return &ffi_type_void;
  98. default:
  99. return NULL;
  100. }
  101. }
  102. static ffi_type *get_ffi_type(HSQUIRRELVM v, int idx)
  103. {
  104. int type = sq_gettype(v, idx);
  105. void *p;
  106. const SQChar *s;
  107. ffi_type *t;
  108. switch (type) {
  109. case OT_USERPOINTER:
  110. sq_getuserpointer(v, idx, &p);
  111. return (ffi_type*)p;
  112. case OT_STRING:
  113. sq_getstring(v, idx, &s);
  114. t = char2ffi_type(*s);
  115. if (t)
  116. return t;
  117. default:
  118. sq_throwerror(v, "Type spec must be string or ffi_type");
  119. return NULL;
  120. }
  121. }
  122. typedef struct FFIFunc
  123. {
  124. void *func;
  125. char rettype;
  126. ffi_cif cif;
  127. ffi_type *params[0];
  128. } FFIFunc;
  129. typedef struct FFIVar
  130. {
  131. void *var;
  132. char type;
  133. } FFIVar;
  134. static SQInteger sq_lib_bind_func(HSQUIRRELVM v)
  135. {
  136. void **modbuf;
  137. void *mod;
  138. void *sym;
  139. const SQChar *symname;
  140. const char *rettype;
  141. sq_getuserdata(v, 1, (void**)&modbuf, NULL);
  142. mod = *modbuf;
  143. sq_getstring(v, 2, &rettype);
  144. sq_getstring(v, 3, &symname);
  145. sym = GET_SYM(mod, symname);
  146. if (!sym)
  147. return sq_throwerror(v, "Cannot find symbol");
  148. int nparam = sq_getsize(v, 4);
  149. int size = sizeof(FFIFunc) + sizeof(ffi_type*) * nparam;
  150. FFIFunc *ffibuf = (FFIFunc*)sq_newuserdata(v, size);
  151. sq_push_delegate_table(v, FFI_LIB_FUNC_TAG);
  152. sq_setdelegate(v, -2);
  153. // printf("Allocated %d bytes at %p\n", size, ffibuf);
  154. ffibuf->func = sym;
  155. ffibuf->rettype = *rettype;
  156. int i;
  157. for (i = 0; i < nparam; i++) {
  158. sq_pushinteger(v, i);
  159. sq_get(v, 4);
  160. ffibuf->params[i] = get_ffi_type(v, -1);
  161. if (!ffibuf->params[i])
  162. return SQ_ERROR;
  163. sq_poptop(v);
  164. }
  165. int res = ffi_prep_cif(&ffibuf->cif, FFI_DEFAULT_ABI, nparam, char2ffi_type(*rettype), ffibuf->params);
  166. if (res != FFI_OK)
  167. return sq_throwerror(v, "Error in ffi_prep_cif");
  168. return 1;
  169. }
  170. static SQInteger sq_lib_bind_var(HSQUIRRELVM v)
  171. {
  172. void **modbuf;
  173. void *mod;
  174. void *sym;
  175. const SQChar *symname;
  176. const char *type;
  177. sq_getuserdata(v, 1, (void**)&modbuf, NULL);
  178. mod = *modbuf;
  179. sq_getstring(v, 2, &type);
  180. sq_getstring(v, 3, &symname);
  181. sym = GET_SYM(mod, symname);
  182. if (!sym)
  183. return sq_throwerror(v, "Cannot find symbol");
  184. FFIVar *ffibuf = (FFIVar*)sq_newuserdata(v, sizeof(FFIVar));
  185. sq_push_delegate_table(v, FFI_LIB_VAR_TAG);
  186. sq_setdelegate(v, -2);
  187. ffibuf->var = sym;
  188. ffibuf->type = *type;
  189. return 1;
  190. }
  191. #define METAMETHOD
  192. #ifdef METAMETHOD
  193. // For metamethod, we have userdata, then delegate table
  194. #define EXTRA_PARAMS 2
  195. #else
  196. // For normal method, there's only userdata
  197. #define EXTRA_PARAMS 1
  198. #endif
  199. static void return_ffi_value(HSQUIRRELVM v, ptrdiff_t val, char type)
  200. {
  201. switch (type) {
  202. case 's':
  203. sq_pushstring(v, (char*)val, -1);
  204. break;
  205. case 'i':
  206. case 'I':
  207. sq_pushinteger(v, (int)val);
  208. break;
  209. case 'b':
  210. sq_pushinteger(v, (SQChar)val);
  211. break;
  212. case 'B':
  213. sq_pushinteger(v, (SQUChar)val);
  214. break;
  215. case 'f':
  216. sq_pushfloat(v, (float)val);
  217. break;
  218. case 'd':
  219. sq_pushfloat(v, (double)val);
  220. break;
  221. case 'P':
  222. sq_pushuserpointer(v, (SQUserPointer)val);
  223. break;
  224. default:
  225. sq_pushinteger(v, val);
  226. }
  227. }
  228. static SQInteger sq_func__call(HSQUIRRELVM v)
  229. {
  230. FFIFunc *ffibuf;
  231. sq_getuserdata(v, 1, (void**)&ffibuf, NULL);
  232. int top = sq_gettop(v);
  233. // printf("ffibuf %p top %d\n", ffibuf, top);
  234. if (ffibuf->cif.nargs != ((unsigned)(top - EXTRA_PARAMS)))
  235. return sq_throwerror(v, "Wrong number of args");
  236. SQUserPointer values[top - EXTRA_PARAMS];
  237. void *valueptrs[top - EXTRA_PARAMS];
  238. int i;
  239. for (i = EXTRA_PARAMS + 1; i <= top; i++) {
  240. #define pi (i - (EXTRA_PARAMS + 1))
  241. switch (sq_gettype(v, i)) {
  242. case OT_INTEGER:
  243. sq_getinteger(v, i, (SQInteger*)&values[pi]);
  244. break;
  245. case OT_STRING:
  246. sq_getstring(v, i, (const char**)&values[pi]);
  247. break;
  248. case OT_USERPOINTER:
  249. sq_getuserpointer(v, i, (SQUserPointer*)&values[pi]);
  250. break;
  251. case OT_USERDATA:
  252. sq_getuserdata(v, i, (SQUserPointer*)&values[pi], NULL);
  253. break;
  254. case OT_INSTANCE: {
  255. if (SQ_FAILED(sqstd_getblob(v, i, (SQUserPointer*)&values[pi])))
  256. return SQ_ERROR;
  257. break;
  258. case OT_NULL:
  259. values[pi] = NULL;
  260. break;
  261. }
  262. default:
  263. return sq_throwerror(v, "Unimplemented type");
  264. }
  265. valueptrs[pi] = &values[pi];
  266. }
  267. ptrdiff_t rc;
  268. // printf("Before call, %p\n", ffibuf->func);
  269. ffi_call(&ffibuf->cif, (void(*)())ffibuf->func, &rc, valueptrs);
  270. return_ffi_value(v, rc, ffibuf->rettype);
  271. return 1;
  272. }
  273. static SQInteger sq_var_get(HSQUIRRELVM v)
  274. {
  275. FFIVar *ffibuf;
  276. sq_getuserdata(v, 1, (void**)&ffibuf, NULL);
  277. void *pval = ffibuf->var;
  278. switch (ffibuf->type) {
  279. case 's':
  280. sq_pushstring(v, *(char**)pval, -1);
  281. break;
  282. case 'i':
  283. sq_pushinteger(v, *(int*)pval);
  284. break;
  285. case 'I':
  286. sq_pushinteger(v, *(unsigned int*)pval);
  287. break;
  288. case 'h':
  289. sq_pushinteger(v, *(short*)pval);
  290. break;
  291. case 'H':
  292. sq_pushinteger(v, *(unsigned short*)pval);
  293. break;
  294. case 'l':
  295. sq_pushinteger(v, *(long*)pval);
  296. break;
  297. case 'L':
  298. sq_pushinteger(v, *(unsigned long*)pval);
  299. break;
  300. case 'b':
  301. sq_pushinteger(v, *(char*)pval);
  302. break;
  303. case 'B':
  304. sq_pushinteger(v, *(unsigned char*)pval);
  305. break;
  306. case 'P':
  307. sq_pushuserpointer(v, (SQUserPointer)pval);
  308. break;
  309. default:
  310. sq_pushinteger(v, *(int*)pval);
  311. }
  312. return 1;
  313. }
  314. static SQInteger sq_ffi_setdelegate(HSQUIRRELVM v)
  315. {
  316. if (SQ_FAILED(sq_setdelegate(v, 2)))
  317. return SQ_ERROR;
  318. return 0;
  319. }
  320. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_ffi_##name,nparams,tycheck}
  321. static SQRegFunction sq_ffi_methods[] =
  322. {
  323. _DECL_FUNC(load, 2, _SC(".s")),
  324. _DECL_FUNC(sym, 3, _SC(".ps")),
  325. _DECL_FUNC(setdelegate, 3, _SC("..t")),
  326. {0,0}
  327. };
  328. #undef _DECL_FUNC
  329. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_lib_##name,nparams,tycheck}
  330. static SQRegFunction sq_lib_methods[] =
  331. {
  332. _DECL_FUNC(bind_func, 4, _SC("ussa")),
  333. _DECL_FUNC(bind_var, 3, _SC("uss")),
  334. {0,0}
  335. };
  336. #undef _DECL_FUNC
  337. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_func_##name,nparams,tycheck}
  338. static SQRegFunction sq_func_methods[] =
  339. {
  340. _DECL_FUNC(_call, -1, _SC("u")),
  341. {0,0}
  342. };
  343. #undef _DECL_FUNC
  344. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_var_##name,nparams,tycheck}
  345. static SQRegFunction sq_var_methods[] =
  346. {
  347. _DECL_FUNC(get, 1, _SC("u")),
  348. {0,0}
  349. };
  350. #undef _DECL_FUNC
  351. struct FFI_type_name {
  352. const char* name;
  353. ffi_type *type;
  354. };
  355. #define FFI_TYPE_WRAP(tp) {"t_" #tp, &ffi_type_##tp}
  356. static struct FFI_type_name ffi_types_wrap[] = {
  357. FFI_TYPE_WRAP(void),
  358. FFI_TYPE_WRAP(schar),
  359. FFI_TYPE_WRAP(uchar),
  360. FFI_TYPE_WRAP(sshort),
  361. FFI_TYPE_WRAP(ushort),
  362. FFI_TYPE_WRAP(sint),
  363. FFI_TYPE_WRAP(uint),
  364. FFI_TYPE_WRAP(sint64),
  365. FFI_TYPE_WRAP(uint64),
  366. FFI_TYPE_WRAP(slong),
  367. FFI_TYPE_WRAP(ulong),
  368. FFI_TYPE_WRAP(float),
  369. FFI_TYPE_WRAP(double),
  370. FFI_TYPE_WRAP(pointer),
  371. {NULL}
  372. };
  373. #undef FFI_TYPE_WRAP
  374. #ifdef __cplusplus
  375. extern "C" {
  376. #endif
  377. static inline void sq_create_delegate_table(HSQUIRRELVM vm, SQRegFunction *methods, HSQOBJECT *handle)
  378. {
  379. sq_newtable(vm);
  380. sq_insert_reg_funcs(vm, methods);
  381. sq_resetobject(handle);
  382. sq_getstackobj(vm, -1, handle);
  383. sq_addref(vm, handle);
  384. }
  385. SQRESULT sqext_register_ffi(HSQUIRRELVM v)
  386. {
  387. int saved_top = sq_gettop(v);
  388. //add a namespace ffi
  389. sq_pushstring(v,_SC("ffi"),-1);
  390. sq_newclass(v,SQFalse);
  391. sq_settypetag(v,-1,(void*)FFI_LIB_TAG);
  392. sq_insert_reg_funcs(v, sq_ffi_methods);
  393. int i;
  394. for (i = 0; ffi_types_wrap[i].name != 0; i++) {
  395. struct FFI_type_name *e = &ffi_types_wrap[i];
  396. sq_pushstring(v, e->name, -1);
  397. sq_pushuserpointer(v, e->type);
  398. sq_newslot(v, -3, SQFalse);
  399. }
  400. sq_newslot(v,-3,SQTrue); //add ffi table to the root table
  401. sq_create_delegate_table(v, sq_lib_methods, FFI_LIB_LIB_TAG);
  402. sq_create_delegate_table(v, sq_func_methods, FFI_LIB_FUNC_TAG);
  403. sq_create_delegate_table(v, sq_var_methods, FFI_LIB_VAR_TAG);
  404. sq_settop(v, saved_top);
  405. return SQ_OK;
  406. }
  407. #ifdef __cplusplus
  408. }
  409. #endif
  410. #endif //WITH_FFI