recompiler.py 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290
  1. import os, sys, io
  2. from . import ffiplatform, model
  3. from .cffi_opcode import *
  4. VERSION = "0x2601"
  5. class GlobalExpr:
  6. def __init__(self, name, address, type_op, size=0, check_value=0):
  7. self.name = name
  8. self.address = address
  9. self.type_op = type_op
  10. self.size = size
  11. self.check_value = check_value
  12. def as_c_expr(self):
  13. return ' { "%s", (void *)%s, %s, (void *)%s },' % (
  14. self.name, self.address, self.type_op.as_c_expr(), self.size)
  15. def as_python_expr(self):
  16. return "b'%s%s',%d" % (self.type_op.as_python_bytes(), self.name,
  17. self.check_value)
  18. class FieldExpr:
  19. def __init__(self, name, field_offset, field_size, fbitsize, field_type_op):
  20. self.name = name
  21. self.field_offset = field_offset
  22. self.field_size = field_size
  23. self.fbitsize = fbitsize
  24. self.field_type_op = field_type_op
  25. def as_c_expr(self):
  26. spaces = " " * len(self.name)
  27. return (' { "%s", %s,\n' % (self.name, self.field_offset) +
  28. ' %s %s,\n' % (spaces, self.field_size) +
  29. ' %s %s },' % (spaces, self.field_type_op.as_c_expr()))
  30. def as_python_expr(self):
  31. raise NotImplementedError
  32. def as_field_python_expr(self):
  33. if self.field_type_op.op == OP_NOOP:
  34. size_expr = ''
  35. elif self.field_type_op.op == OP_BITFIELD:
  36. size_expr = format_four_bytes(self.fbitsize)
  37. else:
  38. raise NotImplementedError
  39. return "b'%s%s%s'" % (self.field_type_op.as_python_bytes(),
  40. size_expr,
  41. self.name)
  42. class StructUnionExpr:
  43. def __init__(self, name, type_index, flags, size, alignment, comment,
  44. first_field_index, c_fields):
  45. self.name = name
  46. self.type_index = type_index
  47. self.flags = flags
  48. self.size = size
  49. self.alignment = alignment
  50. self.comment = comment
  51. self.first_field_index = first_field_index
  52. self.c_fields = c_fields
  53. def as_c_expr(self):
  54. return (' { "%s", %d, %s,' % (self.name, self.type_index, self.flags)
  55. + '\n %s, %s, ' % (self.size, self.alignment)
  56. + '%d, %d ' % (self.first_field_index, len(self.c_fields))
  57. + ('/* %s */ ' % self.comment if self.comment else '')
  58. + '},')
  59. def as_python_expr(self):
  60. flags = eval(self.flags, G_FLAGS)
  61. fields_expr = [c_field.as_field_python_expr()
  62. for c_field in self.c_fields]
  63. return "(b'%s%s%s',%s)" % (
  64. format_four_bytes(self.type_index),
  65. format_four_bytes(flags),
  66. self.name,
  67. ','.join(fields_expr))
  68. class EnumExpr:
  69. def __init__(self, name, type_index, size, signed, allenums):
  70. self.name = name
  71. self.type_index = type_index
  72. self.size = size
  73. self.signed = signed
  74. self.allenums = allenums
  75. def as_c_expr(self):
  76. return (' { "%s", %d, _cffi_prim_int(%s, %s),\n'
  77. ' "%s" },' % (self.name, self.type_index,
  78. self.size, self.signed, self.allenums))
  79. def as_python_expr(self):
  80. prim_index = {
  81. (1, 0): PRIM_UINT8, (1, 1): PRIM_INT8,
  82. (2, 0): PRIM_UINT16, (2, 1): PRIM_INT16,
  83. (4, 0): PRIM_UINT32, (4, 1): PRIM_INT32,
  84. (8, 0): PRIM_UINT64, (8, 1): PRIM_INT64,
  85. }[self.size, self.signed]
  86. return "b'%s%s%s\\x00%s'" % (format_four_bytes(self.type_index),
  87. format_four_bytes(prim_index),
  88. self.name, self.allenums)
  89. class TypenameExpr:
  90. def __init__(self, name, type_index):
  91. self.name = name
  92. self.type_index = type_index
  93. def as_c_expr(self):
  94. return ' { "%s", %d },' % (self.name, self.type_index)
  95. def as_python_expr(self):
  96. return "b'%s%s'" % (format_four_bytes(self.type_index), self.name)
  97. # ____________________________________________________________
  98. class Recompiler:
  99. def __init__(self, ffi, module_name, target_is_python=False):
  100. self.ffi = ffi
  101. self.module_name = module_name
  102. self.target_is_python = target_is_python
  103. def collect_type_table(self):
  104. self._typesdict = {}
  105. self._generate("collecttype")
  106. #
  107. all_decls = sorted(self._typesdict, key=str)
  108. #
  109. # prepare all FUNCTION bytecode sequences first
  110. self.cffi_types = []
  111. for tp in all_decls:
  112. if tp.is_raw_function:
  113. assert self._typesdict[tp] is None
  114. self._typesdict[tp] = len(self.cffi_types)
  115. self.cffi_types.append(tp) # placeholder
  116. for tp1 in tp.args:
  117. assert isinstance(tp1, (model.VoidType,
  118. model.BasePrimitiveType,
  119. model.PointerType,
  120. model.StructOrUnionOrEnum,
  121. model.FunctionPtrType))
  122. if self._typesdict[tp1] is None:
  123. self._typesdict[tp1] = len(self.cffi_types)
  124. self.cffi_types.append(tp1) # placeholder
  125. self.cffi_types.append('END') # placeholder
  126. #
  127. # prepare all OTHER bytecode sequences
  128. for tp in all_decls:
  129. if not tp.is_raw_function and self._typesdict[tp] is None:
  130. self._typesdict[tp] = len(self.cffi_types)
  131. self.cffi_types.append(tp) # placeholder
  132. if tp.is_array_type and tp.length is not None:
  133. self.cffi_types.append('LEN') # placeholder
  134. assert None not in self._typesdict.values()
  135. #
  136. # collect all structs and unions and enums
  137. self._struct_unions = {}
  138. self._enums = {}
  139. for tp in all_decls:
  140. if isinstance(tp, model.StructOrUnion):
  141. self._struct_unions[tp] = None
  142. elif isinstance(tp, model.EnumType):
  143. self._enums[tp] = None
  144. for i, tp in enumerate(sorted(self._struct_unions,
  145. key=lambda tp: tp.name)):
  146. self._struct_unions[tp] = i
  147. for i, tp in enumerate(sorted(self._enums,
  148. key=lambda tp: tp.name)):
  149. self._enums[tp] = i
  150. #
  151. # emit all bytecode sequences now
  152. for tp in all_decls:
  153. method = getattr(self, '_emit_bytecode_' + tp.__class__.__name__)
  154. method(tp, self._typesdict[tp])
  155. #
  156. # consistency check
  157. for op in self.cffi_types:
  158. assert isinstance(op, CffiOp)
  159. self.cffi_types = tuple(self.cffi_types) # don't change any more
  160. def _do_collect_type(self, tp):
  161. if not isinstance(tp, model.BaseTypeByIdentity):
  162. if isinstance(tp, tuple):
  163. for x in tp:
  164. self._do_collect_type(x)
  165. return
  166. if tp not in self._typesdict:
  167. self._typesdict[tp] = None
  168. if isinstance(tp, model.FunctionPtrType):
  169. self._do_collect_type(tp.as_raw_function())
  170. elif isinstance(tp, model.StructOrUnion):
  171. if tp.fldtypes is not None and (
  172. tp not in self.ffi._parser._included_declarations):
  173. for name1, tp1, _, _ in tp.enumfields():
  174. self._do_collect_type(self._field_type(tp, name1, tp1))
  175. else:
  176. for _, x in tp._get_items():
  177. self._do_collect_type(x)
  178. def _generate(self, step_name):
  179. lst = self.ffi._parser._declarations.items()
  180. for name, (tp, quals) in sorted(lst):
  181. kind, realname = name.split(' ', 1)
  182. try:
  183. method = getattr(self, '_generate_cpy_%s_%s' % (kind,
  184. step_name))
  185. except AttributeError:
  186. raise ffiplatform.VerificationError(
  187. "not implemented in recompile(): %r" % name)
  188. try:
  189. self._current_quals = quals
  190. method(tp, realname)
  191. except Exception as e:
  192. model.attach_exception_info(e, name)
  193. raise
  194. # ----------
  195. ALL_STEPS = ["global", "field", "struct_union", "enum", "typename"]
  196. def collect_step_tables(self):
  197. # collect the declarations for '_cffi_globals', '_cffi_typenames', etc.
  198. self._lsts = {}
  199. for step_name in self.ALL_STEPS:
  200. self._lsts[step_name] = []
  201. self._seen_struct_unions = set()
  202. self._generate("ctx")
  203. self._add_missing_struct_unions()
  204. #
  205. for step_name in self.ALL_STEPS:
  206. lst = self._lsts[step_name]
  207. if step_name != "field":
  208. lst.sort(key=lambda entry: entry.name)
  209. self._lsts[step_name] = tuple(lst) # don't change any more
  210. #
  211. # check for a possible internal inconsistency: _cffi_struct_unions
  212. # should have been generated with exactly self._struct_unions
  213. lst = self._lsts["struct_union"]
  214. for tp, i in self._struct_unions.items():
  215. assert i < len(lst)
  216. assert lst[i].name == tp.name
  217. assert len(lst) == len(self._struct_unions)
  218. # same with enums
  219. lst = self._lsts["enum"]
  220. for tp, i in self._enums.items():
  221. assert i < len(lst)
  222. assert lst[i].name == tp.name
  223. assert len(lst) == len(self._enums)
  224. # ----------
  225. def _prnt(self, what=''):
  226. self._f.write(what + '\n')
  227. def write_source_to_f(self, f, preamble):
  228. if self.target_is_python:
  229. assert preamble is None
  230. self.write_py_source_to_f(f)
  231. else:
  232. assert preamble is not None
  233. self.write_c_source_to_f(f, preamble)
  234. def _rel_readlines(self, filename):
  235. g = open(os.path.join(os.path.dirname(__file__), filename), 'r')
  236. lines = g.readlines()
  237. g.close()
  238. return lines
  239. def write_c_source_to_f(self, f, preamble):
  240. self._f = f
  241. prnt = self._prnt
  242. #
  243. # first the '#include' (actually done by inlining the file's content)
  244. lines = self._rel_readlines('_cffi_include.h')
  245. i = lines.index('#include "parse_c_type.h"\n')
  246. lines[i:i+1] = self._rel_readlines('parse_c_type.h')
  247. prnt(''.join(lines))
  248. #
  249. # then paste the C source given by the user, verbatim.
  250. prnt('/************************************************************/')
  251. prnt()
  252. prnt(preamble)
  253. prnt()
  254. prnt('/************************************************************/')
  255. prnt()
  256. #
  257. # the declaration of '_cffi_types'
  258. prnt('static void *_cffi_types[] = {')
  259. typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()])
  260. for i, op in enumerate(self.cffi_types):
  261. comment = ''
  262. if i in typeindex2type:
  263. comment = ' // ' + typeindex2type[i]._get_c_name()
  264. prnt('/* %2d */ %s,%s' % (i, op.as_c_expr(), comment))
  265. if not self.cffi_types:
  266. prnt(' 0')
  267. prnt('};')
  268. prnt()
  269. #
  270. # call generate_cpy_xxx_decl(), for every xxx found from
  271. # ffi._parser._declarations. This generates all the functions.
  272. self._seen_constants = set()
  273. self._generate("decl")
  274. #
  275. # the declaration of '_cffi_globals' and '_cffi_typenames'
  276. nums = {}
  277. for step_name in self.ALL_STEPS:
  278. lst = self._lsts[step_name]
  279. nums[step_name] = len(lst)
  280. if nums[step_name] > 0:
  281. prnt('static const struct _cffi_%s_s _cffi_%ss[] = {' % (
  282. step_name, step_name))
  283. for entry in lst:
  284. prnt(entry.as_c_expr())
  285. prnt('};')
  286. prnt()
  287. #
  288. # the declaration of '_cffi_includes'
  289. if self.ffi._included_ffis:
  290. prnt('static const char * const _cffi_includes[] = {')
  291. for ffi_to_include in self.ffi._included_ffis:
  292. try:
  293. included_module_name, included_source = (
  294. ffi_to_include._assigned_source[:2])
  295. except AttributeError:
  296. raise ffiplatform.VerificationError(
  297. "ffi object %r includes %r, but the latter has not "
  298. "been prepared with set_source()" % (
  299. self.ffi, ffi_to_include,))
  300. if included_source is None:
  301. raise ffiplatform.VerificationError(
  302. "not implemented yet: ffi.include() of a Python-based "
  303. "ffi inside a C-based ffi")
  304. prnt(' "%s",' % (included_module_name,))
  305. prnt(' NULL')
  306. prnt('};')
  307. prnt()
  308. #
  309. # the declaration of '_cffi_type_context'
  310. prnt('static const struct _cffi_type_context_s _cffi_type_context = {')
  311. prnt(' _cffi_types,')
  312. for step_name in self.ALL_STEPS:
  313. if nums[step_name] > 0:
  314. prnt(' _cffi_%ss,' % step_name)
  315. else:
  316. prnt(' NULL, /* no %ss */' % step_name)
  317. for step_name in self.ALL_STEPS:
  318. if step_name != "field":
  319. prnt(' %d, /* num_%ss */' % (nums[step_name], step_name))
  320. if self.ffi._included_ffis:
  321. prnt(' _cffi_includes,')
  322. else:
  323. prnt(' NULL, /* no includes */')
  324. prnt(' %d, /* num_types */' % (len(self.cffi_types),))
  325. prnt(' 0, /* flags */')
  326. prnt('};')
  327. prnt()
  328. #
  329. # the init function
  330. base_module_name = self.module_name.split('.')[-1]
  331. prnt('#ifdef PYPY_VERSION')
  332. prnt('PyMODINIT_FUNC')
  333. prnt('_cffi_pypyinit_%s(const void *p[])' % (base_module_name,))
  334. prnt('{')
  335. prnt(' p[0] = (const void *)%s;' % VERSION)
  336. prnt(' p[1] = &_cffi_type_context;')
  337. prnt('}')
  338. # on Windows, distutils insists on putting init_cffi_xyz in
  339. # 'export_symbols', so instead of fighting it, just give up and
  340. # give it one
  341. prnt('# ifdef _MSC_VER')
  342. prnt(' PyMODINIT_FUNC')
  343. prnt('# if PY_MAJOR_VERSION >= 3')
  344. prnt(' PyInit_%s(void) { return NULL; }' % (base_module_name,))
  345. prnt('# else')
  346. prnt(' init%s(void) { }' % (base_module_name,))
  347. prnt('# endif')
  348. prnt('# endif')
  349. prnt('#elif PY_MAJOR_VERSION >= 3')
  350. prnt('PyMODINIT_FUNC')
  351. prnt('PyInit_%s(void)' % (base_module_name,))
  352. prnt('{')
  353. prnt(' return _cffi_init("%s", %s, &_cffi_type_context);' % (
  354. self.module_name, VERSION))
  355. prnt('}')
  356. prnt('#else')
  357. prnt('PyMODINIT_FUNC')
  358. prnt('init%s(void)' % (base_module_name,))
  359. prnt('{')
  360. prnt(' _cffi_init("%s", %s, &_cffi_type_context);' % (
  361. self.module_name, VERSION))
  362. prnt('}')
  363. prnt('#endif')
  364. def _to_py(self, x):
  365. if isinstance(x, str):
  366. return "b'%s'" % (x,)
  367. if isinstance(x, (list, tuple)):
  368. rep = [self._to_py(item) for item in x]
  369. if len(rep) == 1:
  370. rep.append('')
  371. return "(%s)" % (','.join(rep),)
  372. return x.as_python_expr() # Py2: unicode unexpected; Py3: bytes unexp.
  373. def write_py_source_to_f(self, f):
  374. self._f = f
  375. prnt = self._prnt
  376. #
  377. # header
  378. prnt("# auto-generated file")
  379. prnt("import _cffi_backend")
  380. #
  381. # the 'import' of the included ffis
  382. num_includes = len(self.ffi._included_ffis or ())
  383. for i in range(num_includes):
  384. ffi_to_include = self.ffi._included_ffis[i]
  385. try:
  386. included_module_name, included_source = (
  387. ffi_to_include._assigned_source[:2])
  388. except AttributeError:
  389. raise ffiplatform.VerificationError(
  390. "ffi object %r includes %r, but the latter has not "
  391. "been prepared with set_source()" % (
  392. self.ffi, ffi_to_include,))
  393. if included_source is not None:
  394. raise ffiplatform.VerificationError(
  395. "not implemented yet: ffi.include() of a C-based "
  396. "ffi inside a Python-based ffi")
  397. prnt('from %s import ffi as _ffi%d' % (included_module_name, i))
  398. prnt()
  399. prnt("ffi = _cffi_backend.FFI('%s'," % (self.module_name,))
  400. prnt(" _version = %s," % (VERSION,))
  401. #
  402. # the '_types' keyword argument
  403. self.cffi_types = tuple(self.cffi_types) # don't change any more
  404. types_lst = [op.as_python_bytes() for op in self.cffi_types]
  405. prnt(' _types = %s,' % (self._to_py(''.join(types_lst)),))
  406. typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()])
  407. #
  408. # the keyword arguments from ALL_STEPS
  409. for step_name in self.ALL_STEPS:
  410. lst = self._lsts[step_name]
  411. if len(lst) > 0 and step_name != "field":
  412. prnt(' _%ss = %s,' % (step_name, self._to_py(lst)))
  413. #
  414. # the '_includes' keyword argument
  415. if num_includes > 0:
  416. prnt(' _includes = (%s,),' % (
  417. ', '.join(['_ffi%d' % i for i in range(num_includes)]),))
  418. #
  419. # the footer
  420. prnt(')')
  421. # ----------
  422. def _gettypenum(self, type):
  423. # a KeyError here is a bug. please report it! :-)
  424. return self._typesdict[type]
  425. def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode):
  426. extraarg = ''
  427. if isinstance(tp, model.BasePrimitiveType):
  428. if tp.is_integer_type() and tp.name != '_Bool':
  429. converter = '_cffi_to_c_int'
  430. extraarg = ', %s' % tp.name
  431. elif isinstance(tp, model.UnknownFloatType):
  432. # don't check with is_float_type(): it may be a 'long
  433. # double' here, and _cffi_to_c_double would loose precision
  434. converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),)
  435. else:
  436. converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''),
  437. tp.name.replace(' ', '_'))
  438. errvalue = '-1'
  439. #
  440. elif isinstance(tp, model.PointerType):
  441. self._convert_funcarg_to_c_ptr_or_array(tp, fromvar,
  442. tovar, errcode)
  443. return
  444. #
  445. elif isinstance(tp, (model.StructOrUnion, model.EnumType)):
  446. # a struct (not a struct pointer) as a function argument
  447. self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)'
  448. % (tovar, self._gettypenum(tp), fromvar))
  449. self._prnt(' %s;' % errcode)
  450. return
  451. #
  452. elif isinstance(tp, model.FunctionPtrType):
  453. converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('')
  454. extraarg = ', _cffi_type(%d)' % self._gettypenum(tp)
  455. errvalue = 'NULL'
  456. #
  457. else:
  458. raise NotImplementedError(tp)
  459. #
  460. self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg))
  461. self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % (
  462. tovar, tp.get_c_name(''), errvalue))
  463. self._prnt(' %s;' % errcode)
  464. def _extra_local_variables(self, tp, localvars):
  465. if isinstance(tp, model.PointerType):
  466. localvars.add('Py_ssize_t datasize')
  467. def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode):
  468. self._prnt(' datasize = _cffi_prepare_pointer_call_argument(')
  469. self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % (
  470. self._gettypenum(tp), fromvar, tovar))
  471. self._prnt(' if (datasize != 0) {')
  472. self._prnt(' if (datasize < 0)')
  473. self._prnt(' %s;' % errcode)
  474. self._prnt(' %s = (%s)alloca((size_t)datasize);' % (
  475. tovar, tp.get_c_name('')))
  476. self._prnt(' memset((void *)%s, 0, (size_t)datasize);' % (tovar,))
  477. self._prnt(' if (_cffi_convert_array_from_object('
  478. '(char *)%s, _cffi_type(%d), %s) < 0)' % (
  479. tovar, self._gettypenum(tp), fromvar))
  480. self._prnt(' %s;' % errcode)
  481. self._prnt(' }')
  482. def _convert_expr_from_c(self, tp, var, context):
  483. if isinstance(tp, model.BasePrimitiveType):
  484. if tp.is_integer_type():
  485. return '_cffi_from_c_int(%s, %s)' % (var, tp.name)
  486. elif isinstance(tp, model.UnknownFloatType):
  487. return '_cffi_from_c_double(%s)' % (var,)
  488. elif tp.name != 'long double':
  489. return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var)
  490. else:
  491. return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
  492. var, self._gettypenum(tp))
  493. elif isinstance(tp, (model.PointerType, model.FunctionPtrType)):
  494. return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
  495. var, self._gettypenum(tp))
  496. elif isinstance(tp, model.ArrayType):
  497. return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
  498. var, self._gettypenum(model.PointerType(tp.item)))
  499. elif isinstance(tp, model.StructType):
  500. if tp.fldnames is None:
  501. raise TypeError("'%s' is used as %s, but is opaque" % (
  502. tp._get_c_name(), context))
  503. return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % (
  504. var, self._gettypenum(tp))
  505. elif isinstance(tp, model.EnumType):
  506. return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
  507. var, self._gettypenum(tp))
  508. else:
  509. raise NotImplementedError(tp)
  510. # ----------
  511. # typedefs
  512. def _generate_cpy_typedef_collecttype(self, tp, name):
  513. self._do_collect_type(tp)
  514. def _generate_cpy_typedef_decl(self, tp, name):
  515. pass
  516. def _typedef_ctx(self, tp, name):
  517. type_index = self._typesdict[tp]
  518. self._lsts["typename"].append(TypenameExpr(name, type_index))
  519. def _generate_cpy_typedef_ctx(self, tp, name):
  520. self._typedef_ctx(tp, name)
  521. if getattr(tp, "origin", None) == "unknown_type":
  522. self._struct_ctx(tp, tp.name, approxname=None)
  523. elif isinstance(tp, model.NamedPointerType):
  524. self._struct_ctx(tp.totype, tp.totype.name, approxname=tp.name,
  525. named_ptr=tp)
  526. # ----------
  527. # function declarations
  528. def _generate_cpy_function_collecttype(self, tp, name):
  529. self._do_collect_type(tp.as_raw_function())
  530. if tp.ellipsis and not self.target_is_python:
  531. self._do_collect_type(tp)
  532. def _generate_cpy_function_decl(self, tp, name):
  533. assert not self.target_is_python
  534. assert isinstance(tp, model.FunctionPtrType)
  535. if tp.ellipsis:
  536. # cannot support vararg functions better than this: check for its
  537. # exact type (including the fixed arguments), and build it as a
  538. # constant function pointer (no CPython wrapper)
  539. self._generate_cpy_constant_decl(tp, name)
  540. return
  541. prnt = self._prnt
  542. numargs = len(tp.args)
  543. if numargs == 0:
  544. argname = 'noarg'
  545. elif numargs == 1:
  546. argname = 'arg0'
  547. else:
  548. argname = 'args'
  549. #
  550. # ------------------------------
  551. # the 'd' version of the function, only for addressof(lib, 'func')
  552. arguments = []
  553. call_arguments = []
  554. context = 'argument of %s' % name
  555. for i, type in enumerate(tp.args):
  556. arguments.append(type.get_c_name(' x%d' % i, context))
  557. call_arguments.append('x%d' % i)
  558. repr_arguments = ', '.join(arguments)
  559. repr_arguments = repr_arguments or 'void'
  560. if tp.abi:
  561. abi = tp.abi + ' '
  562. else:
  563. abi = ''
  564. name_and_arguments = '%s_cffi_d_%s(%s)' % (abi, name, repr_arguments)
  565. prnt('static %s' % (tp.result.get_c_name(name_and_arguments),))
  566. prnt('{')
  567. call_arguments = ', '.join(call_arguments)
  568. result_code = 'return '
  569. if isinstance(tp.result, model.VoidType):
  570. result_code = ''
  571. prnt(' %s%s(%s);' % (result_code, name, call_arguments))
  572. prnt('}')
  573. #
  574. prnt('#ifndef PYPY_VERSION') # ------------------------------
  575. #
  576. prnt('static PyObject *')
  577. prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname))
  578. prnt('{')
  579. #
  580. context = 'argument of %s' % name
  581. for i, type in enumerate(tp.args):
  582. arg = type.get_c_name(' x%d' % i, context)
  583. prnt(' %s;' % arg)
  584. #
  585. localvars = set()
  586. for type in tp.args:
  587. self._extra_local_variables(type, localvars)
  588. for decl in localvars:
  589. prnt(' %s;' % (decl,))
  590. #
  591. if not isinstance(tp.result, model.VoidType):
  592. result_code = 'result = '
  593. context = 'result of %s' % name
  594. result_decl = ' %s;' % tp.result.get_c_name(' result', context)
  595. prnt(result_decl)
  596. else:
  597. result_decl = None
  598. result_code = ''
  599. #
  600. if len(tp.args) > 1:
  601. rng = range(len(tp.args))
  602. for i in rng:
  603. prnt(' PyObject *arg%d;' % i)
  604. prnt(' PyObject **aa;')
  605. prnt()
  606. prnt(' aa = _cffi_unpack_args(args, %d, "%s");' % (len(rng), name))
  607. prnt(' if (aa == NULL)')
  608. prnt(' return NULL;')
  609. for i in rng:
  610. prnt(' arg%d = aa[%d];' % (i, i))
  611. prnt()
  612. #
  613. for i, type in enumerate(tp.args):
  614. self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i,
  615. 'return NULL')
  616. prnt()
  617. #
  618. prnt(' Py_BEGIN_ALLOW_THREADS')
  619. prnt(' _cffi_restore_errno();')
  620. call_arguments = ['x%d' % i for i in range(len(tp.args))]
  621. call_arguments = ', '.join(call_arguments)
  622. prnt(' { %s%s(%s); }' % (result_code, name, call_arguments))
  623. prnt(' _cffi_save_errno();')
  624. prnt(' Py_END_ALLOW_THREADS')
  625. prnt()
  626. #
  627. prnt(' (void)self; /* unused */')
  628. if numargs == 0:
  629. prnt(' (void)noarg; /* unused */')
  630. if result_code:
  631. prnt(' return %s;' %
  632. self._convert_expr_from_c(tp.result, 'result', 'result type'))
  633. else:
  634. prnt(' Py_INCREF(Py_None);')
  635. prnt(' return Py_None;')
  636. prnt('}')
  637. #
  638. prnt('#else') # ------------------------------
  639. #
  640. # the PyPy version: need to replace struct/union arguments with
  641. # pointers, and if the result is a struct/union, insert a first
  642. # arg that is a pointer to the result.
  643. difference = False
  644. arguments = []
  645. call_arguments = []
  646. context = 'argument of %s' % name
  647. for i, type in enumerate(tp.args):
  648. indirection = ''
  649. if isinstance(type, model.StructOrUnion):
  650. indirection = '*'
  651. difference = True
  652. arg = type.get_c_name(' %sx%d' % (indirection, i), context)
  653. arguments.append(arg)
  654. call_arguments.append('%sx%d' % (indirection, i))
  655. tp_result = tp.result
  656. if isinstance(tp_result, model.StructOrUnion):
  657. context = 'result of %s' % name
  658. arg = tp_result.get_c_name(' *result', context)
  659. arguments.insert(0, arg)
  660. tp_result = model.void_type
  661. result_decl = None
  662. result_code = '*result = '
  663. difference = True
  664. if difference:
  665. repr_arguments = ', '.join(arguments)
  666. repr_arguments = repr_arguments or 'void'
  667. name_and_arguments = '%s_cffi_f_%s(%s)' % (abi, name,
  668. repr_arguments)
  669. prnt('static %s' % (tp_result.get_c_name(name_and_arguments),))
  670. prnt('{')
  671. if result_decl:
  672. prnt(result_decl)
  673. call_arguments = ', '.join(call_arguments)
  674. prnt(' { %s%s(%s); }' % (result_code, name, call_arguments))
  675. if result_decl:
  676. prnt(' return result;')
  677. prnt('}')
  678. else:
  679. prnt('# define _cffi_f_%s _cffi_d_%s' % (name, name))
  680. #
  681. prnt('#endif') # ------------------------------
  682. prnt()
  683. def _generate_cpy_function_ctx(self, tp, name):
  684. if tp.ellipsis and not self.target_is_python:
  685. self._generate_cpy_constant_ctx(tp, name)
  686. return
  687. type_index = self._typesdict[tp.as_raw_function()]
  688. numargs = len(tp.args)
  689. if self.target_is_python:
  690. meth_kind = OP_DLOPEN_FUNC
  691. elif numargs == 0:
  692. meth_kind = OP_CPYTHON_BLTN_N # 'METH_NOARGS'
  693. elif numargs == 1:
  694. meth_kind = OP_CPYTHON_BLTN_O # 'METH_O'
  695. else:
  696. meth_kind = OP_CPYTHON_BLTN_V # 'METH_VARARGS'
  697. self._lsts["global"].append(
  698. GlobalExpr(name, '_cffi_f_%s' % name,
  699. CffiOp(meth_kind, type_index),
  700. size='_cffi_d_%s' % name))
  701. # ----------
  702. # named structs or unions
  703. def _field_type(self, tp_struct, field_name, tp_field):
  704. if isinstance(tp_field, model.ArrayType):
  705. actual_length = tp_field.length
  706. if actual_length == '...':
  707. ptr_struct_name = tp_struct.get_c_name('*')
  708. actual_length = '_cffi_array_len(((%s)0)->%s)' % (
  709. ptr_struct_name, field_name)
  710. tp_item = self._field_type(tp_struct, '%s[0]' % field_name,
  711. tp_field.item)
  712. tp_field = model.ArrayType(tp_item, actual_length)
  713. return tp_field
  714. def _struct_collecttype(self, tp):
  715. self._do_collect_type(tp)
  716. def _struct_decl(self, tp, cname, approxname):
  717. if tp.fldtypes is None:
  718. return
  719. prnt = self._prnt
  720. checkfuncname = '_cffi_checkfld_%s' % (approxname,)
  721. prnt('_CFFI_UNUSED_FN')
  722. prnt('static void %s(%s *p)' % (checkfuncname, cname))
  723. prnt('{')
  724. prnt(' /* only to generate compile-time warnings or errors */')
  725. prnt(' (void)p;')
  726. for fname, ftype, fbitsize, fqual in tp.enumfields():
  727. try:
  728. if ftype.is_integer_type() or fbitsize >= 0:
  729. # accept all integers, but complain on float or double
  730. prnt(" (void)((p->%s) << 1); /* check that '%s.%s' is "
  731. "an integer */" % (fname, cname, fname))
  732. continue
  733. # only accept exactly the type declared, except that '[]'
  734. # is interpreted as a '*' and so will match any array length.
  735. # (It would also match '*', but that's harder to detect...)
  736. while (isinstance(ftype, model.ArrayType)
  737. and (ftype.length is None or ftype.length == '...')):
  738. ftype = ftype.item
  739. fname = fname + '[0]'
  740. prnt(' { %s = &p->%s; (void)tmp; }' % (
  741. ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual),
  742. fname))
  743. except ffiplatform.VerificationError as e:
  744. prnt(' /* %s */' % str(e)) # cannot verify it, ignore
  745. prnt('}')
  746. prnt('struct _cffi_align_%s { char x; %s y; };' % (approxname, cname))
  747. prnt()
  748. def _struct_ctx(self, tp, cname, approxname, named_ptr=None):
  749. type_index = self._typesdict[tp]
  750. reason_for_not_expanding = None
  751. flags = []
  752. if isinstance(tp, model.UnionType):
  753. flags.append("_CFFI_F_UNION")
  754. if tp.fldtypes is None:
  755. flags.append("_CFFI_F_OPAQUE")
  756. reason_for_not_expanding = "opaque"
  757. if (tp not in self.ffi._parser._included_declarations and
  758. (named_ptr is None or
  759. named_ptr not in self.ffi._parser._included_declarations)):
  760. if tp.fldtypes is None:
  761. pass # opaque
  762. elif tp.partial or tp.has_anonymous_struct_fields():
  763. pass # field layout obtained silently from the C compiler
  764. else:
  765. flags.append("_CFFI_F_CHECK_FIELDS")
  766. if tp.packed:
  767. flags.append("_CFFI_F_PACKED")
  768. else:
  769. flags.append("_CFFI_F_EXTERNAL")
  770. reason_for_not_expanding = "external"
  771. flags = '|'.join(flags) or '0'
  772. c_fields = []
  773. if reason_for_not_expanding is None:
  774. enumfields = list(tp.enumfields())
  775. for fldname, fldtype, fbitsize, fqual in enumfields:
  776. fldtype = self._field_type(tp, fldname, fldtype)
  777. # cname is None for _add_missing_struct_unions() only
  778. op = OP_NOOP
  779. if fbitsize >= 0:
  780. op = OP_BITFIELD
  781. size = '%d /* bits */' % fbitsize
  782. elif cname is None or (
  783. isinstance(fldtype, model.ArrayType) and
  784. fldtype.length is None):
  785. size = '(size_t)-1'
  786. else:
  787. size = 'sizeof(((%s)0)->%s)' % (
  788. tp.get_c_name('*') if named_ptr is None
  789. else named_ptr.name,
  790. fldname)
  791. if cname is None or fbitsize >= 0:
  792. offset = '(size_t)-1'
  793. elif named_ptr is not None:
  794. offset = '((char *)&((%s)0)->%s) - (char *)0' % (
  795. named_ptr.name, fldname)
  796. else:
  797. offset = 'offsetof(%s, %s)' % (tp.get_c_name(''), fldname)
  798. c_fields.append(
  799. FieldExpr(fldname, offset, size, fbitsize,
  800. CffiOp(op, self._typesdict[fldtype])))
  801. first_field_index = len(self._lsts["field"])
  802. self._lsts["field"].extend(c_fields)
  803. #
  804. if cname is None: # unknown name, for _add_missing_struct_unions
  805. size = '(size_t)-2'
  806. align = -2
  807. comment = "unnamed"
  808. else:
  809. if named_ptr is not None:
  810. size = 'sizeof(*(%s)0)' % (named_ptr.name,)
  811. align = '-1 /* unknown alignment */'
  812. else:
  813. size = 'sizeof(%s)' % (cname,)
  814. align = 'offsetof(struct _cffi_align_%s, y)' % (approxname,)
  815. comment = None
  816. else:
  817. size = '(size_t)-1'
  818. align = -1
  819. first_field_index = -1
  820. comment = reason_for_not_expanding
  821. self._lsts["struct_union"].append(
  822. StructUnionExpr(tp.name, type_index, flags, size, align, comment,
  823. first_field_index, c_fields))
  824. self._seen_struct_unions.add(tp)
  825. def _add_missing_struct_unions(self):
  826. # not very nice, but some struct declarations might be missing
  827. # because they don't have any known C name. Check that they are
  828. # not partial (we can't complete or verify them!) and emit them
  829. # anonymously.
  830. lst = list(self._struct_unions.items())
  831. lst.sort(key=lambda tp_order: tp_order[1])
  832. for tp, order in lst:
  833. if tp not in self._seen_struct_unions:
  834. if tp.partial:
  835. raise NotImplementedError("internal inconsistency: %r is "
  836. "partial but was not seen at "
  837. "this point" % (tp,))
  838. if tp.name.startswith('$') and tp.name[1:].isdigit():
  839. approxname = tp.name[1:]
  840. elif tp.name == '_IO_FILE' and tp.forcename == 'FILE':
  841. approxname = 'FILE'
  842. self._typedef_ctx(tp, 'FILE')
  843. else:
  844. raise NotImplementedError("internal inconsistency: %r" %
  845. (tp,))
  846. self._struct_ctx(tp, None, approxname)
  847. def _generate_cpy_struct_collecttype(self, tp, name):
  848. self._struct_collecttype(tp)
  849. _generate_cpy_union_collecttype = _generate_cpy_struct_collecttype
  850. def _struct_names(self, tp):
  851. cname = tp.get_c_name('')
  852. if ' ' in cname:
  853. return cname, cname.replace(' ', '_')
  854. else:
  855. return cname, '_' + cname
  856. def _generate_cpy_struct_decl(self, tp, name):
  857. self._struct_decl(tp, *self._struct_names(tp))
  858. _generate_cpy_union_decl = _generate_cpy_struct_decl
  859. def _generate_cpy_struct_ctx(self, tp, name):
  860. self._struct_ctx(tp, *self._struct_names(tp))
  861. _generate_cpy_union_ctx = _generate_cpy_struct_ctx
  862. # ----------
  863. # 'anonymous' declarations. These are produced for anonymous structs
  864. # or unions; the 'name' is obtained by a typedef.
  865. def _generate_cpy_anonymous_collecttype(self, tp, name):
  866. if isinstance(tp, model.EnumType):
  867. self._generate_cpy_enum_collecttype(tp, name)
  868. else:
  869. self._struct_collecttype(tp)
  870. def _generate_cpy_anonymous_decl(self, tp, name):
  871. if isinstance(tp, model.EnumType):
  872. self._generate_cpy_enum_decl(tp)
  873. else:
  874. self._struct_decl(tp, name, 'typedef_' + name)
  875. def _generate_cpy_anonymous_ctx(self, tp, name):
  876. if isinstance(tp, model.EnumType):
  877. self._enum_ctx(tp, name)
  878. else:
  879. self._struct_ctx(tp, name, 'typedef_' + name)
  880. # ----------
  881. # constants, declared with "static const ..."
  882. def _generate_cpy_const(self, is_int, name, tp=None, category='const',
  883. check_value=None):
  884. if (category, name) in self._seen_constants:
  885. raise ffiplatform.VerificationError(
  886. "duplicate declaration of %s '%s'" % (category, name))
  887. self._seen_constants.add((category, name))
  888. #
  889. prnt = self._prnt
  890. funcname = '_cffi_%s_%s' % (category, name)
  891. if is_int:
  892. prnt('static int %s(unsigned long long *o)' % funcname)
  893. prnt('{')
  894. prnt(' int n = (%s) <= 0;' % (name,))
  895. prnt(' *o = (unsigned long long)((%s) << 0);'
  896. ' /* check that %s is an integer */' % (name, name))
  897. if check_value is not None:
  898. if check_value > 0:
  899. check_value = '%dU' % (check_value,)
  900. prnt(' if (!_cffi_check_int(*o, n, %s))' % (check_value,))
  901. prnt(' n |= 2;')
  902. prnt(' return n;')
  903. prnt('}')
  904. else:
  905. assert check_value is None
  906. prnt('static void %s(char *o)' % funcname)
  907. prnt('{')
  908. prnt(' *(%s)o = %s;' % (tp.get_c_name('*'), name))
  909. prnt('}')
  910. prnt()
  911. def _generate_cpy_constant_collecttype(self, tp, name):
  912. is_int = tp.is_integer_type()
  913. if not is_int or self.target_is_python:
  914. self._do_collect_type(tp)
  915. def _generate_cpy_constant_decl(self, tp, name):
  916. is_int = tp.is_integer_type()
  917. self._generate_cpy_const(is_int, name, tp)
  918. def _generate_cpy_constant_ctx(self, tp, name):
  919. if not self.target_is_python and tp.is_integer_type():
  920. type_op = CffiOp(OP_CONSTANT_INT, -1)
  921. else:
  922. if self.target_is_python:
  923. const_kind = OP_DLOPEN_CONST
  924. else:
  925. const_kind = OP_CONSTANT
  926. type_index = self._typesdict[tp]
  927. type_op = CffiOp(const_kind, type_index)
  928. self._lsts["global"].append(
  929. GlobalExpr(name, '_cffi_const_%s' % name, type_op))
  930. # ----------
  931. # enums
  932. def _generate_cpy_enum_collecttype(self, tp, name):
  933. self._do_collect_type(tp)
  934. def _generate_cpy_enum_decl(self, tp, name=None):
  935. for enumerator in tp.enumerators:
  936. self._generate_cpy_const(True, enumerator)
  937. def _enum_ctx(self, tp, cname):
  938. type_index = self._typesdict[tp]
  939. type_op = CffiOp(OP_ENUM, -1)
  940. if self.target_is_python:
  941. tp.check_not_partial()
  942. for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
  943. self._lsts["global"].append(
  944. GlobalExpr(enumerator, '_cffi_const_%s' % enumerator, type_op,
  945. check_value=enumvalue))
  946. #
  947. if cname is not None and '$' not in cname and not self.target_is_python:
  948. size = "sizeof(%s)" % cname
  949. signed = "((%s)-1) <= 0" % cname
  950. else:
  951. basetp = tp.build_baseinttype(self.ffi, [])
  952. size = self.ffi.sizeof(basetp)
  953. signed = int(int(self.ffi.cast(basetp, -1)) < 0)
  954. allenums = ",".join(tp.enumerators)
  955. self._lsts["enum"].append(
  956. EnumExpr(tp.name, type_index, size, signed, allenums))
  957. def _generate_cpy_enum_ctx(self, tp, name):
  958. self._enum_ctx(tp, tp._get_c_name())
  959. # ----------
  960. # macros: for now only for integers
  961. def _generate_cpy_macro_collecttype(self, tp, name):
  962. pass
  963. def _generate_cpy_macro_decl(self, tp, name):
  964. if tp == '...':
  965. check_value = None
  966. else:
  967. check_value = tp # an integer
  968. self._generate_cpy_const(True, name, check_value=check_value)
  969. def _generate_cpy_macro_ctx(self, tp, name):
  970. if tp == '...':
  971. if self.target_is_python:
  972. raise ffiplatform.VerificationError(
  973. "cannot use the syntax '...' in '#define %s ...' when "
  974. "using the ABI mode" % (name,))
  975. check_value = None
  976. else:
  977. check_value = tp # an integer
  978. type_op = CffiOp(OP_CONSTANT_INT, -1)
  979. self._lsts["global"].append(
  980. GlobalExpr(name, '_cffi_const_%s' % name, type_op,
  981. check_value=check_value))
  982. # ----------
  983. # global variables
  984. def _global_type(self, tp, global_name):
  985. if isinstance(tp, model.ArrayType):
  986. actual_length = tp.length
  987. if actual_length == '...':
  988. actual_length = '_cffi_array_len(%s)' % (global_name,)
  989. tp_item = self._global_type(tp.item, '%s[0]' % global_name)
  990. tp = model.ArrayType(tp_item, actual_length)
  991. return tp
  992. def _generate_cpy_variable_collecttype(self, tp, name):
  993. self._do_collect_type(self._global_type(tp, name))
  994. def _generate_cpy_variable_decl(self, tp, name):
  995. prnt = self._prnt
  996. tp = self._global_type(tp, name)
  997. if isinstance(tp, model.ArrayType) and tp.length is None:
  998. tp = tp.item
  999. ampersand = ''
  1000. else:
  1001. ampersand = '&'
  1002. # This code assumes that casts from "tp *" to "void *" is a
  1003. # no-op, i.e. a function that returns a "tp *" can be called
  1004. # as if it returned a "void *". This should be generally true
  1005. # on any modern machine. The only exception to that rule (on
  1006. # uncommon architectures, and as far as I can tell) might be
  1007. # if 'tp' were a function type, but that is not possible here.
  1008. # (If 'tp' is a function _pointer_ type, then casts from "fn_t
  1009. # **" to "void *" are again no-ops, as far as I can tell.)
  1010. decl = '*_cffi_var_%s(void)' % (name,)
  1011. prnt('static ' + tp.get_c_name(decl, quals=self._current_quals))
  1012. prnt('{')
  1013. prnt(' return %s(%s);' % (ampersand, name))
  1014. prnt('}')
  1015. prnt()
  1016. def _generate_cpy_variable_ctx(self, tp, name):
  1017. tp = self._global_type(tp, name)
  1018. type_index = self._typesdict[tp]
  1019. if self.target_is_python:
  1020. op = OP_GLOBAL_VAR
  1021. else:
  1022. op = OP_GLOBAL_VAR_F
  1023. self._lsts["global"].append(
  1024. GlobalExpr(name, '_cffi_var_%s' % name, CffiOp(op, type_index)))
  1025. # ----------
  1026. # emitting the opcodes for individual types
  1027. def _emit_bytecode_VoidType(self, tp, index):
  1028. self.cffi_types[index] = CffiOp(OP_PRIMITIVE, PRIM_VOID)
  1029. def _emit_bytecode_PrimitiveType(self, tp, index):
  1030. prim_index = PRIMITIVE_TO_INDEX[tp.name]
  1031. self.cffi_types[index] = CffiOp(OP_PRIMITIVE, prim_index)
  1032. def _emit_bytecode_UnknownIntegerType(self, tp, index):
  1033. s = ('_cffi_prim_int(sizeof(%s), (\n'
  1034. ' ((%s)-1) << 0 /* check that %s is an integer type */\n'
  1035. ' ) <= 0)' % (tp.name, tp.name, tp.name))
  1036. self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s)
  1037. def _emit_bytecode_UnknownFloatType(self, tp, index):
  1038. s = ('_cffi_prim_float(sizeof(%s) *\n'
  1039. ' (((%s)1) / 2) * 2 /* integer => 0, float => 1 */\n'
  1040. ' )' % (tp.name, tp.name))
  1041. self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s)
  1042. def _emit_bytecode_RawFunctionType(self, tp, index):
  1043. self.cffi_types[index] = CffiOp(OP_FUNCTION, self._typesdict[tp.result])
  1044. index += 1
  1045. for tp1 in tp.args:
  1046. realindex = self._typesdict[tp1]
  1047. if index != realindex:
  1048. if isinstance(tp1, model.PrimitiveType):
  1049. self._emit_bytecode_PrimitiveType(tp1, index)
  1050. else:
  1051. self.cffi_types[index] = CffiOp(OP_NOOP, realindex)
  1052. index += 1
  1053. flags = int(tp.ellipsis)
  1054. if tp.abi is not None:
  1055. if tp.abi == '__stdcall':
  1056. flags |= 2
  1057. else:
  1058. raise NotImplementedError("abi=%r" % (tp.abi,))
  1059. self.cffi_types[index] = CffiOp(OP_FUNCTION_END, flags)
  1060. def _emit_bytecode_PointerType(self, tp, index):
  1061. self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[tp.totype])
  1062. _emit_bytecode_ConstPointerType = _emit_bytecode_PointerType
  1063. _emit_bytecode_NamedPointerType = _emit_bytecode_PointerType
  1064. def _emit_bytecode_FunctionPtrType(self, tp, index):
  1065. raw = tp.as_raw_function()
  1066. self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[raw])
  1067. def _emit_bytecode_ArrayType(self, tp, index):
  1068. item_index = self._typesdict[tp.item]
  1069. if tp.length is None:
  1070. self.cffi_types[index] = CffiOp(OP_OPEN_ARRAY, item_index)
  1071. elif tp.length == '...':
  1072. raise ffiplatform.VerificationError(
  1073. "type %s badly placed: the '...' array length can only be "
  1074. "used on global arrays or on fields of structures" % (
  1075. str(tp).replace('/*...*/', '...'),))
  1076. else:
  1077. assert self.cffi_types[index + 1] == 'LEN'
  1078. self.cffi_types[index] = CffiOp(OP_ARRAY, item_index)
  1079. self.cffi_types[index + 1] = CffiOp(None, str(tp.length))
  1080. def _emit_bytecode_StructType(self, tp, index):
  1081. struct_index = self._struct_unions[tp]
  1082. self.cffi_types[index] = CffiOp(OP_STRUCT_UNION, struct_index)
  1083. _emit_bytecode_UnionType = _emit_bytecode_StructType
  1084. def _emit_bytecode_EnumType(self, tp, index):
  1085. enum_index = self._enums[tp]
  1086. self.cffi_types[index] = CffiOp(OP_ENUM, enum_index)
  1087. if sys.version_info >= (3,):
  1088. NativeIO = io.StringIO
  1089. else:
  1090. class NativeIO(io.BytesIO):
  1091. def write(self, s):
  1092. if isinstance(s, unicode):
  1093. s = s.encode('ascii')
  1094. super(NativeIO, self).write(s)
  1095. def _make_c_or_py_source(ffi, module_name, preamble, target_file):
  1096. recompiler = Recompiler(ffi, module_name,
  1097. target_is_python=(preamble is None))
  1098. recompiler.collect_type_table()
  1099. recompiler.collect_step_tables()
  1100. f = NativeIO()
  1101. recompiler.write_source_to_f(f, preamble)
  1102. output = f.getvalue()
  1103. try:
  1104. with open(target_file, 'r') as f1:
  1105. if f1.read(len(output) + 1) != output:
  1106. raise IOError
  1107. return False # already up-to-date
  1108. except IOError:
  1109. tmp_file = '%s.~%d' % (target_file, os.getpid())
  1110. with open(tmp_file, 'w') as f1:
  1111. f1.write(output)
  1112. try:
  1113. os.rename(tmp_file, target_file)
  1114. except OSError:
  1115. os.unlink(target_file)
  1116. os.rename(tmp_file, target_file)
  1117. return True
  1118. def make_c_source(ffi, module_name, preamble, target_c_file):
  1119. assert preamble is not None
  1120. return _make_c_or_py_source(ffi, module_name, preamble, target_c_file)
  1121. def make_py_source(ffi, module_name, target_py_file):
  1122. return _make_c_or_py_source(ffi, module_name, None, target_py_file)
  1123. def _modname_to_file(outputdir, modname, extension):
  1124. parts = modname.split('.')
  1125. try:
  1126. os.makedirs(os.path.join(outputdir, *parts[:-1]))
  1127. except OSError:
  1128. pass
  1129. parts[-1] += extension
  1130. return os.path.join(outputdir, *parts), parts
  1131. def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True,
  1132. c_file=None, source_extension='.c', extradir=None, **kwds):
  1133. if not isinstance(module_name, str):
  1134. module_name = module_name.encode('ascii')
  1135. if ffi._windows_unicode:
  1136. ffi._apply_windows_unicode(kwds)
  1137. if preamble is not None:
  1138. if c_file is None:
  1139. c_file, parts = _modname_to_file(tmpdir, module_name,
  1140. source_extension)
  1141. if extradir:
  1142. parts = [extradir] + parts
  1143. ext_c_file = os.path.join(*parts)
  1144. else:
  1145. ext_c_file = c_file
  1146. ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds)
  1147. updated = make_c_source(ffi, module_name, preamble, c_file)
  1148. if call_c_compiler:
  1149. cwd = os.getcwd()
  1150. try:
  1151. os.chdir(tmpdir)
  1152. outputfilename = ffiplatform.compile('.', ext)
  1153. finally:
  1154. os.chdir(cwd)
  1155. return outputfilename
  1156. else:
  1157. return ext, updated
  1158. else:
  1159. if c_file is None:
  1160. c_file, _ = _modname_to_file(tmpdir, module_name, '.py')
  1161. updated = make_py_source(ffi, module_name, c_file)
  1162. if call_c_compiler:
  1163. return c_file
  1164. else:
  1165. return None, updated
  1166. def _verify(ffi, module_name, preamble, *args, **kwds):
  1167. # FOR TESTS ONLY
  1168. from testing.udir import udir
  1169. import imp
  1170. assert module_name not in sys.modules, "module name conflict: %r" % (
  1171. module_name,)
  1172. kwds.setdefault('tmpdir', str(udir))
  1173. outputfilename = recompile(ffi, module_name, preamble, *args, **kwds)
  1174. module = imp.load_dynamic(module_name, outputfilename)
  1175. #
  1176. # hack hack hack: copy all *bound methods* from module.ffi back to the
  1177. # ffi instance. Then calls like ffi.new() will invoke module.ffi.new().
  1178. for name in dir(module.ffi):
  1179. if not name.startswith('_'):
  1180. attr = getattr(module.ffi, name)
  1181. if attr is not getattr(ffi, name, object()):
  1182. setattr(ffi, name, attr)
  1183. def typeof_disabled(*args, **kwds):
  1184. raise NotImplementedError
  1185. ffi._typeof = typeof_disabled
  1186. return module.lib