PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/gnustep-base-1.24.0/Source/cifframe.m

#
Objective C | 598 lines | 481 code | 50 blank | 67 comment | 97 complexity | 32e2923861ed8047b41c7c28c9f7c682 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. /** cifframe.m - Wrapper/Objective-C interface for ffi function interface
  2. Copyright (C) 1999, Free Software Foundation, Inc.
  3. Written by: Adam Fedor <fedor@gnu.org>
  4. Date: Dec 1999, rewritten Apr 2002
  5. This file is part of the GNUstep Base Library.
  6. This library is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU Lesser General Public
  8. License as published by the Free Software Foundation; either
  9. version 2 of the License, or (at your option) any later version.
  10. This library is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. Library General Public License for more details.
  14. You should have received a copy of the GNU Lesser General Public
  15. License along with this library; if not, write to the Free
  16. Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  17. Boston, MA 02111 USA.
  18. */
  19. #import "common.h"
  20. #if !defined (__GNU_LIBOBJC__)
  21. # include <objc/encoding.h>
  22. #endif
  23. #ifdef HAVE_MALLOC_H
  24. #include <malloc.h>
  25. #endif
  26. #ifdef HAVE_ALLOCA_H
  27. #include <alloca.h>
  28. #endif
  29. #include "cifframe.h"
  30. #import "Foundation/NSException.h"
  31. #import "Foundation/NSData.h"
  32. #import "GSInvocation.h"
  33. #if defined(ALPHA) || (defined(MIPS) && (_MIPS_SIM == _ABIN32))
  34. typedef long long smallret_t;
  35. #elif defined(__sparc)
  36. typedef NSInteger smallret_t;
  37. #else
  38. typedef int smallret_t;
  39. #endif
  40. /* ffi defines types in a very odd way that doesn't map to the
  41. normal objective-c type (see ffi.h). Here we make up for that */
  42. #if GS_SIZEOF_SHORT == 2
  43. #define gsffi_type_ushort ffi_type_uint16
  44. #define gsffi_type_sshort ffi_type_sint16
  45. #elif GS_SIZEOF_SHORT == 4
  46. #define gsffi_type_ushort ffi_type_uint32
  47. #define gsffi_type_sshort ffi_type_sint32
  48. #else
  49. #error FFI Sizeof SHORT case not handled
  50. #endif
  51. #if GS_SIZEOF_INT == 2
  52. #define gsffi_type_uint ffi_type_uint16
  53. #define gsffi_type_sint ffi_type_sint16
  54. #elif GS_SIZEOF_INT == 4
  55. #define gsffi_type_uint ffi_type_uint32
  56. #define gsffi_type_sint ffi_type_sint32
  57. #elif GS_SIZEOF_INT == 8
  58. #define gsffi_type_uint ffi_type_uint64
  59. #define gsffi_type_sint ffi_type_sint64
  60. #else
  61. #error FFI Sizeof INT case not handled
  62. #endif
  63. #if GS_SIZEOF_LONG == 2
  64. #define gsffi_type_ulong ffi_type_uint16
  65. #define gsffi_type_slong ffi_type_sint16
  66. #elif GS_SIZEOF_LONG == 4
  67. #define gsffi_type_ulong ffi_type_uint32
  68. #define gsffi_type_slong ffi_type_sint32
  69. #elif GS_SIZEOF_LONG == 8
  70. #define gsffi_type_ulong ffi_type_uint64
  71. #define gsffi_type_slong ffi_type_sint64
  72. #else
  73. #error FFI Sizeof LONG case not handled
  74. #endif
  75. #ifdef _C_LNG_LNG
  76. #if GS_SIZEOF_LONG_LONG == 8
  77. #define gsffi_type_ulong_long ffi_type_uint64
  78. #define gsffi_type_slong_long ffi_type_sint64
  79. #else
  80. #error FFI Sizeof LONG LONG case not handled
  81. #endif
  82. #endif
  83. ffi_type *cifframe_type(const char *typePtr, const char **advance);
  84. /* Best guess at the space needed for a structure, since we don't know
  85. for sure until it's calculated in ffi_prep_cif, which is too late */
  86. int
  87. cifframe_guess_struct_size(ffi_type *stype)
  88. {
  89. int i, size;
  90. unsigned align = __alignof(double);
  91. if (stype->elements == NULL)
  92. return stype->size;
  93. size = 0;
  94. i = 0;
  95. while (stype->elements[i])
  96. {
  97. if (stype->elements[i]->elements)
  98. size += cifframe_guess_struct_size(stype->elements[i]);
  99. else
  100. size += stype->elements[i]->size;
  101. if (size % align != 0)
  102. {
  103. size += (align - size % align);
  104. }
  105. i++;
  106. }
  107. return size;
  108. }
  109. NSMutableData *
  110. cifframe_from_signature (NSMethodSignature *info)
  111. {
  112. unsigned size = sizeof(cifframe_t);
  113. unsigned align = __alignof(double);
  114. unsigned type_offset = 0;
  115. unsigned offset = 0;
  116. NSMutableData *result;
  117. void *buf;
  118. int i;
  119. int numargs = [info numberOfArguments];
  120. ffi_type *rtype;
  121. ffi_type *arg_types[numargs];
  122. cifframe_t *cframe;
  123. /* FIXME: in cifframe_type, return values/arguments that are structures
  124. have custom ffi_types with are allocated separately. We should allocate
  125. them in our cifframe so we don't leak memory. Or maybe we could
  126. cache structure types? */
  127. rtype = cifframe_type([info methodReturnType], NULL);
  128. for (i = 0; i < numargs; i++)
  129. {
  130. arg_types[i] = cifframe_type([info getArgumentTypeAtIndex: i], NULL);
  131. }
  132. if (numargs > 0)
  133. {
  134. if (size % align != 0)
  135. {
  136. size += align - (size % align);
  137. }
  138. type_offset = size;
  139. /* Make room to copy the arg_types */
  140. size += sizeof(ffi_type *) * numargs;
  141. if (size % align != 0)
  142. {
  143. size += align - (size % align);
  144. }
  145. offset = size;
  146. size += numargs * sizeof(void*);
  147. if (size % align != 0)
  148. {
  149. size += (align - (size % align));
  150. }
  151. for (i = 0; i < numargs; i++)
  152. {
  153. if (arg_types[i]->elements)
  154. size += cifframe_guess_struct_size(arg_types[i]);
  155. else
  156. size += arg_types[i]->size;
  157. if (size % align != 0)
  158. {
  159. size += (align - size % align);
  160. }
  161. }
  162. }
  163. result = [NSMutableData dataWithCapacity: size];
  164. [result setLength: size];
  165. cframe = buf = [result mutableBytes];
  166. if (cframe)
  167. {
  168. cframe->nargs = numargs;
  169. cframe->arg_types = buf + type_offset;
  170. memcpy(cframe->arg_types, arg_types, sizeof(ffi_type *) * numargs);
  171. cframe->values = buf + offset;
  172. if (ffi_prep_cif (&cframe->cif, FFI_DEFAULT_ABI, cframe->nargs,
  173. rtype, cframe->arg_types) != FFI_OK)
  174. {
  175. cframe = NULL;
  176. result = NULL;
  177. }
  178. else
  179. {
  180. /* Set values locations. This must be done after ffi_prep_cif so
  181. that any structure sizes get calculated first. */
  182. offset += numargs * sizeof(void*);
  183. if (offset % align != 0)
  184. {
  185. offset += align - (offset % align);
  186. }
  187. for (i = 0; i < cframe->nargs; i++)
  188. {
  189. cframe->values[i] = buf + offset;
  190. offset += arg_types[i]->size;
  191. if (offset % align != 0)
  192. {
  193. offset += (align - offset % align);
  194. }
  195. }
  196. }
  197. }
  198. return result;
  199. }
  200. void
  201. cifframe_set_arg(cifframe_t *cframe, int index, void *buffer, int size)
  202. {
  203. if (index < 0 || index >= cframe->nargs)
  204. return;
  205. memcpy(cframe->values[index], buffer, size);
  206. }
  207. void
  208. cifframe_get_arg(cifframe_t *cframe, int index, void *buffer, int size)
  209. {
  210. if (index < 0 || index >= cframe->nargs)
  211. return;
  212. memcpy(buffer, cframe->values[index], size);
  213. }
  214. void *
  215. cifframe_arg_addr(cifframe_t *cframe, int index)
  216. {
  217. if (index < 0 || index >= cframe->nargs)
  218. return NULL;
  219. return cframe->values[index];
  220. }
  221. /*
  222. * Get the ffi_type for this type
  223. */
  224. ffi_type *
  225. cifframe_type(const char *typePtr, const char **advance)
  226. {
  227. const char *type;
  228. ffi_type *ftype;
  229. typePtr = objc_skip_type_qualifiers (typePtr);
  230. type = typePtr;
  231. /*
  232. * Scan for size and alignment information.
  233. */
  234. switch (*typePtr++)
  235. {
  236. case _C_ID: ftype = &ffi_type_pointer;
  237. break;
  238. case _C_CLASS: ftype = &ffi_type_pointer;
  239. break;
  240. case _C_SEL: ftype = &ffi_type_pointer;
  241. break;
  242. case _C_CHR: ftype = &ffi_type_schar;
  243. break;
  244. case _C_UCHR: ftype = &ffi_type_uchar;
  245. break;
  246. case _C_SHT: ftype = &gsffi_type_sshort;
  247. break;
  248. case _C_USHT: ftype = &gsffi_type_ushort;
  249. break;
  250. case _C_INT: ftype = &gsffi_type_sint;
  251. break;
  252. case _C_UINT: ftype = &gsffi_type_uint;
  253. break;
  254. case _C_LNG: ftype = &gsffi_type_slong;
  255. break;
  256. case _C_ULNG: ftype = &gsffi_type_ulong;
  257. break;
  258. #ifdef _C_LNG_LNG
  259. case _C_LNG_LNG: ftype = &gsffi_type_slong_long;
  260. break;
  261. case _C_ULNG_LNG: ftype = &gsffi_type_ulong_long;
  262. break;
  263. #endif
  264. case _C_FLT: ftype = &ffi_type_float;
  265. break;
  266. case _C_DBL: ftype = &ffi_type_double;
  267. break;
  268. case _C_PTR:
  269. ftype = &ffi_type_pointer;
  270. if (*typePtr == '?')
  271. {
  272. typePtr++;
  273. }
  274. else
  275. {
  276. const char *adv;
  277. cifframe_type(typePtr, &adv);
  278. typePtr = adv;
  279. }
  280. break;
  281. case _C_ATOM:
  282. case _C_CHARPTR:
  283. ftype = &ffi_type_pointer;
  284. break;
  285. case _C_ARY_B:
  286. {
  287. const char *adv;
  288. ftype = &ffi_type_pointer;
  289. while (isdigit(*typePtr))
  290. {
  291. typePtr++;
  292. }
  293. cifframe_type(typePtr, &adv);
  294. typePtr = adv;
  295. typePtr++; /* Skip end-of-array */
  296. }
  297. break;
  298. case _C_STRUCT_B:
  299. {
  300. int types, maxtypes, size;
  301. ffi_type *local;
  302. const char *adv;
  303. unsigned align = __alignof(double);
  304. /* Standard structures can be handled using cached type information.
  305. Since the switch statement has already skipped the _C_STRUCT_B
  306. character, we must use typePtr-1 below to successfully match the
  307. type encoding with one of the standard type encodings. The same
  308. holds for skipping past the whole structure type's encoding with
  309. objc_skip_typespec.
  310. */
  311. if (GSSelectorTypesMatch(typePtr - 1, @encode(NSRange)))
  312. {
  313. static ffi_type *elems[3];
  314. static ffi_type stype = { 0 };
  315. if (stype.type == 0)
  316. {
  317. const char *t = @encode(NSUInteger);
  318. if (*t == _C_ULNG)
  319. {
  320. elems[0] = &gsffi_type_ulong;
  321. }
  322. #ifdef _C_LNG_LNG
  323. else if (*t == _C_ULNG_LNG)
  324. {
  325. elems[0] = &gsffi_type_ulong_long;
  326. }
  327. #endif
  328. else
  329. {
  330. elems[0] = &gsffi_type_uint;
  331. }
  332. elems[1] = elems[0];
  333. elems[2] = 0;
  334. stype.elements = elems;
  335. stype.type = FFI_TYPE_STRUCT;
  336. }
  337. ftype = &stype;
  338. typePtr = objc_skip_typespec (typePtr - 1);
  339. break;
  340. }
  341. else if (GSSelectorTypesMatch(typePtr - 1, @encode(NSSize)))
  342. {
  343. static ffi_type *elems[3];
  344. static ffi_type stype = { 0 };
  345. if (stype.type == 0)
  346. {
  347. if (*@encode(CGFloat) == _C_DBL)
  348. {
  349. elems[0] = &ffi_type_double;
  350. }
  351. else
  352. {
  353. elems[0] = &ffi_type_float;
  354. }
  355. elems[1] = elems[0];
  356. elems[2] = 0;
  357. stype.elements = elems;
  358. stype.type = FFI_TYPE_STRUCT;
  359. }
  360. ftype = &stype;
  361. typePtr = objc_skip_typespec (typePtr - 1);
  362. break;
  363. }
  364. else if (GSSelectorTypesMatch(typePtr - 1, @encode(NSRect)))
  365. {
  366. static ffi_type *elems[3];
  367. static ffi_type stype = { 0 };
  368. if (stype.type == 0)
  369. {
  370. /* An NSRect is an NSPoint and an NSSize, but those
  371. * two structures are actually identical.
  372. */
  373. elems[0] = cifframe_type(@encode(NSSize), NULL);
  374. elems[1] = elems[0];
  375. elems[2] = 0;
  376. stype.elements = elems;
  377. stype.type = FFI_TYPE_STRUCT;
  378. }
  379. ftype = &stype;
  380. typePtr = objc_skip_typespec (typePtr - 1);
  381. break;
  382. }
  383. /*
  384. * Skip "<name>=" stuff.
  385. */
  386. while (*typePtr != _C_STRUCT_E)
  387. {
  388. if (*typePtr++ == '=')
  389. {
  390. break;
  391. }
  392. }
  393. types = 0;
  394. maxtypes = 4;
  395. size = sizeof(ffi_type);
  396. if (size % align != 0)
  397. {
  398. size += (align - (size % align));
  399. }
  400. ftype = malloc(size + (maxtypes+1)*sizeof(ffi_type));
  401. ftype->size = 0;
  402. ftype->alignment = 0;
  403. ftype->type = FFI_TYPE_STRUCT;
  404. ftype->elements = (void*)ftype + size;
  405. /*
  406. * Continue accumulating structure size.
  407. */
  408. while (*typePtr != _C_STRUCT_E)
  409. {
  410. local = cifframe_type(typePtr, &adv);
  411. typePtr = adv;
  412. NSCAssert(typePtr, @"End of signature while parsing");
  413. ftype->elements[types++] = local;
  414. if (types >= maxtypes)
  415. {
  416. maxtypes *=2;
  417. ftype = realloc(ftype,
  418. size + (maxtypes+1)*sizeof(ffi_type));
  419. ftype->elements = (void*)ftype + size;
  420. }
  421. }
  422. ftype->elements[types] = NULL;
  423. typePtr++; /* Skip end-of-struct */
  424. }
  425. break;
  426. case _C_UNION_B:
  427. {
  428. const char *adv;
  429. int max_align = 0;
  430. /*
  431. * Skip "<name>=" stuff.
  432. */
  433. while (*typePtr != _C_UNION_E)
  434. {
  435. if (*typePtr++ == '=')
  436. {
  437. break;
  438. }
  439. }
  440. ftype = NULL;
  441. while (*typePtr != _C_UNION_E)
  442. {
  443. ffi_type *local;
  444. int align = objc_alignof_type(typePtr);
  445. local = cifframe_type(typePtr, &adv);
  446. typePtr = adv;
  447. NSCAssert(typePtr, @"End of signature while parsing");
  448. if (align > max_align)
  449. {
  450. if (ftype && ftype->type == FFI_TYPE_STRUCT)
  451. free(ftype);
  452. ftype = local;
  453. max_align = align;
  454. }
  455. }
  456. typePtr++; /* Skip end-of-union */
  457. }
  458. break;
  459. case _C_VOID: ftype = &ffi_type_void;
  460. break;
  461. default:
  462. ftype = &ffi_type_void;
  463. NSCAssert(0, @"Unknown type in sig");
  464. }
  465. /* Skip past any offset information, if there is any */
  466. if (*type != _C_PTR || *type == '?')
  467. {
  468. if (*typePtr == '+')
  469. typePtr++;
  470. if (*typePtr == '-')
  471. typePtr++;
  472. while (isdigit(*typePtr))
  473. typePtr++;
  474. }
  475. if (advance)
  476. *advance = typePtr;
  477. return ftype;
  478. }
  479. /*-------------------------------------------------------------------------*/
  480. /* Functions for handling sending and receiving messages accross a
  481. connection
  482. */
  483. /* Some return types actually get coded differently. We need to convert
  484. back to the expected return type */
  485. BOOL
  486. cifframe_decode_arg (const char *type, void* buffer)
  487. {
  488. type = objc_skip_type_qualifiers (type);
  489. switch (*type)
  490. {
  491. case _C_CHR:
  492. case _C_UCHR:
  493. {
  494. *(unsigned char*)buffer = (unsigned char)(*((smallret_t *)buffer));
  495. break;
  496. }
  497. case _C_SHT:
  498. case _C_USHT:
  499. {
  500. *(unsigned short*)buffer = (unsigned short)(*((smallret_t *)buffer));
  501. break;
  502. }
  503. case _C_INT:
  504. case _C_UINT:
  505. {
  506. *(unsigned int*)buffer = (unsigned int)(*((smallret_t *)buffer));
  507. break;
  508. }
  509. default:
  510. return NO;
  511. }
  512. return YES;
  513. }
  514. BOOL
  515. cifframe_encode_arg (const char *type, void* buffer)
  516. {
  517. type = objc_skip_type_qualifiers (type);
  518. switch (*type)
  519. {
  520. case _C_CHR:
  521. case _C_UCHR:
  522. {
  523. *(smallret_t *)buffer = (smallret_t)(*((unsigned char *)buffer));
  524. break;
  525. }
  526. case _C_SHT:
  527. case _C_USHT:
  528. {
  529. *(smallret_t *)buffer = (smallret_t)(*((unsigned short *)buffer));
  530. break;
  531. }
  532. case _C_INT:
  533. case _C_UINT:
  534. {
  535. *(smallret_t *)buffer = (smallret_t)(*((unsigned int *)buffer));
  536. break;
  537. }
  538. default:
  539. return NO;
  540. }
  541. return YES;
  542. }