PageRenderTime 58ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 1ms

/pypy/translator/c/database.py

http://github.com/pypy/pypy
Python | 413 lines | 397 code | 12 blank | 4 comment | 36 complexity | 330f9958a7402753e68efbd77a4c3bc5 MD5 | raw file
  1. from pypy.rpython.lltypesystem.lltype import (
  2. Primitive, Ptr, typeOf, RuntimeTypeInfo, Struct, Array, FuncType, PyObject,
  3. Void, ContainerType, OpaqueType, FixedSizeArray, _uninitialized, Typedef)
  4. from pypy.rpython.lltypesystem import lltype, rffi
  5. from pypy.rpython.lltypesystem.llmemory import WeakRef, _WeakRefType, GCREF
  6. from pypy.rpython.lltypesystem.rffi import CConstant
  7. from pypy.rpython.lltypesystem import llgroup
  8. from pypy.tool.sourcetools import valid_identifier
  9. from pypy.translator.c.primitive import PrimitiveName, PrimitiveType
  10. from pypy.translator.c.node import StructDefNode, ArrayDefNode
  11. from pypy.translator.c.node import FixedSizeArrayDefNode, BareBoneArrayDefNode
  12. from pypy.translator.c.node import ContainerNodeFactory, ExtTypeOpaqueDefNode
  13. from pypy.translator.c.support import cdecl, CNameManager
  14. from pypy.translator.c.support import log, barebonearray
  15. from pypy.translator.c.extfunc import do_the_getting
  16. from pypy import conftest
  17. from pypy.translator.c import gc
  18. from pypy.tool.identity_dict import identity_dict
  19. class NoCorrespondingNode(Exception):
  20. pass
  21. # ____________________________________________________________
  22. class LowLevelDatabase(object):
  23. gctransformer = None
  24. def __init__(self, translator=None, standalone=False,
  25. cpython_extension=False,
  26. gcpolicyclass=None,
  27. thread_enabled=False,
  28. sandbox=False):
  29. self.translator = translator
  30. self.standalone = standalone
  31. self.cpython_extension = cpython_extension
  32. self.sandbox = sandbox
  33. if gcpolicyclass is None:
  34. gcpolicyclass = gc.RefcountingGcPolicy
  35. self.gcpolicy = gcpolicyclass(self, thread_enabled)
  36. self.structdefnodes = {}
  37. self.pendingsetupnodes = []
  38. self.containernodes = {}
  39. self.containerlist = []
  40. self.idelayedfunctionnames = identity_dict()
  41. self.delayedfunctionptrs = []
  42. self.completedcontainers = 0
  43. self.containerstats = {}
  44. self.externalfuncs = {}
  45. self.helper2ptr = {}
  46. # late_initializations is for when the value you want to
  47. # assign to a constant object is something C doesn't think is
  48. # constant
  49. self.late_initializations = []
  50. self.namespace = CNameManager()
  51. if translator is None or translator.rtyper is None:
  52. self.exctransformer = None
  53. else:
  54. self.exctransformer = translator.getexceptiontransformer()
  55. if translator is not None:
  56. self.gctransformer = self.gcpolicy.transformerclass(translator)
  57. self.completed = False
  58. self.instrument_ncounter = 0
  59. def gettypedefnode(self, T, varlength=1):
  60. if varlength <= 1:
  61. varlength = 1 # it's C after all
  62. key = T
  63. else:
  64. key = T, varlength
  65. try:
  66. node = self.structdefnodes[key]
  67. except KeyError:
  68. if isinstance(T, Struct):
  69. if isinstance(T, FixedSizeArray):
  70. node = FixedSizeArrayDefNode(self, T)
  71. else:
  72. node = StructDefNode(self, T, varlength)
  73. elif isinstance(T, Array):
  74. if barebonearray(T):
  75. node = BareBoneArrayDefNode(self, T, varlength)
  76. else:
  77. node = ArrayDefNode(self, T, varlength)
  78. elif isinstance(T, OpaqueType) and T.hints.get("render_structure", False):
  79. node = ExtTypeOpaqueDefNode(self, T)
  80. elif T == WeakRef:
  81. REALT = self.gcpolicy.get_real_weakref_type()
  82. node = self.gettypedefnode(REALT)
  83. else:
  84. raise NoCorrespondingNode("don't know about %r" % (T,))
  85. self.structdefnodes[key] = node
  86. self.pendingsetupnodes.append(node)
  87. return node
  88. def gettype(self, T, varlength=1, who_asks=None, argnames=[]):
  89. if isinstance(T, Primitive) or T == GCREF:
  90. return PrimitiveType[T]
  91. elif isinstance(T, Typedef):
  92. return '%s @' % T.c_name
  93. elif isinstance(T, Ptr):
  94. if (isinstance(T.TO, OpaqueType) and
  95. T.TO.hints.get('c_pointer_typedef') is not None):
  96. return '%s @' % T.TO.hints['c_pointer_typedef']
  97. try:
  98. node = self.gettypedefnode(T.TO)
  99. except NoCorrespondingNode:
  100. pass
  101. else:
  102. if hasattr(node, 'getptrtype'):
  103. return node.getptrtype() # special-casing because of C
  104. typename = self.gettype(T.TO) # who_asks not propagated
  105. return typename.replace('@', '*@')
  106. elif isinstance(T, (Struct, Array, _WeakRefType)):
  107. node = self.gettypedefnode(T, varlength=varlength)
  108. if who_asks is not None:
  109. who_asks.dependencies[node] = True
  110. return node.gettype()
  111. elif T == PyObject:
  112. return 'PyObject @'
  113. elif isinstance(T, FuncType):
  114. resulttype = self.gettype(T.RESULT)
  115. argtypes = []
  116. for i in range(len(T.ARGS)):
  117. if T.ARGS[i] is not Void:
  118. argtype = self.gettype(T.ARGS[i])
  119. try:
  120. argname = argnames[i]
  121. except IndexError:
  122. argname = ''
  123. argtypes.append(cdecl(argtype, argname))
  124. argtypes = ', '.join(argtypes) or 'void'
  125. return resulttype.replace('@', '(@)(%s)' % argtypes)
  126. elif isinstance(T, OpaqueType):
  127. if T == RuntimeTypeInfo:
  128. return self.gcpolicy.rtti_type()
  129. elif T.hints.get("render_structure", False):
  130. node = self.gettypedefnode(T, varlength=varlength)
  131. if who_asks is not None:
  132. who_asks.dependencies[node] = True
  133. return 'struct %s @' % node.name
  134. elif T.hints.get('external', None) == 'C':
  135. return '%s @' % T.hints['c_name']
  136. else:
  137. #raise Exception("don't know about opaque type %r" % (T,))
  138. return 'struct %s @' % (
  139. valid_identifier('pypy_opaque_' + T.tag),)
  140. elif isinstance(T, llgroup.GroupType):
  141. return "/*don't use me*/ void @"
  142. else:
  143. raise Exception("don't know about type %r" % (T,))
  144. def getcontainernode(self, container, _dont_write_c_code=True, **buildkwds):
  145. try:
  146. node = self.containernodes[container]
  147. except KeyError:
  148. T = typeOf(container)
  149. if isinstance(T, (lltype.Array, lltype.Struct)):
  150. if hasattr(self.gctransformer, 'consider_constant'):
  151. self.gctransformer.consider_constant(T, container)
  152. nodefactory = ContainerNodeFactory[T.__class__]
  153. node = nodefactory(self, T, container, **buildkwds)
  154. self.containernodes[container] = node
  155. # _dont_write_c_code should only be False for a hack in
  156. # weakrefnode_factory()
  157. if not _dont_write_c_code:
  158. return node
  159. kind = getattr(node, 'nodekind', '?')
  160. self.containerstats[kind] = self.containerstats.get(kind, 0) + 1
  161. self.containerlist.append(node)
  162. if self.completed:
  163. pass # we would like to fail here, but a few containers
  164. # are found very late, e.g. _subarrays via addresses
  165. # introduced by the GC transformer, or the type_info_table
  166. return node
  167. def get(self, obj, funcgen=None):
  168. if isinstance(obj, CConstant):
  169. return obj.c_name # without further checks
  170. T = typeOf(obj)
  171. if isinstance(T, Primitive) or T == GCREF:
  172. return PrimitiveName[T](obj, self)
  173. elif isinstance(T, Ptr):
  174. if (isinstance(T.TO, OpaqueType) and
  175. T.TO.hints.get('c_pointer_typedef') is not None):
  176. if obj._obj is not None:
  177. value = rffi.cast(rffi.SSIZE_T, obj)
  178. return '((%s) %s)' % (cdecl(self.gettype(T), ''),
  179. self.get(value))
  180. if obj: # test if the ptr is non-NULL
  181. try:
  182. container = obj._obj
  183. except lltype.DelayedPointer:
  184. # hack hack hack
  185. name = obj._obj0
  186. assert name.startswith('delayed!')
  187. n = len('delayed!')
  188. if len(name) == n:
  189. raise
  190. if isinstance(lltype.typeOf(obj).TO, lltype.FuncType):
  191. if obj in self.idelayedfunctionnames:
  192. return self.idelayedfunctionnames[obj][0]
  193. funcname = name[n:]
  194. funcname = self.namespace.uniquename('g_'+funcname)
  195. self.idelayedfunctionnames[obj] = funcname, obj
  196. else:
  197. funcname = None # can't use the name of a
  198. # delayed non-function ptr
  199. self.delayedfunctionptrs.append(obj)
  200. return funcname
  201. # /hack hack hack
  202. else:
  203. # hack hack hack
  204. if obj in self.idelayedfunctionnames:
  205. # this used to be a delayed function,
  206. # make sure we use the same name
  207. forcename = self.idelayedfunctionnames[obj][0]
  208. node = self.getcontainernode(container,
  209. forcename=forcename)
  210. assert node.getptrname() == forcename
  211. return forcename
  212. # /hack hack hack
  213. if isinstance(container, int):
  214. # special case for tagged odd-valued pointers
  215. return '((%s) %d)' % (cdecl(self.gettype(T), ''),
  216. obj._obj)
  217. node = self.getcontainernode(container)
  218. if node._funccodegen_owner is None:
  219. node._funccodegen_owner = funcgen
  220. return node.getptrname()
  221. else:
  222. return '((%s) NULL)' % (cdecl(self.gettype(T), ''), )
  223. else:
  224. raise Exception("don't know about %r" % (obj,))
  225. def complete(self, show_progress=True):
  226. assert not self.completed
  227. if self.translator and self.translator.rtyper:
  228. do_the_getting(self, self.translator.rtyper)
  229. def dump():
  230. lst = ['%s: %d' % keyvalue
  231. for keyvalue in self.containerstats.items()]
  232. lst.sort()
  233. log.event('%8d nodes [ %s ]' % (i, ' '.join(lst)))
  234. i = self.completedcontainers
  235. if show_progress:
  236. show_i = (i//1000 + 1) * 1000
  237. else:
  238. show_i = -1
  239. # The order of database completion is fragile with gc transformers.
  240. # Here is what occurs:
  241. #
  242. # 1. follow dependencies recursively from the entry point: data
  243. # structures pointing to other structures or functions, and
  244. # constants in functions pointing to other structures or functions.
  245. # Because of the mixlevelannotator, this might find delayed
  246. # (not-annotated-and-rtyped-yet) function pointers. They are
  247. # not followed at this point. User finalizers (__del__) on the
  248. # other hand are followed during this step too.
  249. #
  250. # 2. gctransformer.finish_helpers() - after this, all functions in
  251. # the program have been rtyped.
  252. #
  253. # 3. follow new dependencies. All previously delayed functions
  254. # should have been resolved by 2 - they are gc helpers, like
  255. # ll_finalize(). New FuncNodes are built for them. No more
  256. # FuncNodes can show up after this step.
  257. #
  258. # 4. gctransformer.finish_tables() - freeze the gc types table.
  259. #
  260. # 5. follow new dependencies (this should be only the gc type table,
  261. # which contains only numbers and pointers to ll_finalizer
  262. # functions seen in step 3).
  263. #
  264. # This is implemented by interleaving the follow-new-dependencies
  265. # steps with calls to the next 'finish' function from the following
  266. # list:
  267. finish_callbacks = []
  268. if self.gctransformer:
  269. finish_callbacks.append(('GC transformer: finished helpers',
  270. self.gctransformer.finish_helpers))
  271. finish_callbacks.append(('GC transformer: finished tables',
  272. self.gctransformer.get_finish_tables()))
  273. def add_dependencies(newdependencies, parent=None):
  274. for value in newdependencies:
  275. #if isinstance(value, _uninitialized):
  276. # continue
  277. if isinstance(typeOf(value), ContainerType):
  278. node = self.getcontainernode(value)
  279. if parent and node._funccodegen_owner is not None:
  280. node._funccodegen_owner = parent._funccodegen_owner
  281. else:
  282. self.get(value, parent and parent._funccodegen_owner)
  283. while True:
  284. while True:
  285. while self.pendingsetupnodes:
  286. lst = self.pendingsetupnodes
  287. self.pendingsetupnodes = []
  288. for nodedef in lst:
  289. nodedef.setup()
  290. if i == len(self.containerlist):
  291. break
  292. node = self.containerlist[i]
  293. add_dependencies(node.enum_dependencies(), node)
  294. i += 1
  295. self.completedcontainers = i
  296. if i == show_i:
  297. dump()
  298. show_i += 1000
  299. if self.delayedfunctionptrs:
  300. lst = self.delayedfunctionptrs
  301. self.delayedfunctionptrs = []
  302. progress = False
  303. for fnptr in lst:
  304. try:
  305. fnptr._obj
  306. except lltype.DelayedPointer: # still not resolved
  307. self.delayedfunctionptrs.append(fnptr)
  308. else:
  309. self.get(fnptr)
  310. progress = True
  311. if progress:
  312. continue # progress - follow all dependencies again
  313. if finish_callbacks:
  314. logmsg, finish = finish_callbacks.pop(0)
  315. if not hasattr(finish, 'next'):
  316. newdependencies = finish()
  317. else:
  318. # if 'finish' is a generator, consume the next element
  319. # and put the generator again in the queue
  320. try:
  321. newdependencies = finish.next()
  322. finish_callbacks.insert(0, (None, finish))
  323. except StopIteration:
  324. newdependencies = None
  325. if logmsg:
  326. log.database(logmsg)
  327. if newdependencies:
  328. add_dependencies(newdependencies)
  329. continue # progress - follow all dependencies again
  330. break # database is now complete
  331. assert not self.delayedfunctionptrs
  332. self.completed = True
  333. if show_progress:
  334. dump()
  335. log.database("Completed")
  336. def globalcontainers(self):
  337. for node in self.containerlist:
  338. if node.globalcontainer:
  339. yield node
  340. def get_lltype_of_exception_value(self):
  341. if self.translator is not None and self.translator.rtyper is not None:
  342. exceptiondata = self.translator.rtyper.getexceptiondata()
  343. return exceptiondata.lltype_of_exception_value
  344. else:
  345. return Ptr(PyObject)
  346. def getstructdeflist(self):
  347. # return the StructDefNodes sorted according to dependencies
  348. result = []
  349. seen = {}
  350. def produce(node):
  351. if node not in seen:
  352. deps = node.dependencies.keys()
  353. deps.sort(key=lambda x: x.name)
  354. for othernode in deps:
  355. produce(othernode)
  356. result.append(node)
  357. seen[node] = True
  358. nodes = self.structdefnodes.values()
  359. nodes.sort(key=lambda x: x.name)
  360. for node in nodes:
  361. produce(node)
  362. return result
  363. def need_sandboxing(self, fnobj):
  364. if not self.sandbox:
  365. return False
  366. if hasattr(fnobj, '_safe_not_sandboxed'):
  367. return not fnobj._safe_not_sandboxed
  368. else:
  369. return "if_external"
  370. def prepare_inline_helpers(self):
  371. all_nodes = self.globalcontainers()
  372. funcnodes = [node for node in all_nodes if node.nodekind == 'func']
  373. graphs = []
  374. for node in funcnodes:
  375. for graph in node.graphs_to_patch():
  376. graphs.append(graph)
  377. self.gctransformer.prepare_inline_helpers(graphs)
  378. def all_graphs(self):
  379. graphs = []
  380. for node in self.containerlist:
  381. if node.nodekind == 'func':
  382. for graph in node.graphs_to_patch():
  383. graphs.append(graph)
  384. return graphs