PageRenderTime 59ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/rpython/annlowlevel.py

http://github.com/pypy/pypy
Python | 687 lines | 583 code | 51 blank | 53 comment | 53 complexity | 89111297028b8b819878173da3357fff MD5 | raw file
  1. """
  2. The code needed to flow and annotate low-level helpers -- the ll_*() functions
  3. """
  4. import types
  5. from pypy.tool.sourcetools import valid_identifier
  6. from pypy.annotation import model as annmodel
  7. from pypy.annotation.policy import AnnotatorPolicy, Sig
  8. from pypy.annotation.specialize import flatten_star_args
  9. from pypy.rpython.lltypesystem import lltype
  10. from pypy.rpython.ootypesystem import ootype
  11. from pypy.rpython import extregistry
  12. from pypy.objspace.flow.model import Constant
  13. from pypy.translator.simplify import get_functype
  14. class KeyComp(object):
  15. def __init__(self, val):
  16. self.val = val
  17. def __eq__(self, other):
  18. return self.__class__ is other.__class__ and self.val == other.val
  19. def __ne__(self, other):
  20. return not (self == other)
  21. def __hash__(self):
  22. return hash(self.val)
  23. def __str__(self):
  24. val = self.val
  25. if isinstance(val, lltype.LowLevelType):
  26. return val._short_name() + 'LlT'
  27. s = getattr(val, '__name__', None)
  28. if s is None:
  29. compact = getattr(val, 'compact_repr', None)
  30. if compact is None:
  31. s = repr(val)
  32. else:
  33. s = compact()
  34. return s + 'Const'
  35. __repr__ = __str__
  36. class LowLevelAnnotatorPolicy(AnnotatorPolicy):
  37. allow_someobjects = False
  38. def __init__(pol, rtyper=None):
  39. pol.rtyper = rtyper
  40. def lowlevelspecialize(funcdesc, args_s, key_for_args):
  41. args_s, key1, builder = flatten_star_args(funcdesc, args_s)
  42. key = []
  43. new_args_s = []
  44. for i, s_obj in enumerate(args_s):
  45. if i in key_for_args:
  46. key.append(key_for_args[i])
  47. new_args_s.append(s_obj)
  48. elif isinstance(s_obj, annmodel.SomePBC):
  49. assert s_obj.is_constant(), "ambiguous low-level helper specialization"
  50. key.append(KeyComp(s_obj.const))
  51. new_args_s.append(s_obj)
  52. else:
  53. new_args_s.append(annmodel.not_const(s_obj))
  54. try:
  55. key.append(annmodel.annotation_to_lltype(s_obj))
  56. except ValueError:
  57. # passing non-low-level types to a ll_* function is allowed
  58. # for module/ll_*
  59. key.append(s_obj.__class__)
  60. key = (tuple(key),)
  61. if key1 is not None:
  62. key += (key1,)
  63. flowgraph = funcdesc.cachedgraph(key, builder=builder)
  64. args_s[:] = new_args_s
  65. return flowgraph
  66. lowlevelspecialize = staticmethod(lowlevelspecialize)
  67. def default_specialize(funcdesc, args_s):
  68. return LowLevelAnnotatorPolicy.lowlevelspecialize(funcdesc, args_s, {})
  69. default_specialize = staticmethod(default_specialize)
  70. def specialize__ts(pol, funcdesc, args_s, ref):
  71. ts = pol.rtyper.type_system
  72. ref = ref.split('.')
  73. x = ts
  74. for part in ref:
  75. x = getattr(x, part)
  76. bk = pol.rtyper.annotator.bookkeeper
  77. funcdesc2 = bk.getdesc(x)
  78. return pol.default_specialize(funcdesc2, args_s)
  79. def specialize__semierased(funcdesc, args_s):
  80. a2l = annmodel.annotation_to_lltype
  81. l2a = annmodel.lltype_to_annotation
  82. args_s[:] = [l2a(a2l(s)) for s in args_s]
  83. return LowLevelAnnotatorPolicy.default_specialize(funcdesc, args_s)
  84. specialize__semierased = staticmethod(specialize__semierased)
  85. specialize__ll = default_specialize
  86. def specialize__ll_and_arg(funcdesc, args_s, *argindices):
  87. keys = {}
  88. for i in argindices:
  89. keys[i] = args_s[i].const
  90. return LowLevelAnnotatorPolicy.lowlevelspecialize(funcdesc, args_s,
  91. keys)
  92. specialize__ll_and_arg = staticmethod(specialize__ll_and_arg)
  93. def annotate_lowlevel_helper(annotator, ll_function, args_s, policy=None):
  94. if policy is None:
  95. policy= LowLevelAnnotatorPolicy()
  96. return annotator.annotate_helper(ll_function, args_s, policy)
  97. # ___________________________________________________________________
  98. # Mix-level helpers: combining RPython and ll-level
  99. class MixLevelAnnotatorPolicy(LowLevelAnnotatorPolicy):
  100. def __init__(pol, annhelper):
  101. pol.annhelper = annhelper
  102. pol.rtyper = annhelper.rtyper
  103. def default_specialize(pol, funcdesc, args_s):
  104. name = funcdesc.name
  105. if name.startswith('ll_') or name.startswith('_ll_'): # xxx can we do better?
  106. return super(MixLevelAnnotatorPolicy, pol).default_specialize(
  107. funcdesc, args_s)
  108. else:
  109. return AnnotatorPolicy.default_specialize(funcdesc, args_s)
  110. def specialize__arglltype(pol, funcdesc, args_s, i):
  111. key = pol.rtyper.getrepr(args_s[i]).lowleveltype
  112. alt_name = funcdesc.name+"__for_%sLlT" % key._short_name()
  113. return funcdesc.cachedgraph(key, alt_name=valid_identifier(alt_name))
  114. def specialize__genconst(pol, funcdesc, args_s, i):
  115. # XXX this is specific to the JIT
  116. TYPE = annmodel.annotation_to_lltype(args_s[i], 'genconst')
  117. args_s[i] = annmodel.lltype_to_annotation(TYPE)
  118. alt_name = funcdesc.name + "__%s" % (TYPE._short_name(),)
  119. return funcdesc.cachedgraph(TYPE, alt_name=valid_identifier(alt_name))
  120. class MixLevelHelperAnnotator(object):
  121. def __init__(self, rtyper):
  122. self.rtyper = rtyper
  123. self.policy = MixLevelAnnotatorPolicy(self)
  124. self.pending = [] # list of (ll_function, graph, args_s, s_result)
  125. self.delayedreprs = {}
  126. self.delayedconsts = []
  127. self.delayedfuncs = []
  128. self.newgraphs = {}
  129. def getgraph(self, ll_function, args_s, s_result):
  130. # get the graph of the mix-level helper ll_function and prepare it for
  131. # being annotated. Annotation and RTyping should be done in a single shot
  132. # at the end with finish().
  133. graph, args_s = self.rtyper.annotator.get_call_parameters(
  134. ll_function, args_s, policy = self.policy)
  135. for v_arg, s_arg in zip(graph.getargs(), args_s):
  136. self.rtyper.annotator.setbinding(v_arg, s_arg)
  137. self.rtyper.annotator.setbinding(graph.getreturnvar(), s_result)
  138. #self.rtyper.annotator.annotated[graph.returnblock] = graph
  139. self.pending.append((ll_function, graph, args_s, s_result))
  140. return graph
  141. def delayedfunction(self, ll_function, args_s, s_result, needtype=False):
  142. # get a delayed pointer to the low-level function, annotated as
  143. # specified. The pointer is only valid after finish() was called.
  144. graph = self.getgraph(ll_function, args_s, s_result)
  145. if needtype:
  146. ARGS = [self.getdelayedrepr(s_arg, False).lowleveltype
  147. for s_arg in args_s]
  148. RESULT = self.getdelayedrepr(s_result, False).lowleveltype
  149. FUNCTYPE = lltype.FuncType(ARGS, RESULT)
  150. else:
  151. FUNCTYPE = None
  152. return self.graph2delayed(graph, FUNCTYPE)
  153. def constfunc(self, ll_function, args_s, s_result):
  154. p = self.delayedfunction(ll_function, args_s, s_result)
  155. return Constant(p, lltype.typeOf(p))
  156. def graph2delayed(self, graph, FUNCTYPE=None):
  157. if self.rtyper.type_system.name == 'lltypesystem':
  158. if FUNCTYPE is None:
  159. FUNCTYPE = lltype.ForwardReference()
  160. # obscure hack: embed the name of the function in the string, so
  161. # that the genc database can get it even before the delayedptr
  162. # is really computed
  163. name = "delayed!%s" % (graph.name,)
  164. delayedptr = lltype._ptr(lltype.Ptr(FUNCTYPE), name, solid=True)
  165. else:
  166. if FUNCTYPE is None:
  167. FUNCTYPE = ootype.ForwardReference()
  168. name = "delayed!%s" % (graph.name,)
  169. delayedptr = ootype._forward_static_meth(FUNCTYPE, _name=name)
  170. self.delayedfuncs.append((delayedptr, graph))
  171. return delayedptr
  172. def graph2const(self, graph):
  173. p = self.graph2delayed(graph)
  174. return Constant(p, lltype.typeOf(p))
  175. def getdelayedrepr(self, s_value, check_never_seen=True):
  176. """Like rtyper.getrepr(), but the resulting repr will not be setup() at
  177. all before finish() is called.
  178. """
  179. r = self.rtyper.getrepr(s_value)
  180. if check_never_seen:
  181. r.set_setup_delayed(True)
  182. delayed = True
  183. else:
  184. delayed = r.set_setup_maybe_delayed()
  185. if delayed:
  186. self.delayedreprs[r] = True
  187. return r
  188. def s_r_instanceof(self, cls, can_be_None=True, check_never_seen=True):
  189. classdesc = self.rtyper.annotator.bookkeeper.getdesc(cls)
  190. classdef = classdesc.getuniqueclassdef()
  191. s_instance = annmodel.SomeInstance(classdef, can_be_None)
  192. r_instance = self.getdelayedrepr(s_instance, check_never_seen)
  193. return s_instance, r_instance
  194. def delayedconst(self, repr, obj):
  195. if repr.is_setup_delayed():
  196. # record the existence of this 'obj' for the bookkeeper - e.g.
  197. # if 'obj' is an instance, this will populate the classdef with
  198. # the prebuilt attribute values of the instance
  199. bk = self.rtyper.annotator.bookkeeper
  200. bk.immutablevalue(obj)
  201. if self.rtyper.type_system.name == 'lltypesystem':
  202. delayedptr = lltype._ptr(repr.lowleveltype, "delayed!")
  203. else:
  204. delayedptr = ootype.make_instance(repr.lowleveltype)
  205. self.delayedconsts.append((delayedptr, repr, obj))
  206. return delayedptr
  207. else:
  208. return repr.convert_const(obj)
  209. def finish(self):
  210. self.finish_annotate()
  211. self.finish_rtype()
  212. def finish_annotate(self):
  213. # push all the graphs into the annotator's pending blocks dict at once
  214. rtyper = self.rtyper
  215. ann = rtyper.annotator
  216. bk = ann.bookkeeper
  217. translator = ann.translator
  218. original_graph_count = len(translator.graphs)
  219. for ll_function, graph, args_s, s_result in self.pending:
  220. # mark the return block as already annotated, because the return var
  221. # annotation was forced in getgraph() above. This prevents temporary
  222. # less general values reaching the return block from crashing the
  223. # annotator (on the assert-that-new-binding-is-not-less-general).
  224. ann.annotated[graph.returnblock] = graph
  225. s_function = bk.immutablevalue(ll_function)
  226. bk.emulate_pbc_call(graph, s_function, args_s)
  227. self.newgraphs[graph] = True
  228. ann.complete_helpers(self.policy)
  229. for ll_function, graph, args_s, s_result in self.pending:
  230. s_real_result = ann.binding(graph.getreturnvar())
  231. if s_real_result != s_result:
  232. raise Exception("wrong annotation for the result of %r:\n"
  233. "originally specified: %r\n"
  234. " found by annotating: %r" %
  235. (graph, s_result, s_real_result))
  236. del self.pending[:]
  237. for graph in translator.graphs[original_graph_count:]:
  238. self.newgraphs[graph] = True
  239. def finish_rtype(self):
  240. rtyper = self.rtyper
  241. translator = rtyper.annotator.translator
  242. original_graph_count = len(translator.graphs)
  243. rtyper.type_system.perform_normalizations(rtyper)
  244. for r in self.delayedreprs:
  245. r.set_setup_delayed(False)
  246. rtyper.call_all_setups()
  247. for p, repr, obj in self.delayedconsts:
  248. p._become(repr.convert_const(obj))
  249. rtyper.call_all_setups()
  250. for p, graph in self.delayedfuncs:
  251. self.newgraphs[graph] = True
  252. real_p = rtyper.getcallable(graph)
  253. REAL = get_functype(lltype.typeOf(real_p))
  254. FUNCTYPE = get_functype(lltype.typeOf(p))
  255. if isinstance(FUNCTYPE, (lltype.ForwardReference, ootype.ForwardReference)):
  256. FUNCTYPE.become(REAL)
  257. assert FUNCTYPE == REAL
  258. p._become(real_p)
  259. rtyper.specialize_more_blocks()
  260. self.delayedreprs.clear()
  261. del self.delayedconsts[:]
  262. del self.delayedfuncs[:]
  263. for graph in translator.graphs[original_graph_count:]:
  264. self.newgraphs[graph] = True
  265. def backend_optimize(self, **flags):
  266. # only optimize the newly created graphs
  267. from pypy.translator.backendopt.all import backend_optimizations
  268. translator = self.rtyper.annotator.translator
  269. newgraphs = self.newgraphs.keys()
  270. backend_optimizations(translator, newgraphs, secondary=True, **flags)
  271. self.newgraphs.clear()
  272. # ____________________________________________________________
  273. class PseudoHighLevelCallable(object):
  274. """A gateway to a low-level function pointer. To high-level RPython
  275. code it looks like a normal function, taking high-level arguments
  276. and returning a high-level result.
  277. """
  278. def __init__(self, llfnptr, args_s, s_result):
  279. self.llfnptr = llfnptr
  280. self.args_s = args_s
  281. self.s_result = s_result
  282. def __call__(self, *args):
  283. raise Exception("PseudoHighLevelCallable objects are not really "
  284. "callable directly")
  285. class PseudoHighLevelCallableEntry(extregistry.ExtRegistryEntry):
  286. _type_ = PseudoHighLevelCallable
  287. def compute_result_annotation(self, *args_s):
  288. return self.instance.s_result
  289. def specialize_call(self, hop):
  290. args_r = [hop.rtyper.getrepr(s) for s in self.instance.args_s]
  291. r_res = hop.rtyper.getrepr(self.instance.s_result)
  292. vlist = hop.inputargs(*args_r)
  293. p = self.instance.llfnptr
  294. TYPE = lltype.typeOf(p)
  295. c_func = Constant(p, TYPE)
  296. FUNCTYPE = get_functype(TYPE)
  297. for r_arg, ARGTYPE in zip(args_r, FUNCTYPE.ARGS):
  298. assert r_arg.lowleveltype == ARGTYPE
  299. assert r_res.lowleveltype == FUNCTYPE.RESULT
  300. hop.exception_is_here()
  301. return hop.genop('direct_call', [c_func] + vlist, resulttype = r_res)
  302. # ____________________________________________________________
  303. def llhelper(F, f):
  304. """Gives a low-level function pointer of type F which, when called,
  305. invokes the RPython function f().
  306. """
  307. # Example - the following code can be either run or translated:
  308. #
  309. # def my_rpython_code():
  310. # g = llhelper(F, my_other_rpython_function)
  311. # assert typeOf(g) == F
  312. # ...
  313. # g()
  314. #
  315. # however the following doesn't translate (xxx could be fixed with hacks):
  316. #
  317. # prebuilt_g = llhelper(F, f)
  318. # def my_rpython_code():
  319. # prebuilt_g()
  320. # the next line is the implementation for the purpose of direct running
  321. if isinstance(F, ootype.OOType):
  322. return ootype.static_meth(F, f.func_name, _callable=f)
  323. else:
  324. return lltype.functionptr(F.TO, f.func_name, _callable=f)
  325. class LLHelperEntry(extregistry.ExtRegistryEntry):
  326. _about_ = llhelper
  327. def compute_result_annotation(self, s_F, s_callable):
  328. assert s_F.is_constant()
  329. assert s_callable.is_constant()
  330. F = s_F.const
  331. if isinstance(F, ootype.OOType):
  332. FUNC = F
  333. resultcls = annmodel.SomeOOStaticMeth
  334. else:
  335. FUNC = F.TO
  336. resultcls = annmodel.SomePtr
  337. args_s = [annmodel.lltype_to_annotation(T) for T in FUNC.ARGS]
  338. key = (llhelper, s_callable.const)
  339. s_res = self.bookkeeper.emulate_pbc_call(key, s_callable, args_s)
  340. assert annmodel.lltype_to_annotation(FUNC.RESULT).contains(s_res)
  341. return resultcls(F)
  342. def specialize_call(self, hop):
  343. hop.exception_cannot_occur()
  344. return hop.args_r[1].get_unique_llfn()
  345. # ____________________________________________________________
  346. def make_string_entries(strtype):
  347. assert strtype in (str, unicode)
  348. def hlstr(ll_s):
  349. if not ll_s:
  350. return None
  351. if hasattr(ll_s, 'chars'):
  352. if strtype is str:
  353. return ''.join(ll_s.chars)
  354. else:
  355. return u''.join(ll_s.chars)
  356. else:
  357. return ll_s._str
  358. class HLStrEntry(extregistry.ExtRegistryEntry):
  359. _about_ = hlstr
  360. def compute_result_annotation(self, s_ll_str):
  361. if strtype is str:
  362. return annmodel.SomeString(can_be_None=True)
  363. else:
  364. return annmodel.SomeUnicodeString(can_be_None=True)
  365. def specialize_call(self, hop):
  366. hop.exception_cannot_occur()
  367. assert hop.args_r[0].lowleveltype == hop.r_result.lowleveltype
  368. v_ll_str, = hop.inputargs(*hop.args_r)
  369. return hop.genop('same_as', [v_ll_str],
  370. resulttype = hop.r_result.lowleveltype)
  371. def llstr(s):
  372. from pypy.rpython.lltypesystem.rstr import mallocstr, mallocunicode
  373. from pypy.rpython.lltypesystem.rstr import STR, UNICODE
  374. if strtype is str:
  375. if s is None:
  376. return lltype.nullptr(STR)
  377. ll_s = mallocstr(len(s))
  378. else:
  379. if s is None:
  380. return lltype.nullptr(UNICODE)
  381. ll_s = mallocunicode(len(s))
  382. for i, c in enumerate(s):
  383. ll_s.chars[i] = c
  384. return ll_s
  385. def oostr(s):
  386. if strtype is str:
  387. return ootype.make_string(s)
  388. else:
  389. return ootype.make_unicode(s)
  390. class LLStrEntry(extregistry.ExtRegistryEntry):
  391. _about_ = llstr
  392. def compute_result_annotation(self, s_str):
  393. from pypy.rpython.lltypesystem.rstr import STR, UNICODE
  394. if strtype is str:
  395. return annmodel.lltype_to_annotation(lltype.Ptr(STR))
  396. else:
  397. return annmodel.lltype_to_annotation(lltype.Ptr(UNICODE))
  398. def specialize_call(self, hop):
  399. hop.exception_cannot_occur()
  400. assert hop.args_r[0].lowleveltype == hop.r_result.lowleveltype
  401. v_ll_str, = hop.inputargs(*hop.args_r)
  402. return hop.genop('same_as', [v_ll_str],
  403. resulttype = hop.r_result.lowleveltype)
  404. class OOStrEntry(extregistry.ExtRegistryEntry):
  405. _about_ = oostr
  406. def compute_result_annotation(self, s_str):
  407. if strtype is str:
  408. return annmodel.lltype_to_annotation(ootype.String)
  409. else:
  410. return annmodel.lltype_to_annotation(ootype.Unicode)
  411. specialize_call = LLStrEntry.specialize_call.im_func
  412. return hlstr, llstr, oostr
  413. hlstr, llstr, oostr = make_string_entries(str)
  414. hlunicode, llunicode, oounicode = make_string_entries(unicode)
  415. # ____________________________________________________________
  416. def cast_object_to_ptr(PTR, object):
  417. """NOT_RPYTHON: hack. The object may be disguised as a PTR now.
  418. Limited to casting a given object to a single type.
  419. """
  420. if isinstance(PTR, lltype.Ptr):
  421. TO = PTR.TO
  422. else:
  423. TO = PTR
  424. if not hasattr(object, '_carry_around_for_tests'):
  425. if object is None:
  426. return lltype.nullptr(PTR.TO)
  427. assert not hasattr(object, '_TYPE')
  428. object._carry_around_for_tests = True
  429. object._TYPE = TO
  430. else:
  431. assert object._TYPE == TO
  432. #
  433. if isinstance(PTR, lltype.Ptr):
  434. return lltype._ptr(PTR, object, True)
  435. elif isinstance(PTR, ootype.Instance):
  436. return object
  437. else:
  438. raise NotImplementedError("cast_object_to_ptr(%r, ...)" % PTR)
  439. def cast_instance_to_base_ptr(instance):
  440. return cast_object_to_ptr(base_ptr_lltype(), instance)
  441. cast_instance_to_base_ptr._annspecialcase_ = 'specialize:argtype(0)'
  442. def cast_instance_to_base_obj(instance):
  443. return cast_object_to_ptr(base_obj_ootype(), instance)
  444. cast_instance_to_base_obj._annspecialcase_ = 'specialize:argtype(0)'
  445. def base_ptr_lltype():
  446. from pypy.rpython.lltypesystem.rclass import OBJECTPTR
  447. return OBJECTPTR
  448. def base_obj_ootype():
  449. from pypy.rpython.ootypesystem.rclass import OBJECT
  450. return OBJECT
  451. class CastObjectToPtrEntry(extregistry.ExtRegistryEntry):
  452. _about_ = cast_object_to_ptr
  453. def compute_result_annotation(self, s_PTR, s_object):
  454. assert s_PTR.is_constant()
  455. if isinstance(s_PTR.const, lltype.Ptr):
  456. return annmodel.SomePtr(s_PTR.const)
  457. elif isinstance(s_PTR.const, ootype.Instance):
  458. return annmodel.SomeOOInstance(s_PTR.const)
  459. else:
  460. assert False
  461. def specialize_call(self, hop):
  462. from pypy.rpython import rpbc
  463. PTR = hop.r_result.lowleveltype
  464. if isinstance(PTR, lltype.Ptr):
  465. T = lltype.Ptr
  466. opname = 'cast_pointer'
  467. null = lltype.nullptr(PTR.TO)
  468. elif isinstance(PTR, ootype.Instance):
  469. T = ootype.Instance
  470. opname = 'ooupcast'
  471. null = ootype.null(PTR)
  472. else:
  473. assert False
  474. hop.exception_cannot_occur()
  475. if isinstance(hop.args_r[1], rpbc.NoneFrozenPBCRepr):
  476. return hop.inputconst(PTR, null)
  477. v_arg = hop.inputarg(hop.args_r[1], arg=1)
  478. assert isinstance(v_arg.concretetype, T)
  479. return hop.genop(opname, [v_arg], resulttype = PTR)
  480. # ____________________________________________________________
  481. def cast_base_ptr_to_instance(Class, ptr):
  482. """NOT_RPYTHON: hack. Reverse the hacking done in cast_object_to_ptr()."""
  483. if isinstance(lltype.typeOf(ptr), lltype.Ptr):
  484. ptr = ptr._as_obj()
  485. if ptr is None:
  486. return None
  487. if not isinstance(ptr, Class):
  488. raise NotImplementedError("cast_base_ptr_to_instance: casting %r to %r"
  489. % (ptr, Class))
  490. return ptr
  491. class CastBasePtrToInstanceEntry(extregistry.ExtRegistryEntry):
  492. _about_ = cast_base_ptr_to_instance
  493. def compute_result_annotation(self, s_Class, s_ptr):
  494. assert s_Class.is_constant()
  495. classdef = self.bookkeeper.getuniqueclassdef(s_Class.const)
  496. return annmodel.SomeInstance(classdef, can_be_None=True)
  497. def specialize_call(self, hop):
  498. # XXX: check if there is any test to port from oo-jit/
  499. v_arg = hop.inputarg(hop.args_r[1], arg=1)
  500. if isinstance(v_arg.concretetype, lltype.Ptr):
  501. opname = 'cast_pointer'
  502. elif isinstance(v_arg.concretetype, ootype.Instance):
  503. opname = 'oodowncast'
  504. else:
  505. assert False
  506. hop.exception_cannot_occur()
  507. return hop.genop(opname, [v_arg],
  508. resulttype = hop.r_result.lowleveltype)
  509. # ____________________________________________________________
  510. def placeholder_sigarg(s):
  511. if s == "self":
  512. def expand(s_self, *args_s):
  513. assert isinstance(s_self, annmodel.SomePtr)
  514. return s_self
  515. elif s == "SELF":
  516. raise NotImplementedError
  517. else:
  518. assert s.islower()
  519. def expand(s_self, *args_s):
  520. assert isinstance(s_self, annmodel.SomePtr)
  521. return getattr(s_self.ll_ptrtype.TO, s.upper())
  522. return expand
  523. def typemeth_placeholder_sigarg(s):
  524. if s == "SELF":
  525. def expand(s_TYPE, *args_s):
  526. assert isinstance(s_TYPE, annmodel.SomePBC)
  527. assert s_TYPE.is_constant()
  528. return s_TYPE
  529. elif s == "self":
  530. def expand(s_TYPE, *args_s):
  531. assert isinstance(s_TYPE, annmodel.SomePBC)
  532. assert s_TYPE.is_constant()
  533. return lltype.Ptr(s_TYPE.const)
  534. else:
  535. assert s.islower()
  536. def expand(s_TYPE, *args_s):
  537. assert isinstance(s_TYPE, annmodel.SomePBC)
  538. assert s_TYPE.is_constant()
  539. return getattr(s_TYPE.const, s.upper())
  540. return expand
  541. class ADTInterface(object):
  542. def __init__(self, base, sigtemplates):
  543. self.sigtemplates = sigtemplates
  544. self.base = base
  545. sigs = {}
  546. if base is not None:
  547. sigs.update(base.sigs)
  548. for name, template in sigtemplates.items():
  549. args, result = template
  550. if args[0] == "self":
  551. make_expand = placeholder_sigarg
  552. elif args[0] == "SELF":
  553. make_expand = typemeth_placeholder_sigarg
  554. else:
  555. assert False, ("ADTInterface signature should start with"
  556. " 'SELF' or 'self'")
  557. sigargs = []
  558. for arg in args:
  559. if isinstance(arg, str):
  560. arg = make_expand(arg)
  561. sigargs.append(arg)
  562. sigs[name] = Sig(*sigargs)
  563. self.sigs = sigs
  564. def __call__(self, adtmeths):
  565. for name, sig in self.sigs.items():
  566. meth = adtmeths[name]
  567. prevsig = getattr(meth, '_annenforceargs_', None)
  568. if prevsig:
  569. assert prevsig is sig
  570. else:
  571. meth._annenforceargs_ = sig
  572. return adtmeths
  573. # ____________________________________________________________
  574. class cachedtype(type):
  575. """Metaclass for classes that should only have one instance per
  576. tuple of arguments given to the constructor."""
  577. def __init__(selfcls, name, bases, dict):
  578. super(cachedtype, selfcls).__init__(name, bases, dict)
  579. selfcls._instancecache = {}
  580. def __call__(selfcls, *args):
  581. d = selfcls._instancecache
  582. try:
  583. return d[args]
  584. except KeyError:
  585. instance = d[args] = selfcls.__new__(selfcls, *args)
  586. try:
  587. instance.__init__(*args)
  588. except:
  589. # If __init__ fails, remove the 'instance' from d.
  590. # That's a "best effort" attempt, it's not really enough
  591. # in theory because some other place might have grabbed
  592. # a reference to the same broken 'instance' in the meantime
  593. del d[args]
  594. raise
  595. return instance