sq_ffi.cpp 11 KB

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