sq_ffi.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  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 'P':
  89. case 's':
  90. return &ffi_type_pointer;
  91. default:
  92. return NULL;
  93. }
  94. }
  95. static ffi_type *get_ffi_type(HSQUIRRELVM v, int idx)
  96. {
  97. int type = sq_gettype(v, idx);
  98. void *p;
  99. const SQChar *s;
  100. ffi_type *t;
  101. switch (type) {
  102. case OT_USERPOINTER:
  103. sq_getuserpointer(v, idx, &p);
  104. return (ffi_type*)p;
  105. case OT_STRING:
  106. sq_getstring(v, idx, &s);
  107. t = char2ffi_type(*s);
  108. if (t)
  109. return t;
  110. default:
  111. sq_throwerror(v, "Type spec must be string or ffi_type");
  112. return NULL;
  113. }
  114. }
  115. typedef struct FFIFunc
  116. {
  117. void *func;
  118. char rettype;
  119. ffi_cif cif;
  120. ffi_type *params[0];
  121. } FFIFunc;
  122. typedef struct FFIVar
  123. {
  124. void *var;
  125. char type;
  126. } FFIVar;
  127. static SQInteger sq_lib_bind_func(HSQUIRRELVM v)
  128. {
  129. void **modbuf;
  130. void *mod;
  131. void *sym;
  132. const SQChar *symname;
  133. const char *rettype;
  134. sq_getuserdata(v, 1, (void**)&modbuf, NULL);
  135. mod = *modbuf;
  136. sq_getstring(v, 2, &rettype);
  137. sq_getstring(v, 3, &symname);
  138. sym = GET_SYM(mod, symname);
  139. if (!sym)
  140. return sq_throwerror(v, "Cannot find symbol");
  141. int nparam = sq_getsize(v, 4);
  142. int size = sizeof(FFIFunc) + sizeof(ffi_type*) * nparam;
  143. FFIFunc *ffibuf = (FFIFunc*)sq_newuserdata(v, size);
  144. sq_push_delegate_table(v, FFI_LIB_FUNC_TAG);
  145. sq_setdelegate(v, -2);
  146. // printf("Allocated %d bytes at %p\n", size, ffibuf);
  147. ffibuf->func = sym;
  148. ffibuf->rettype = *rettype;
  149. int i;
  150. for (i = 0; i < nparam; i++) {
  151. sq_pushinteger(v, i);
  152. sq_get(v, 4);
  153. ffibuf->params[i] = get_ffi_type(v, -1);
  154. if (!ffibuf->params[i])
  155. return SQ_ERROR;
  156. sq_poptop(v);
  157. }
  158. int res = ffi_prep_cif(&ffibuf->cif, FFI_DEFAULT_ABI, nparam, char2ffi_type(*rettype), ffibuf->params);
  159. if (res != FFI_OK)
  160. return sq_throwerror(v, "Error in ffi_prep_cif");
  161. return 1;
  162. }
  163. static SQInteger sq_lib_bind_var(HSQUIRRELVM v)
  164. {
  165. void **modbuf;
  166. void *mod;
  167. void *sym;
  168. const SQChar *symname;
  169. const char *type;
  170. sq_getuserdata(v, 1, (void**)&modbuf, NULL);
  171. mod = *modbuf;
  172. sq_getstring(v, 2, &type);
  173. sq_getstring(v, 3, &symname);
  174. sym = GET_SYM(mod, symname);
  175. if (!sym)
  176. return sq_throwerror(v, "Cannot find symbol");
  177. FFIVar *ffibuf = (FFIVar*)sq_newuserdata(v, sizeof(FFIVar));
  178. sq_push_delegate_table(v, FFI_LIB_VAR_TAG);
  179. sq_setdelegate(v, -2);
  180. ffibuf->var = sym;
  181. ffibuf->type = *type;
  182. return 1;
  183. }
  184. #define METAMETHOD
  185. #ifdef METAMETHOD
  186. // For metamethod, we have userdata, then delegate table
  187. #define EXTRA_PARAMS 2
  188. #else
  189. // For normal method, there's only userdata
  190. #define EXTRA_PARAMS 1
  191. #endif
  192. static void return_ffi_value(HSQUIRRELVM v, ptrdiff_t val, char type)
  193. {
  194. switch (type) {
  195. case 's':
  196. sq_pushstring(v, (char*)val, -1);
  197. break;
  198. default:
  199. sq_pushinteger(v, val);
  200. }
  201. }
  202. static SQInteger sq_func__call(HSQUIRRELVM v)
  203. {
  204. FFIFunc *ffibuf;
  205. sq_getuserdata(v, 1, (void**)&ffibuf, NULL);
  206. int top = sq_gettop(v);
  207. // printf("ffibuf %p top %d\n", ffibuf, top);
  208. if (ffibuf->cif.nargs != ((unsigned)(top - EXTRA_PARAMS)))
  209. return sq_throwerror(v, "Wrong number of args");
  210. SQInteger values[top - EXTRA_PARAMS];
  211. void *valueptrs[top - EXTRA_PARAMS];
  212. int i;
  213. for (i = EXTRA_PARAMS + 1; i <= top; i++) {
  214. #define pi (i - (EXTRA_PARAMS + 1))
  215. switch (sq_gettype(v, i)) {
  216. case OT_INTEGER:
  217. sq_getinteger(v, i, (SQInteger*)&values[pi]);
  218. break;
  219. case OT_STRING:
  220. sq_getstring(v, i, (const char**)&values[pi]);
  221. break;
  222. case OT_INSTANCE: {
  223. if (SQ_FAILED(sqstd_getblob(v, i, (SQUserPointer*)&values[pi])))
  224. return SQ_ERROR;
  225. break;
  226. }
  227. default:
  228. return sq_throwerror(v, "Unimplemented type");
  229. }
  230. valueptrs[pi] = &values[pi];
  231. }
  232. ptrdiff_t rc;
  233. // printf("Before call, %p\n", ffibuf->func);
  234. ffi_call(&ffibuf->cif, (void(*)())ffibuf->func, &rc, valueptrs);
  235. return_ffi_value(v, rc, ffibuf->rettype);
  236. return 1;
  237. }
  238. static SQInteger sq_var_get(HSQUIRRELVM v)
  239. {
  240. FFIVar *ffibuf;
  241. sq_getuserdata(v, 1, (void**)&ffibuf, NULL);
  242. void *pval = ffibuf->var;
  243. switch (ffibuf->type) {
  244. case 's':
  245. sq_pushstring(v, *(char**)pval, -1);
  246. break;
  247. case 'i':
  248. sq_pushinteger(v, *(int*)pval);
  249. break;
  250. case 'I':
  251. sq_pushinteger(v, *(unsigned int*)pval);
  252. break;
  253. case 'h':
  254. sq_pushinteger(v, *(short*)pval);
  255. break;
  256. case 'H':
  257. sq_pushinteger(v, *(unsigned short*)pval);
  258. break;
  259. case 'l':
  260. sq_pushinteger(v, *(long*)pval);
  261. break;
  262. case 'L':
  263. sq_pushinteger(v, *(unsigned long*)pval);
  264. break;
  265. case 'b':
  266. sq_pushinteger(v, *(char*)pval);
  267. break;
  268. case 'B':
  269. sq_pushinteger(v, *(unsigned char*)pval);
  270. break;
  271. default:
  272. sq_pushinteger(v, *(int*)pval);
  273. }
  274. return 1;
  275. }
  276. static SQInteger sq_ffi_setdelegate(HSQUIRRELVM v)
  277. {
  278. if (SQ_FAILED(sq_setdelegate(v, 2)))
  279. return SQ_ERROR;
  280. return 0;
  281. }
  282. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_ffi_##name,nparams,tycheck}
  283. static SQRegFunction sq_ffi_methods[] =
  284. {
  285. _DECL_FUNC(load, 2, _SC(".s")),
  286. _DECL_FUNC(sym, 3, _SC(".ps")),
  287. _DECL_FUNC(setdelegate, 3, _SC("..t")),
  288. {0,0}
  289. };
  290. #undef _DECL_FUNC
  291. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_lib_##name,nparams,tycheck}
  292. static SQRegFunction sq_lib_methods[] =
  293. {
  294. _DECL_FUNC(bind_func, 4, _SC("ussa")),
  295. _DECL_FUNC(bind_var, 3, _SC("uss")),
  296. {0,0}
  297. };
  298. #undef _DECL_FUNC
  299. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_func_##name,nparams,tycheck}
  300. static SQRegFunction sq_func_methods[] =
  301. {
  302. _DECL_FUNC(_call, -1, _SC("u")),
  303. {0,0}
  304. };
  305. #undef _DECL_FUNC
  306. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_var_##name,nparams,tycheck}
  307. static SQRegFunction sq_var_methods[] =
  308. {
  309. _DECL_FUNC(get, 1, _SC("u")),
  310. {0,0}
  311. };
  312. #undef _DECL_FUNC
  313. struct FFI_type_name {
  314. const char* name;
  315. ffi_type *type;
  316. };
  317. static struct FFI_type_name ffi_types_wrap[] = {
  318. {"void", &ffi_type_void},
  319. {"schar", &ffi_type_schar},
  320. {"uchar", &ffi_type_uchar},
  321. {"sshort", &ffi_type_sshort},
  322. {"ushort", &ffi_type_ushort},
  323. {"sint", &ffi_type_sint},
  324. {"uint", &ffi_type_uint},
  325. {"slong", &ffi_type_slong},
  326. {"ulong", &ffi_type_ulong},
  327. {"float", &ffi_type_float},
  328. {"double", &ffi_type_double},
  329. {"pointer", &ffi_type_pointer},
  330. {NULL}
  331. };
  332. #ifdef __cplusplus
  333. extern "C" {
  334. #endif
  335. static inline void sq_create_delegate_table(HSQUIRRELVM vm, SQRegFunction *methods, HSQOBJECT *handle)
  336. {
  337. sq_newtable(vm);
  338. sq_insert_reg_funcs(vm, methods);
  339. sq_resetobject(handle);
  340. sq_getstackobj(vm, -1, handle);
  341. sq_addref(vm, handle);
  342. }
  343. SQRESULT sqext_register_ffi(HSQUIRRELVM v)
  344. {
  345. int saved_top = sq_gettop(v);
  346. //add a namespace ffi
  347. sq_pushstring(v,_SC("ffi"),-1);
  348. sq_newclass(v,SQFalse);
  349. sq_settypetag(v,-1,(void*)FFI_LIB_TAG);
  350. sq_insert_reg_funcs(v, sq_ffi_methods);
  351. int i;
  352. for (i = 0; ffi_types_wrap[i].name != 0; i++) {
  353. struct FFI_type_name *e = &ffi_types_wrap[i];
  354. sq_pushstring(v, e->name, -1);
  355. sq_pushuserpointer(v, e->type);
  356. sq_newslot(v, -3, SQFalse);
  357. }
  358. sq_newslot(v,-3,SQTrue); //add ffi table to the root table
  359. sq_create_delegate_table(v, sq_lib_methods, FFI_LIB_LIB_TAG);
  360. sq_create_delegate_table(v, sq_func_methods, FFI_LIB_FUNC_TAG);
  361. sq_create_delegate_table(v, sq_var_methods, FFI_LIB_VAR_TAG);
  362. sq_settop(v, saved_top);
  363. return SQ_OK;
  364. }
  365. #ifdef __cplusplus
  366. }
  367. #endif
  368. #endif //WITH_FFI