PageRenderTime 57ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/rtyper/rpbc.py

https://bitbucket.org/pypy/pypy/
Python | 1191 lines | 1122 code | 57 blank | 12 comment | 83 complexity | 23902ca77e5a7eff1750106855ff9848 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import types
  2. from rpython.flowspace.model import FunctionGraph, Link, Block, SpaceOperation
  3. from rpython.annotator import model as annmodel
  4. from rpython.annotator.description import (
  5. FunctionDesc, MethodDesc, FrozenDesc, MethodOfFrozenDesc)
  6. from rpython.annotator.classdesc import ClassDesc
  7. from rpython.flowspace.model import Constant
  8. from rpython.annotator.argument import simple_args
  9. from rpython.rtyper.debug import ll_assert
  10. from rpython.rlib.unroll import unrolling_iterable
  11. from rpython.rtyper import rclass, callparse
  12. from rpython.rtyper.rclass import CLASSTYPE, OBJECT_VTABLE, OBJECTPTR
  13. from rpython.rtyper.error import TyperError
  14. from rpython.rtyper.lltypesystem import rffi
  15. from rpython.rtyper.lltypesystem import llmemory
  16. from rpython.rtyper.lltypesystem.lltype import (
  17. typeOf, Void, ForwardReference, Struct, Bool, Char, Ptr, malloc, nullptr,
  18. Array, Signed, cast_pointer, getfunctionptr)
  19. from rpython.rtyper.rmodel import (Repr, inputconst, CanBeNull, mangle,
  20. warning, impossible_repr)
  21. from rpython.tool.pairtype import pair, pairtype
  22. from rpython.translator.unsimplify import varoftype
  23. def small_cand(rtyper, s_pbc):
  24. if 1 < len(s_pbc.descriptions) < rtyper.getconfig().translation.withsmallfuncsets:
  25. callfamily = s_pbc.any_description().getcallfamily()
  26. llct = get_concrete_calltable(rtyper, callfamily)
  27. if (len(llct.uniquerows) == 1 and
  28. (not s_pbc.subset_of or small_cand(rtyper, s_pbc.subset_of))):
  29. return True
  30. return False
  31. class __extend__(annmodel.SomePBC):
  32. def rtyper_makerepr(self, rtyper):
  33. kind = self.getKind()
  34. if issubclass(kind, FunctionDesc):
  35. if len(self.descriptions) == 1 and not self.can_be_None:
  36. getRepr = FunctionRepr
  37. else:
  38. sample = self.any_description()
  39. callfamily = sample.querycallfamily()
  40. if callfamily and callfamily.total_calltable_size > 0:
  41. getRepr = FunctionsPBCRepr
  42. if small_cand(rtyper, self):
  43. getRepr = SmallFunctionSetPBCRepr
  44. else:
  45. getRepr = getFrozenPBCRepr
  46. elif issubclass(kind, ClassDesc):
  47. # user classes
  48. getRepr = ClassesPBCRepr
  49. elif issubclass(kind, MethodDesc):
  50. getRepr = MethodsPBCRepr
  51. elif issubclass(kind, FrozenDesc):
  52. getRepr = getFrozenPBCRepr
  53. elif issubclass(kind, MethodOfFrozenDesc):
  54. getRepr = MethodOfFrozenPBCRepr
  55. else:
  56. raise TyperError("unexpected PBC kind %r" % (kind,))
  57. return getRepr(rtyper, self)
  58. def rtyper_makekey(self):
  59. lst = list(self.descriptions)
  60. lst.sort()
  61. if self.subset_of:
  62. t = self.subset_of.rtyper_makekey()
  63. else:
  64. t = ()
  65. return tuple([self.__class__, self.can_be_None] + lst) + t
  66. # ____________________________________________________________
  67. class ConcreteCallTableRow(dict):
  68. """A row in a concrete call table."""
  69. @classmethod
  70. def from_row(cls, rtyper, row):
  71. concreterow = cls()
  72. for funcdesc, graph in row.items():
  73. llfn = rtyper.getcallable(graph)
  74. concreterow[funcdesc] = llfn
  75. assert len(concreterow) > 0
  76. # 'typeOf(llfn)' should be the same for all graphs
  77. concreterow.fntype = typeOf(llfn)
  78. return concreterow
  79. class LLCallTable(object):
  80. """A call table of a call family with low-level functions."""
  81. def __init__(self, table, uniquerows):
  82. self.table = table # (shape,index): row, maybe with duplicates
  83. self.uniquerows = uniquerows # list of rows, without duplicates
  84. def lookup(self, row):
  85. """A 'matching' row is one that has the same llfn, except
  86. that it may have more or less 'holes'."""
  87. for existingindex, existingrow in enumerate(self.uniquerows):
  88. if row.fntype != existingrow.fntype:
  89. continue # not the same pointer type, cannot match
  90. for funcdesc, llfn in row.items():
  91. if funcdesc in existingrow:
  92. if llfn != existingrow[funcdesc]:
  93. break # mismatch
  94. else:
  95. # potential match, unless the two rows have no common funcdesc
  96. merged = ConcreteCallTableRow(row)
  97. merged.update(existingrow)
  98. merged.fntype = row.fntype
  99. if len(merged) == len(row) + len(existingrow):
  100. pass # no common funcdesc, not a match
  101. else:
  102. return existingindex, merged
  103. raise LookupError
  104. def add(self, row):
  105. """Add a row to the table, potentially merging it with an existing row
  106. """
  107. try:
  108. index, merged = self.lookup(row)
  109. except LookupError:
  110. self.uniquerows.append(row) # new row
  111. else:
  112. if merged == self.uniquerows[index]:
  113. pass # already exactly in the table
  114. else:
  115. del self.uniquerows[index]
  116. self.add(merged) # add the potentially larger merged row
  117. def build_concrete_calltable(rtyper, callfamily):
  118. """Build a complete call table of a call family
  119. with concrete low-level function objs.
  120. """
  121. concretetable = {}
  122. uniquerows = []
  123. llct = LLCallTable(concretetable, uniquerows)
  124. concreterows = {}
  125. for shape, rows in callfamily.calltables.items():
  126. for index, row in enumerate(rows):
  127. concreterow = ConcreteCallTableRow.from_row(rtyper, row)
  128. concreterows[shape, index] = concreterow
  129. llct.add(concreterow)
  130. for (shape, index), row in concreterows.items():
  131. existingindex, biggerrow = llct.lookup(row)
  132. row = llct.uniquerows[existingindex]
  133. assert biggerrow == row
  134. llct.table[shape, index] = row
  135. if len(llct.uniquerows) == 1:
  136. llct.uniquerows[0].attrname = None
  137. else:
  138. for finalindex, row in enumerate(llct.uniquerows):
  139. row.attrname = 'variant%d' % finalindex
  140. return llct
  141. def get_concrete_calltable(rtyper, callfamily):
  142. """Get a complete call table of a call family
  143. with concrete low-level function objs.
  144. """
  145. # cache on the callfamily
  146. try:
  147. cached = rtyper.concrete_calltables[callfamily]
  148. except KeyError:
  149. llct = build_concrete_calltable(rtyper, callfamily)
  150. cached = llct, callfamily.total_calltable_size
  151. rtyper.concrete_calltables[callfamily] = cached
  152. else:
  153. llct, oldsize = cached
  154. if oldsize != callfamily.total_calltable_size:
  155. raise TyperError("call table was unexpectedly extended")
  156. return llct
  157. class FunctionReprBase(Repr):
  158. def __init__(self, rtyper, s_pbc):
  159. self.rtyper = rtyper
  160. self.s_pbc = s_pbc
  161. self.callfamily = s_pbc.any_description().getcallfamily()
  162. def get_s_callable(self):
  163. return self.s_pbc
  164. def get_r_implfunc(self):
  165. return self, 0
  166. def get_s_signatures(self, shape):
  167. funcdesc = self.s_pbc.any_description()
  168. return funcdesc.get_s_signatures(shape)
  169. def rtype_simple_call(self, hop):
  170. return self.call(hop)
  171. def rtype_call_args(self, hop):
  172. return self.call(hop)
  173. def call(self, hop):
  174. bk = self.rtyper.annotator.bookkeeper
  175. args = hop.spaceop.build_args(hop.args_s[1:])
  176. s_pbc = hop.args_s[0] # possibly more precise than self.s_pbc
  177. descs = list(s_pbc.descriptions)
  178. shape, index = self.callfamily.find_row(bk, descs, args, hop.spaceop)
  179. row_of_graphs = self.callfamily.calltables[shape][index]
  180. anygraph = row_of_graphs.itervalues().next() # pick any witness
  181. vfn = hop.inputarg(self, arg=0)
  182. vlist = [self.convert_to_concrete_llfn(vfn, shape, index,
  183. hop.llops)]
  184. vlist += callparse.callparse(self.rtyper, anygraph, hop)
  185. rresult = callparse.getrresult(self.rtyper, anygraph)
  186. hop.exception_is_here()
  187. if isinstance(vlist[0], Constant):
  188. v = hop.genop('direct_call', vlist, resulttype=rresult)
  189. else:
  190. vlist.append(hop.inputconst(Void, row_of_graphs.values()))
  191. v = hop.genop('indirect_call', vlist, resulttype=rresult)
  192. if hop.r_result is impossible_repr:
  193. return None # see test_always_raising_methods
  194. else:
  195. return hop.llops.convertvar(v, rresult, hop.r_result)
  196. class FunctionsPBCRepr(CanBeNull, FunctionReprBase):
  197. """Representation selected for a PBC of functions."""
  198. def __init__(self, rtyper, s_pbc):
  199. FunctionReprBase.__init__(self, rtyper, s_pbc)
  200. llct = get_concrete_calltable(self.rtyper, self.callfamily)
  201. self.concretetable = llct.table
  202. self.uniquerows = llct.uniquerows
  203. if len(llct.uniquerows) == 1:
  204. row = llct.uniquerows[0]
  205. self.lowleveltype = row.fntype
  206. else:
  207. # several functions, each with several specialized variants.
  208. # each function becomes a pointer to a Struct containing
  209. # pointers to its variants.
  210. self.lowleveltype = self.setup_specfunc()
  211. self.funccache = {}
  212. def setup_specfunc(self):
  213. fields = []
  214. for row in self.uniquerows:
  215. fields.append((row.attrname, row.fntype))
  216. kwds = {'hints': {'immutable': True}}
  217. return Ptr(Struct('specfunc', *fields, **kwds))
  218. def create_specfunc(self):
  219. return malloc(self.lowleveltype.TO, immortal=True)
  220. def get_specfunc_row(self, llop, v, c_rowname, resulttype):
  221. return llop.genop('getfield', [v, c_rowname], resulttype=resulttype)
  222. def convert_desc(self, funcdesc):
  223. # get the whole "column" of the call table corresponding to this desc
  224. try:
  225. return self.funccache[funcdesc]
  226. except KeyError:
  227. pass
  228. llfns = {}
  229. found_anything = False
  230. for row in self.uniquerows:
  231. if funcdesc in row:
  232. llfn = row[funcdesc]
  233. found_anything = True
  234. else:
  235. # missing entry -- need a 'null' of the type that matches
  236. # this row
  237. llfn = nullptr(row.fntype.TO)
  238. llfns[row.attrname] = llfn
  239. if len(self.uniquerows) == 1:
  240. if found_anything:
  241. result = llfn # from the loop above
  242. else:
  243. # extremely rare case, shown only sometimes by
  244. # test_bug_callfamily: don't emit NULL, because that
  245. # would be interpreted as equal to None... It should
  246. # never be called anyway.
  247. result = rffi.cast(self.lowleveltype, ~len(self.funccache))
  248. else:
  249. # build a Struct with all the values collected in 'llfns'
  250. result = self.create_specfunc()
  251. for attrname, llfn in llfns.items():
  252. setattr(result, attrname, llfn)
  253. self.funccache[funcdesc] = result
  254. return result
  255. def convert_const(self, value):
  256. if isinstance(value, types.MethodType) and value.im_self is None:
  257. value = value.im_func # unbound method -> bare function
  258. elif isinstance(value, staticmethod):
  259. value = value.__get__(42) # hackish, get the function wrapped by staticmethod
  260. if value is None:
  261. null = nullptr(self.lowleveltype.TO)
  262. return null
  263. funcdesc = self.rtyper.annotator.bookkeeper.getdesc(value)
  264. return self.convert_desc(funcdesc)
  265. def convert_to_concrete_llfn(self, v, shape, index, llop):
  266. """Convert the variable 'v' to a variable referring to a concrete
  267. low-level function. In case the call table contains multiple rows,
  268. 'index' and 'shape' tells which of its items we are interested in.
  269. """
  270. assert v.concretetype == self.lowleveltype
  271. if len(self.uniquerows) == 1:
  272. return v
  273. else:
  274. # 'v' is a Struct pointer, read the corresponding field
  275. row = self.concretetable[shape, index]
  276. cname = inputconst(Void, row.attrname)
  277. return self.get_specfunc_row(llop, v, cname, row.fntype)
  278. class FunctionRepr(FunctionReprBase):
  279. """Repr for a constant function"""
  280. lowleveltype = Void
  281. def convert_desc(self, funcdesc):
  282. return None
  283. def convert_const(self, value):
  284. return None
  285. def convert_to_concrete_llfn(self, v, shape, index, llop):
  286. """Convert the variable 'v' to a variable referring to a concrete
  287. low-level function. In case the call table contains multiple rows,
  288. 'index' and 'shape' tells which of its items we are interested in.
  289. """
  290. assert v.concretetype == Void
  291. funcdesc, = self.s_pbc.descriptions
  292. row_of_one_graph = self.callfamily.calltables[shape][index]
  293. graph = row_of_one_graph[funcdesc]
  294. llfn = self.rtyper.getcallable(graph)
  295. return inputconst(typeOf(llfn), llfn)
  296. def get_unique_llfn(self):
  297. # try to build a unique low-level function. Avoid to use
  298. # whenever possible! Doesn't work with specialization, multiple
  299. # different call sites, etc.
  300. funcdesc, = self.s_pbc.descriptions
  301. tables = [] # find the simple call in the calltable
  302. for shape, table in self.callfamily.calltables.items():
  303. if not shape[1] and not shape[2]:
  304. tables.append(table)
  305. if len(tables) != 1:
  306. raise TyperError("cannot pass a function with various call shapes")
  307. table, = tables
  308. graphs = []
  309. for row in table:
  310. if funcdesc in row:
  311. graphs.append(row[funcdesc])
  312. if not graphs:
  313. raise TyperError("cannot pass here a function that is not called")
  314. graph = graphs[0]
  315. if graphs != [graph] * len(graphs):
  316. raise TyperError("cannot pass a specialized function here")
  317. llfn = self.rtyper.getcallable(graph)
  318. return inputconst(typeOf(llfn), llfn)
  319. def get_concrete_llfn(self, s_pbc, args_s, op):
  320. bk = self.rtyper.annotator.bookkeeper
  321. funcdesc, = s_pbc.descriptions
  322. args = simple_args(args_s)
  323. with bk.at_position(None):
  324. graph = funcdesc.get_graph(args, op)
  325. llfn = self.rtyper.getcallable(graph)
  326. return inputconst(typeOf(llfn), llfn)
  327. class __extend__(pairtype(FunctionRepr, FunctionRepr)):
  328. def convert_from_to((r_fpbc1, r_fpbc2), v, llops):
  329. return v
  330. class __extend__(pairtype(FunctionRepr, FunctionsPBCRepr)):
  331. def convert_from_to((r_fpbc1, r_fpbc2), v, llops):
  332. return inputconst(r_fpbc2, r_fpbc1.s_pbc.const)
  333. class __extend__(pairtype(FunctionsPBCRepr, FunctionRepr)):
  334. def convert_from_to((r_fpbc1, r_fpbc2), v, llops):
  335. return inputconst(Void, None)
  336. class __extend__(pairtype(FunctionsPBCRepr, FunctionsPBCRepr)):
  337. def convert_from_to((r_fpbc1, r_fpbc2), v, llops):
  338. # this check makes sense because both source and dest repr are FunctionsPBCRepr
  339. if r_fpbc1.lowleveltype == r_fpbc2.lowleveltype:
  340. return v
  341. return NotImplemented
  342. class SmallFunctionSetPBCRepr(FunctionReprBase):
  343. def __init__(self, rtyper, s_pbc):
  344. FunctionReprBase.__init__(self, rtyper, s_pbc)
  345. llct = get_concrete_calltable(self.rtyper, self.callfamily)
  346. assert len(llct.uniquerows) == 1
  347. self.lowleveltype = Char
  348. self.pointer_repr = FunctionsPBCRepr(rtyper, s_pbc)
  349. self._conversion_tables = {}
  350. self._compression_function = None
  351. self._dispatch_cache = {}
  352. def _setup_repr(self):
  353. if self.s_pbc.subset_of:
  354. assert self.s_pbc.can_be_None == self.s_pbc.subset_of.can_be_None
  355. r = self.rtyper.getrepr(self.s_pbc.subset_of)
  356. if r is not self:
  357. r.setup()
  358. self.descriptions = r.descriptions
  359. self.c_pointer_table = r.c_pointer_table
  360. return
  361. self.descriptions = list(self.s_pbc.descriptions)
  362. if self.s_pbc.can_be_None:
  363. self.descriptions.insert(0, None)
  364. POINTER_TABLE = Array(self.pointer_repr.lowleveltype,
  365. hints={'nolength': True, 'immutable': True})
  366. pointer_table = malloc(POINTER_TABLE, len(self.descriptions),
  367. immortal=True)
  368. for i, desc in enumerate(self.descriptions):
  369. if desc is not None:
  370. pointer_table[i] = self.pointer_repr.convert_desc(desc)
  371. else:
  372. pointer_table[i] = self.pointer_repr.convert_const(None)
  373. self.c_pointer_table = inputconst(Ptr(POINTER_TABLE), pointer_table)
  374. def convert_desc(self, funcdesc):
  375. return chr(self.descriptions.index(funcdesc))
  376. def convert_const(self, value):
  377. if isinstance(value, types.MethodType) and value.im_self is None:
  378. value = value.im_func # unbound method -> bare function
  379. if value is None:
  380. assert self.descriptions[0] is None
  381. return chr(0)
  382. funcdesc = self.rtyper.annotator.bookkeeper.getdesc(value)
  383. return self.convert_desc(funcdesc)
  384. def special_uninitialized_value(self):
  385. return chr(0xFF)
  386. def dispatcher(self, shape, index, argtypes, resulttype):
  387. key = shape, index, tuple(argtypes), resulttype
  388. if key in self._dispatch_cache:
  389. return self._dispatch_cache[key]
  390. graph = self.make_dispatcher(shape, index, argtypes, resulttype)
  391. self.rtyper.annotator.translator.graphs.append(graph)
  392. ll_ret = getfunctionptr(graph)
  393. c_ret = self._dispatch_cache[key] = inputconst(typeOf(ll_ret), ll_ret)
  394. return c_ret
  395. def make_dispatcher(self, shape, index, argtypes, resulttype):
  396. inputargs = [varoftype(t) for t in [Char] + argtypes]
  397. startblock = Block(inputargs)
  398. startblock.exitswitch = inputargs[0]
  399. graph = FunctionGraph("dispatcher", startblock, varoftype(resulttype))
  400. row_of_graphs = self.callfamily.calltables[shape][index]
  401. links = []
  402. descs = list(self.s_pbc.descriptions)
  403. if self.s_pbc.can_be_None:
  404. descs.insert(0, None)
  405. for desc in descs:
  406. if desc is None:
  407. continue
  408. args_v = [varoftype(t) for t in argtypes]
  409. b = Block(args_v)
  410. llfn = self.rtyper.getcallable(row_of_graphs[desc])
  411. v_fn = inputconst(typeOf(llfn), llfn)
  412. v_result = varoftype(resulttype)
  413. b.operations.append(
  414. SpaceOperation("direct_call", [v_fn] + args_v, v_result))
  415. b.closeblock(Link([v_result], graph.returnblock))
  416. i = self.descriptions.index(desc)
  417. links.append(Link(inputargs[1:], b, chr(i)))
  418. links[-1].llexitcase = chr(i)
  419. startblock.closeblock(*links)
  420. return graph
  421. def call(self, hop):
  422. bk = self.rtyper.annotator.bookkeeper
  423. args = hop.spaceop.build_args(hop.args_s[1:])
  424. s_pbc = hop.args_s[0] # possibly more precise than self.s_pbc
  425. descs = list(s_pbc.descriptions)
  426. shape, index = self.callfamily.find_row(bk, descs, args, hop.spaceop)
  427. row_of_graphs = self.callfamily.calltables[shape][index]
  428. anygraph = row_of_graphs.itervalues().next() # pick any witness
  429. vlist = [hop.inputarg(self, arg=0)]
  430. vlist += callparse.callparse(self.rtyper, anygraph, hop)
  431. rresult = callparse.getrresult(self.rtyper, anygraph)
  432. hop.exception_is_here()
  433. v_dispatcher = self.dispatcher(shape, index,
  434. [v.concretetype for v in vlist[1:]], rresult.lowleveltype)
  435. v_result = hop.genop('direct_call', [v_dispatcher] + vlist,
  436. resulttype=rresult)
  437. return hop.llops.convertvar(v_result, rresult, hop.r_result)
  438. def rtype_bool(self, hop):
  439. if not self.s_pbc.can_be_None:
  440. return inputconst(Bool, True)
  441. else:
  442. v1, = hop.inputargs(self)
  443. return hop.genop('char_ne', [v1, inputconst(Char, '\000')],
  444. resulttype=Bool)
  445. class __extend__(pairtype(SmallFunctionSetPBCRepr, FunctionRepr)):
  446. def convert_from_to((r_set, r_ptr), v, llops):
  447. return inputconst(Void, None)
  448. class __extend__(pairtype(SmallFunctionSetPBCRepr, FunctionsPBCRepr)):
  449. def convert_from_to((r_set, r_ptr), v, llops):
  450. assert v.concretetype is Char
  451. v_int = llops.genop('cast_char_to_int', [v], resulttype=Signed)
  452. return llops.genop('getarrayitem', [r_set.c_pointer_table, v_int],
  453. resulttype=r_ptr.lowleveltype)
  454. def compression_function(r_set):
  455. if r_set._compression_function is None:
  456. table = []
  457. for i, p in enumerate(r_set.c_pointer_table.value):
  458. table.append((chr(i), p))
  459. last_c, last_p = table[-1]
  460. unroll_table = unrolling_iterable(table[:-1])
  461. def ll_compress(fnptr):
  462. for c, p in unroll_table:
  463. if fnptr == p:
  464. return c
  465. else:
  466. ll_assert(fnptr == last_p, "unexpected function pointer")
  467. return last_c
  468. r_set._compression_function = ll_compress
  469. return r_set._compression_function
  470. class __extend__(pairtype(FunctionRepr, SmallFunctionSetPBCRepr)):
  471. def convert_from_to((r_ptr, r_set), v, llops):
  472. desc, = r_ptr.s_pbc.descriptions
  473. return inputconst(Char, r_set.convert_desc(desc))
  474. class __extend__(pairtype(FunctionsPBCRepr, SmallFunctionSetPBCRepr)):
  475. def convert_from_to((r_ptr, r_set), v, llops):
  476. ll_compress = compression_function(r_set)
  477. return llops.gendirectcall(ll_compress, v)
  478. class __extend__(pairtype(FunctionReprBase, FunctionReprBase)):
  479. def rtype_is_((robj1, robj2), hop):
  480. if hop.s_result.is_constant():
  481. return inputconst(Bool, hop.s_result.const)
  482. s_pbc = annmodel.unionof(robj1.s_pbc, robj2.s_pbc)
  483. r_pbc = hop.rtyper.getrepr(s_pbc)
  484. v1, v2 = hop.inputargs(r_pbc, r_pbc)
  485. assert v1.concretetype == v2.concretetype
  486. if v1.concretetype == Char:
  487. return hop.genop('char_eq', [v1, v2], resulttype=Bool)
  488. elif isinstance(v1.concretetype, Ptr):
  489. return hop.genop('ptr_eq', [v1, v2], resulttype=Bool)
  490. else:
  491. raise TyperError("unknown type %r" % (v1.concretetype,))
  492. def conversion_table(r_from, r_to):
  493. if r_to in r_from._conversion_tables:
  494. return r_from._conversion_tables[r_to]
  495. else:
  496. t = malloc(Array(Char, hints={'nolength': True, 'immutable': True}),
  497. len(r_from.descriptions), immortal=True)
  498. l = []
  499. for i, d in enumerate(r_from.descriptions):
  500. if d in r_to.descriptions:
  501. j = r_to.descriptions.index(d)
  502. l.append(j)
  503. t[i] = chr(j)
  504. else:
  505. l.append(None)
  506. if l == range(len(r_from.descriptions)):
  507. r = None
  508. else:
  509. r = inputconst(typeOf(t), t)
  510. r_from._conversion_tables[r_to] = r
  511. return r
  512. class __extend__(pairtype(SmallFunctionSetPBCRepr, SmallFunctionSetPBCRepr)):
  513. def convert_from_to((r_from, r_to), v, llops):
  514. c_table = conversion_table(r_from, r_to)
  515. if c_table:
  516. assert v.concretetype is Char
  517. v_int = llops.genop('cast_char_to_int', [v],
  518. resulttype=Signed)
  519. return llops.genop('getarrayitem', [c_table, v_int],
  520. resulttype=Char)
  521. else:
  522. return v
  523. def getFrozenPBCRepr(rtyper, s_pbc):
  524. descs = list(s_pbc.descriptions)
  525. assert len(descs) >= 1
  526. if len(descs) == 1 and not s_pbc.can_be_None:
  527. return SingleFrozenPBCRepr(descs[0])
  528. else:
  529. access = descs[0].queryattrfamily()
  530. for desc in descs[1:]:
  531. access1 = desc.queryattrfamily()
  532. if access1 is not access:
  533. try:
  534. return rtyper.pbc_reprs['unrelated']
  535. except KeyError:
  536. result = MultipleUnrelatedFrozenPBCRepr(rtyper)
  537. rtyper.pbc_reprs['unrelated'] = result
  538. return result
  539. try:
  540. return rtyper.pbc_reprs[access]
  541. except KeyError:
  542. result = MultipleFrozenPBCRepr(rtyper, access)
  543. rtyper.pbc_reprs[access] = result
  544. rtyper.add_pendingsetup(result)
  545. return result
  546. class SingleFrozenPBCRepr(Repr):
  547. """Representation selected for a single non-callable pre-built constant."""
  548. lowleveltype = Void
  549. def __init__(self, frozendesc):
  550. self.frozendesc = frozendesc
  551. def rtype_getattr(_, hop):
  552. if not hop.s_result.is_constant():
  553. raise TyperError("getattr on a constant PBC returns a non-constant")
  554. return hop.inputconst(hop.r_result, hop.s_result.const)
  555. def convert_desc(self, frozendesc):
  556. assert frozendesc is self.frozendesc
  557. return object() # lowleveltype is Void
  558. def convert_const(self, value):
  559. return None
  560. def getstr(self):
  561. return str(self.frozendesc)
  562. getstr._annspecialcase_ = 'specialize:memo'
  563. def ll_str(self, x):
  564. return self.getstr()
  565. class MultipleFrozenPBCReprBase(CanBeNull, Repr):
  566. def convert_const(self, pbc):
  567. if pbc is None:
  568. return self.null_instance()
  569. frozendesc = self.rtyper.annotator.bookkeeper.getdesc(pbc)
  570. return self.convert_desc(frozendesc)
  571. class MultipleUnrelatedFrozenPBCRepr(MultipleFrozenPBCReprBase):
  572. """For a SomePBC of frozen PBCs that have no common access set.
  573. The only possible operation on such a thing is comparison with 'is'."""
  574. lowleveltype = llmemory.Address
  575. EMPTY = Struct('pbc', hints={'immutable': True})
  576. def __init__(self, rtyper):
  577. self.rtyper = rtyper
  578. self.converted_pbc_cache = {}
  579. def convert_desc(self, frozendesc):
  580. try:
  581. return self.converted_pbc_cache[frozendesc]
  582. except KeyError:
  583. r = self.rtyper.getrepr(annmodel.SomePBC([frozendesc]))
  584. if r.lowleveltype is Void:
  585. # must create a new empty structure, as a placeholder
  586. pbc = self.create_instance()
  587. else:
  588. pbc = r.convert_desc(frozendesc)
  589. convpbc = self.convert_pbc(pbc)
  590. self.converted_pbc_cache[frozendesc] = convpbc
  591. return convpbc
  592. def convert_pbc(self, pbcptr):
  593. return llmemory.fakeaddress(pbcptr)
  594. def create_instance(self):
  595. return malloc(self.EMPTY, immortal=True)
  596. def null_instance(self):
  597. return llmemory.Address._defl()
  598. def rtype_getattr(_, hop):
  599. if not hop.s_result.is_constant():
  600. raise TyperError("getattr on a constant PBC returns a non-constant")
  601. return hop.inputconst(hop.r_result, hop.s_result.const)
  602. class __extend__(pairtype(MultipleUnrelatedFrozenPBCRepr,
  603. MultipleUnrelatedFrozenPBCRepr),
  604. pairtype(MultipleUnrelatedFrozenPBCRepr,
  605. SingleFrozenPBCRepr),
  606. pairtype(SingleFrozenPBCRepr,
  607. MultipleUnrelatedFrozenPBCRepr)):
  608. def rtype_is_((robj1, robj2), hop):
  609. if isinstance(robj1, MultipleUnrelatedFrozenPBCRepr):
  610. r = robj1
  611. else:
  612. r = robj2
  613. vlist = hop.inputargs(r, r)
  614. return hop.genop('adr_eq', vlist, resulttype=Bool)
  615. class MultipleFrozenPBCRepr(MultipleFrozenPBCReprBase):
  616. """For a SomePBC of frozen PBCs with a common attribute access set."""
  617. def __init__(self, rtyper, access_set):
  618. self.rtyper = rtyper
  619. self.access_set = access_set
  620. self.pbc_type = ForwardReference()
  621. self.lowleveltype = Ptr(self.pbc_type)
  622. self.pbc_cache = {}
  623. def _setup_repr(self):
  624. llfields = self._setup_repr_fields()
  625. kwds = {'hints': {'immutable': True}}
  626. self.pbc_type.become(Struct('pbc', *llfields, **kwds))
  627. def create_instance(self):
  628. return malloc(self.pbc_type, immortal=True)
  629. def null_instance(self):
  630. return nullptr(self.pbc_type)
  631. def getfield(self, vpbc, attr, llops):
  632. mangled_name, r_value = self.fieldmap[attr]
  633. cmangledname = inputconst(Void, mangled_name)
  634. return llops.genop('getfield', [vpbc, cmangledname],
  635. resulttype=r_value)
  636. def _setup_repr_fields(self):
  637. fields = []
  638. self.fieldmap = {}
  639. if self.access_set is not None:
  640. attrlist = self.access_set.attrs.keys()
  641. attrlist.sort()
  642. for attr in attrlist:
  643. s_value = self.access_set.attrs[attr]
  644. r_value = self.rtyper.getrepr(s_value)
  645. mangled_name = mangle('pbc', attr)
  646. fields.append((mangled_name, r_value.lowleveltype))
  647. self.fieldmap[attr] = mangled_name, r_value
  648. return fields
  649. def convert_desc(self, frozendesc):
  650. if (self.access_set is not None and
  651. frozendesc not in self.access_set.descs):
  652. raise TyperError("not found in PBC access set: %r" % (frozendesc,))
  653. try:
  654. return self.pbc_cache[frozendesc]
  655. except KeyError:
  656. self.setup()
  657. result = self.create_instance()
  658. self.pbc_cache[frozendesc] = result
  659. for attr, (mangled_name, r_value) in self.fieldmap.items():
  660. if r_value.lowleveltype is Void:
  661. continue
  662. try:
  663. thisattrvalue = frozendesc.attrcache[attr]
  664. except KeyError:
  665. if frozendesc.warn_missing_attribute(attr):
  666. warning("Desc %r has no attribute %r" % (frozendesc, attr))
  667. continue
  668. llvalue = r_value.convert_const(thisattrvalue)
  669. setattr(result, mangled_name, llvalue)
  670. return result
  671. def rtype_getattr(self, hop):
  672. if hop.s_result.is_constant():
  673. return hop.inputconst(hop.r_result, hop.s_result.const)
  674. attr = hop.args_s[1].const
  675. vpbc, vattr = hop.inputargs(self, Void)
  676. v_res = self.getfield(vpbc, attr, hop.llops)
  677. mangled_name, r_res = self.fieldmap[attr]
  678. return hop.llops.convertvar(v_res, r_res, hop.r_result)
  679. class __extend__(pairtype(MultipleFrozenPBCRepr,
  680. MultipleUnrelatedFrozenPBCRepr)):
  681. def convert_from_to((robj1, robj2), v, llops):
  682. return llops.genop('cast_ptr_to_adr', [v], resulttype=llmemory.Address)
  683. class __extend__(pairtype(MultipleFrozenPBCRepr, MultipleFrozenPBCRepr)):
  684. def convert_from_to((r_pbc1, r_pbc2), v, llops):
  685. if r_pbc1.access_set == r_pbc2.access_set:
  686. return v
  687. return NotImplemented
  688. class __extend__(pairtype(SingleFrozenPBCRepr, MultipleFrozenPBCRepr)):
  689. def convert_from_to((r_pbc1, r_pbc2), v, llops):
  690. frozendesc1 = r_pbc1.frozendesc
  691. access = frozendesc1.queryattrfamily()
  692. if access is r_pbc2.access_set:
  693. value = r_pbc2.convert_desc(frozendesc1)
  694. lltype = r_pbc2.lowleveltype
  695. return Constant(value, lltype)
  696. return NotImplemented
  697. class __extend__(pairtype(MultipleFrozenPBCReprBase,
  698. SingleFrozenPBCRepr)):
  699. def convert_from_to((r_pbc1, r_pbc2), v, llops):
  700. return inputconst(Void, r_pbc2.frozendesc)
  701. class MethodOfFrozenPBCRepr(Repr):
  702. """Representation selected for a PBC of method object(s) of frozen PBCs.
  703. It assumes that all methods are the same function bound to different PBCs.
  704. The low-level representation can then be a pointer to that PBC."""
  705. def __init__(self, rtyper, s_pbc):
  706. self.rtyper = rtyper
  707. self.funcdesc = s_pbc.any_description().funcdesc
  708. # a hack to force the underlying function to show up in call_families
  709. # (generally not needed, as normalizecalls() should ensure this,
  710. # but needed for bound methods that are ll helpers)
  711. # XXX sort this out
  712. #call_families = rtyper.annotator.getpbccallfamilies()
  713. #call_families.find((None, self.function))
  714. if s_pbc.can_be_none():
  715. raise TyperError("unsupported: variable of type "
  716. "method-of-frozen-PBC or None")
  717. im_selves = []
  718. for desc in s_pbc.descriptions:
  719. if desc.funcdesc is not self.funcdesc:
  720. raise TyperError(
  721. "You can't mix a set of methods on a frozen PBC in "
  722. "RPython that are different underlying functions")
  723. im_selves.append(desc.frozendesc)
  724. self.s_im_self = annmodel.SomePBC(im_selves)
  725. self.r_im_self = rtyper.getrepr(self.s_im_self)
  726. self.lowleveltype = self.r_im_self.lowleveltype
  727. def get_s_callable(self):
  728. return annmodel.SomePBC([self.funcdesc])
  729. def get_r_implfunc(self):
  730. r_func = self.rtyper.getrepr(self.get_s_callable())
  731. return r_func, 1
  732. def convert_desc(self, mdesc):
  733. if mdesc.funcdesc is not self.funcdesc:
  734. raise TyperError("not a method bound on %r: %r" % (self.funcdesc,
  735. mdesc))
  736. return self.r_im_self.convert_desc(mdesc.frozendesc)
  737. def convert_const(self, method):
  738. mdesc = self.rtyper.annotator.bookkeeper.getdesc(method)
  739. return self.convert_desc(mdesc)
  740. def rtype_simple_call(self, hop):
  741. return self.redispatch_call(hop, call_args=False)
  742. def rtype_call_args(self, hop):
  743. return self.redispatch_call(hop, call_args=True)
  744. def redispatch_call(self, hop, call_args):
  745. # XXX obscure, try to refactor...
  746. s_function = annmodel.SomePBC([self.funcdesc])
  747. hop2 = hop.copy()
  748. hop2.args_s[0] = self.s_im_self # make the 1st arg stand for 'im_self'
  749. hop2.args_r[0] = self.r_im_self # (same lowleveltype as 'self')
  750. if isinstance(hop2.args_v[0], Constant):
  751. boundmethod = hop2.args_v[0].value
  752. hop2.args_v[0] = Constant(boundmethod.im_self)
  753. if call_args:
  754. hop2.swap_fst_snd_args()
  755. _, s_shape = hop2.r_s_popfirstarg() # temporarely remove shape
  756. adjust_shape(hop2, s_shape)
  757. # a marker that would crash if actually used...
  758. c = Constant("obscure-don't-use-me")
  759. hop2.v_s_insertfirstarg(c, s_function) # insert 'function'
  760. # now hop2 looks like simple_call(function, self, args...)
  761. return hop2.dispatch()
  762. class __extend__(pairtype(MethodOfFrozenPBCRepr, MethodOfFrozenPBCRepr)):
  763. def convert_from_to((r_from, r_to), v, llops):
  764. return pair(r_from.r_im_self, r_to.r_im_self).convert_from_to(v, llops)
  765. # ____________________________________________________________
  766. class ClassesPBCRepr(Repr):
  767. """Representation selected for a PBC of class(es)."""
  768. def __init__(self, rtyper, s_pbc):
  769. self.rtyper = rtyper
  770. self.s_pbc = s_pbc
  771. #if s_pbc.can_be_None:
  772. # raise TyperError("unsupported: variable of type "
  773. # "class-pointer or None")
  774. if s_pbc.is_constant():
  775. self.lowleveltype = Void
  776. else:
  777. self.lowleveltype = self.getlowleveltype()
  778. def get_access_set(self, attrname):
  779. """Return the ClassAttrFamily corresponding to accesses to 'attrname'
  780. and the ClassRepr of the class which stores this attribute in
  781. its vtable.
  782. """
  783. classdescs = list(self.s_pbc.descriptions)
  784. access = classdescs[0].queryattrfamily(attrname)
  785. for classdesc in classdescs[1:]:
  786. access1 = classdesc.queryattrfamily(attrname)
  787. assert access1 is access # XXX not implemented
  788. if access is None:
  789. raise rclass.MissingRTypeAttribute(attrname)
  790. commonbase = access.commonbase
  791. class_repr = rclass.getclassrepr(self.rtyper, commonbase)
  792. return access, class_repr
  793. def convert_desc(self, desc):
  794. if desc not in self.s_pbc.descriptions:
  795. raise TyperError("%r not in %r" % (desc, self))
  796. if self.lowleveltype is Void:
  797. return None
  798. subclassdef = desc.getuniqueclassdef()
  799. r_subclass = rclass.getclassrepr(self.rtyper, subclassdef)
  800. return r_subclass.getruntime(self.lowleveltype)
  801. def convert_const(self, cls):
  802. if cls is None:
  803. if self.lowleveltype is Void:
  804. return None
  805. else:
  806. T = self.lowleveltype
  807. return nullptr(T.TO)
  808. bk = self.rtyper.annotator.bookkeeper
  809. classdesc = bk.getdesc(cls)
  810. return self.convert_desc(classdesc)
  811. def rtype_getattr(self, hop):
  812. if hop.s_result.is_constant():
  813. return hop.inputconst(hop.r_result, hop.s_result.const)
  814. else:
  815. attr = hop.args_s[1].const
  816. if attr == '__name__':
  817. from rpython.rtyper.lltypesystem import rstr
  818. class_repr = self.rtyper.rootclass_repr
  819. vcls, vattr = hop.inputargs(class_repr, Void)
  820. cname = inputconst(Void, 'name')
  821. return hop.genop('getfield', [vcls, cname],
  822. resulttype = Ptr(rstr.STR))
  823. access_set, class_repr = self.get_access_set(attr)
  824. vcls, vattr = hop.inputargs(class_repr, Void)
  825. v_res = class_repr.getpbcfield(vcls, access_set, attr, hop.llops)
  826. s_res = access_set.s_value
  827. r_res = self.rtyper.getrepr(s_res)
  828. return hop.llops.convertvar(v_res, r_res, hop.r_result)
  829. def replace_class_with_inst_arg(self, hop, v_inst, s_inst, call_args):
  830. hop2 = hop.copy()
  831. hop2.r_s_popfirstarg() # discard the class pointer argument
  832. if call_args:
  833. _, s_shape = hop2.r_s_popfirstarg() # temporarely remove shape
  834. hop2.v_s_insertfirstarg(v_inst, s_inst) # add 'instance'
  835. adjust_shape(hop2, s_shape)
  836. else:
  837. hop2.v_s_insertfirstarg(v_inst, s_inst) # add 'instance'
  838. return hop2
  839. def rtype_simple_call(self, hop):
  840. return self.redispatch_call(hop, call_args=False)
  841. def rtype_call_args(self, hop):
  842. return self.redispatch_call(hop, call_args=True)
  843. def redispatch_call(self, hop, call_args):
  844. s_instance = hop.s_result
  845. r_instance = hop.r_result
  846. if len(self.s_pbc.descriptions) == 1:
  847. # instantiating a single class
  848. if self.lowleveltype is not Void:
  849. assert 0, "XXX None-or-1-class instantation not implemented"
  850. assert isinstance(s_instance, annmodel.SomeInstance)
  851. classdef = s_instance.classdef
  852. s_init = classdef.classdesc.s_read_attribute('__init__')
  853. v_init = Constant("init-func-dummy") # this value not really used
  854. if (isinstance(s_init, annmodel.SomeImpossibleValue) and
  855. classdef.classdesc.is_exception_class() and
  856. classdef.has_no_attrs()):
  857. # special case for instanciating simple built-in
  858. # exceptions: always return the same prebuilt instance,
  859. # and ignore any arguments passed to the contructor.
  860. r_instance = rclass.getinstancerepr(hop.rtyper, classdef)
  861. example = r_instance.get_reusable_prebuilt_instance()
  862. hop.exception_cannot_occur()
  863. return hop.inputconst(r_instance.lowleveltype, example)
  864. v_instance = rclass.rtype_new_instance(hop.rtyper, classdef,
  865. hop.llops, hop)
  866. if isinstance(v_instance, tuple):
  867. v_instance, must_call_init = v_instance
  868. if not must_call_init:
  869. return v_instance
  870. else:
  871. # instantiating a class from multiple possible classes
  872. vtypeptr = hop.inputarg(self, arg=0)
  873. try:
  874. access_set, r_class = self.get_access_set('__init__')
  875. except rclass.MissingRTypeAttribute:
  876. s_init = annmodel.s_ImpossibleValue
  877. else:
  878. s_init = access_set.s_value
  879. v_init = r_class.getpbcfield(vtypeptr, access_set, '__init__',
  880. hop.llops)
  881. v_instance = self._instantiate_runtime_class(hop, vtypeptr, r_instance)
  882. if isinstance(s_init, annmodel.SomeImpossibleValue):
  883. assert hop.nb_args == 1, ("arguments passed to __init__, "
  884. "but no __init__!")
  885. hop.exception_cannot_occur()
  886. else:
  887. hop2 = self.replace_class_with_inst_arg(
  888. hop, v_instance, s_instance, call_args)
  889. hop2.v_s_insertfirstarg(v_init, s_init) # add 'initfunc'
  890. hop2.s_result = annmodel.s_None
  891. hop2.r_result = self.rtyper.getrepr(hop2.s_result)
  892. # now hop2 looks like simple_call(initfunc, instance, args...)
  893. hop2.dispatch()
  894. return v_instance
  895. def _instantiate_runtime_class(self, hop, vtypeptr, r_instance):
  896. graphs = []
  897. for desc in self.s_pbc.descriptions:
  898. classdef = desc.getclassdef(None)
  899. assert hasattr(classdef, 'my_instantiate_graph')
  900. graphs.append(classdef.my_instantiate_graph)
  901. c_graphs = hop.inputconst(Void, graphs)
  902. #
  903. # "my_instantiate = typeptr.instantiate"
  904. c_name = hop.inputconst(Void, 'instantiate')
  905. v_instantiate = hop.genop('getfield', [vtypeptr, c_name],
  906. resulttype=OBJECT_VTABLE.instantiate)
  907. # "my_instantiate()"
  908. v_inst = hop.genop('indirect_call', [v_instantiate, c_graphs],
  909. resulttype=OBJECTPTR)
  910. return hop.genop('cast_pointer', [v_inst], resulttype=r_instance)
  911. def getlowleveltype(self):
  912. return CLASSTYPE
  913. def get_ll_hash_function(self):
  914. return ll_cls_hash
  915. get_ll_fasthash_function = get_ll_hash_function
  916. def get_ll_eq_function(self):
  917. return None
  918. def ll_str(self, ptr):
  919. cls = cast_pointer(CLASSTYPE, ptr)
  920. return cls.name
  921. def ll_cls_hash(cls):
  922. if not cls:
  923. return 0
  924. else:
  925. return cls.hash
  926. class __extend__(pairtype(ClassesPBCRepr, rclass.ClassRepr)):
  927. def convert_from_to((r_clspbc, r_cls), v, llops):
  928. # turn a PBC of classes to a standard pointer-to-vtable class repr
  929. if r_clspbc.lowleveltype == r_cls.lowleveltype:
  930. return v
  931. if r_clspbc.lowleveltype is Void:
  932. return inputconst(r_cls, r_clspbc.s_pbc.const)
  933. # convert from ptr-to-object-vtable to ptr-to-more-precise-vtable
  934. return r_cls.fromclasstype(v, llops)
  935. class __extend__(pairtype(ClassesPBCRepr, ClassesPBCRepr)):
  936. def convert_from_to((r_clspbc1, r_clspbc2), v, llops):
  937. # this check makes sense because both source and dest repr are ClassesPBCRepr
  938. if r_clspbc1.lowleveltype == r_clspbc2.lowleveltype:
  939. return v
  940. if r_clspbc1.lowleveltype is Void:
  941. return inputconst(r_clspbc2, r_clspbc1.s_pbc.const)
  942. if r_clspbc2.lowleveltype is Void:
  943. return inputconst(Void, r_clspbc2.s_pbc.const)
  944. return NotImplemented
  945. def adjust_shape(hop2, s_shape):
  946. new_shape = (s_shape.const[0]+1,) + s_shape.const[1:]
  947. c_shape = Constant(new_shape)
  948. s_shape = hop2.rtyper.annotator.bookkeeper.immutablevalue(new_shape)
  949. hop2.v_s_insertfirstarg(c_shape, s_shape) # reinsert adjusted shape
  950. class MethodsPBCRepr(Repr):
  951. """Representation selected for a PBC of MethodDescs.
  952. It assumes that all the methods come from the same name and have
  953. been read from instances with a common base."""
  954. def __init__(self, rtyper, s_pbc):
  955. self.rtyper = rtyper
  956. self.s_pbc = s_pbc
  957. mdescs = list(s_pbc.descriptions)
  958. methodname = mdescs[0].name
  959. classdef = mdescs[0].selfclassdef
  960. flags = mdescs[0].flags
  961. for mdesc in mdescs[1:]:
  962. if mdesc.name != methodname:
  963. raise TyperError("cannot find a unique name under which the "
  964. "methods can be found: %r" % (
  965. mdescs,))
  966. if mdesc.flags != flags:
  967. raise TyperError("inconsistent 'flags': %r versus %r" % (
  968. mdesc.flags, flags))
  969. classdef = classdef.commonbase(mdesc.selfclassdef)
  970. if classdef is None:
  971. raise TyperError("mixing methods coming from instances of "
  972. "classes with no common base: %r" % (mdescs,))
  973. self.methodname = methodname
  974. self.classdef = classdef.get_owner(methodname)
  975. # the low-level representation is just the bound 'self' argument.
  976. self.s_im_self = annmodel.SomeInstance(self.classdef, flags=flags)
  977. self.r_im_self = rclass.getinstancerepr(rtyper, self.classdef)
  978. self.lowleveltype = self.r_im_self.lowleveltype
  979. def convert_const(self, method):
  980. if getattr(method, 'im_func', None) is None:
  981. raise TyperError("not a bound method: %r" % method)
  982. return self.r_im_self.convert_const(method.im_self)
  983. def get_r_implfunc(self):
  984. r_class = self.r_im_self.rclass
  985. mangled_name, r_func = r_class.clsfields[self.methodname]
  986. return r_func, 1
  987. def get_s_callable(self):
  988. return self.s_pbc
  989. def get_method_from_instance(self, r_inst, v_inst, llops):
  990. # The 'self' might have to be cast to a parent class
  991. # (as shown for example in test_rclass/test_method_both_A_and_B)
  992. return llops.convertvar(v_inst, r_inst, self.r_im_self)
  993. def add_instance_arg_to_hop(self, hop, call_args):
  994. hop2 = hop.copy()
  995. hop2.args_s[0] = self.s_im_self # make the 1st arg stand for 'im_self'
  996. hop2.args_r[0] = self.r_im_self # (same lowleveltype as 'self')
  997. if call_args:
  998. hop2.swap_fst_snd_args()
  999. _, s_shape = hop2.r_s_popfirstarg()
  1000. adjust_shape(hop2, s_shape)
  1001. return hop2
  1002. def rtype_simple_call(self, hop):
  1003. return self.redispatch_call(hop, call_args=False)
  1004. def rtype_call_args(self, hop):
  1005. return self.redispatch_call(hop, call_args=True)
  1006. def redispatch_call(self, hop, call_args):
  1007. r_class = self.r_im_self.rclass
  1008. mangled_name, r_func = r_class.clsfields[self.methodname]
  1009. assert isinstance(r_func, FunctionReprBase)
  1010. # s_func = r_func.s_pbc -- not precise enough, see
  1011. # test_precise_method_call_1. Build a more precise one...
  1012. funcdescs = [desc.funcdesc for desc in hop.args_s[0].descriptions]
  1013. s_func = annmodel.SomePBC(funcdescs, subset_of=r_func.s_pbc)
  1014. v_im_self = hop.inputarg(self, arg=0)
  1015. v_cls = self.r_im_self.getfield(v_im_self, '__class__', hop.llops)
  1016. v_func = r_class.getclsfield(v_cls, self.methodname, hop.llops)
  1017. hop2 = self.add_instance_arg_to_hop(hop, call_args)
  1018. hop2.v_s_insertfirstarg(v_func, s_func) # insert 'function'
  1019. if (type(hop2.args_r[0]) is SmallFunctionSetPBCRepr and
  1020. type(r_func) is FunctionsPBCRepr):
  1021. hop2.args_r[0] = FunctionsPBCRepr(self.rtyper, s_func)
  1022. else:
  1023. hop2.args_v[0] = hop2.llops.convertvar(
  1024. hop2.args_v[0], r_func, hop2.args_r[0])
  1025. # now hop2 looks like simple_call(function, self, args...)
  1026. return hop2.dispatch()