sq_ffi.cpp 9.8 KB

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