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

/pypy/rpython/rclass.py

http://github.com/pypy/pypy
Python | 468 lines | 379 code | 60 blank | 29 comment | 77 complexity | df0e302139935c0000e7f673e85773af MD5 | raw file
  1. import types
  2. from pypy.annotation import model as annmodel
  3. #from pypy.annotation.classdef import isclassdef
  4. from pypy.annotation import description
  5. from pypy.rpython.error import TyperError
  6. from pypy.rpython.rmodel import Repr, getgcflavor, inputconst
  7. from pypy.rpython.lltypesystem.lltype import Void
  8. class FieldListAccessor(object):
  9. def initialize(self, TYPE, fields):
  10. assert type(fields) is dict
  11. self.TYPE = TYPE
  12. self.fields = fields
  13. for x in fields.itervalues():
  14. assert isinstance(x, ImmutableRanking)
  15. def all_immutable_fields(self):
  16. result = set()
  17. for key, value in self.fields.iteritems():
  18. if value in (IR_IMMUTABLE, IR_IMMUTABLE_ARRAY):
  19. result.add(key)
  20. return result
  21. def __repr__(self):
  22. return '<FieldListAccessor for %s>' % getattr(self, 'TYPE', '?')
  23. def _freeze_(self):
  24. return True
  25. class ImmutableRanking(object):
  26. def __init__(self, name, is_immutable):
  27. self.name = name
  28. self.is_immutable = is_immutable
  29. def __nonzero__(self):
  30. return self.is_immutable
  31. def __repr__(self):
  32. return '<%s>' % self.name
  33. IR_MUTABLE = ImmutableRanking('mutable', False)
  34. IR_IMMUTABLE = ImmutableRanking('immutable', True)
  35. IR_IMMUTABLE_ARRAY = ImmutableRanking('immutable_array', True)
  36. IR_QUASIIMMUTABLE = ImmutableRanking('quasiimmutable', False)
  37. IR_QUASIIMMUTABLE_ARRAY = ImmutableRanking('quasiimmutable_array', False)
  38. class ImmutableConflictError(Exception):
  39. """Raised when the _immutable_ or _immutable_fields_ hints are
  40. not consistent across a class hierarchy."""
  41. def getclassrepr(rtyper, classdef):
  42. try:
  43. result = rtyper.class_reprs[classdef]
  44. except KeyError:
  45. result = rtyper.type_system.rclass.ClassRepr(rtyper, classdef)
  46. rtyper.class_reprs[classdef] = result
  47. rtyper.add_pendingsetup(result)
  48. return result
  49. def getinstancerepr(rtyper, classdef, default_flavor='gc'):
  50. if classdef is None:
  51. flavor = default_flavor
  52. else:
  53. flavor = getgcflavor(classdef)
  54. try:
  55. result = rtyper.instance_reprs[classdef, flavor]
  56. except KeyError:
  57. result = buildinstancerepr(rtyper, classdef, gcflavor=flavor)
  58. rtyper.instance_reprs[classdef, flavor] = result
  59. rtyper.add_pendingsetup(result)
  60. return result
  61. def buildinstancerepr(rtyper, classdef, gcflavor='gc'):
  62. from pypy.rlib.objectmodel import UnboxedValue
  63. from pypy.objspace.flow.model import Constant
  64. if classdef is None:
  65. unboxed = []
  66. virtualizable2 = False
  67. else:
  68. unboxed = [subdef for subdef in classdef.getallsubdefs()
  69. if subdef.classdesc.pyobj is not None and
  70. issubclass(subdef.classdesc.pyobj, UnboxedValue)]
  71. virtualizable2 = classdef.classdesc.read_attribute('_virtualizable2_',
  72. Constant(False)).value
  73. config = rtyper.annotator.translator.config
  74. usetagging = len(unboxed) != 0 and config.translation.taggedpointers
  75. if virtualizable2:
  76. assert len(unboxed) == 0
  77. assert gcflavor == 'gc'
  78. return rtyper.type_system.rvirtualizable2.Virtualizable2InstanceRepr(rtyper, classdef)
  79. elif usetagging and rtyper.type_system.name == 'lltypesystem':
  80. # the UnboxedValue class and its parent classes need a
  81. # special repr for their instances
  82. if len(unboxed) != 1:
  83. raise TyperError("%r has several UnboxedValue subclasses" % (
  84. classdef,))
  85. assert gcflavor == 'gc'
  86. from pypy.rpython.lltypesystem import rtagged
  87. return rtagged.TaggedInstanceRepr(rtyper, classdef, unboxed[0])
  88. else:
  89. return rtyper.type_system.rclass.InstanceRepr(rtyper, classdef, gcflavor)
  90. class MissingRTypeAttribute(TyperError):
  91. pass
  92. class AbstractClassRepr(Repr):
  93. def __init__(self, rtyper, classdef):
  94. self.rtyper = rtyper
  95. self.classdef = classdef
  96. def _setup_repr(self):
  97. pass
  98. def __repr__(self):
  99. if self.classdef is None:
  100. clsname = 'object'
  101. else:
  102. clsname = self.classdef.name
  103. return '<ClassRepr for %s>' % (clsname,)
  104. def compact_repr(self):
  105. if self.classdef is None:
  106. clsname = 'object'
  107. else:
  108. clsname = self.classdef.name
  109. return 'ClassR %s' % (clsname,)
  110. def convert_desc(self, desc):
  111. subclassdef = desc.getuniqueclassdef()
  112. if self.classdef is not None:
  113. if self.classdef.commonbase(subclassdef) != self.classdef:
  114. raise TyperError("not a subclass of %r: %r" % (
  115. self.classdef.name, desc))
  116. r_subclass = getclassrepr(self.rtyper, subclassdef)
  117. return r_subclass.getruntime(self.lowleveltype)
  118. def convert_const(self, value):
  119. if not isinstance(value, (type, types.ClassType)):
  120. raise TyperError("not a class: %r" % (value,))
  121. bk = self.rtyper.annotator.bookkeeper
  122. return self.convert_desc(bk.getdesc(value))
  123. def prepare_method(self, s_value):
  124. # special-casing for methods:
  125. # if s_value is SomePBC([MethodDescs...])
  126. # return a PBC representing the underlying functions
  127. if isinstance(s_value, annmodel.SomePBC):
  128. if not s_value.isNone() and s_value.getKind() == description.MethodDesc:
  129. s_value = self.classdef.lookup_filter(s_value)
  130. funcdescs = [mdesc.funcdesc for mdesc in s_value.descriptions]
  131. return annmodel.SomePBC(funcdescs)
  132. return None # not a method
  133. def get_ll_eq_function(self):
  134. return None
  135. def get_type_repr(rtyper):
  136. return getclassrepr(rtyper, None)
  137. # ____________________________________________________________
  138. class __extend__(annmodel.SomeInstance):
  139. def rtyper_makerepr(self, rtyper):
  140. return getinstancerepr(rtyper, self.classdef)
  141. def rtyper_makekey(self):
  142. return self.__class__, self.classdef
  143. class AbstractInstanceRepr(Repr):
  144. def __init__(self, rtyper, classdef):
  145. self.rtyper = rtyper
  146. self.classdef = classdef
  147. def _setup_repr(self):
  148. if self.classdef is None:
  149. self.immutable_field_set = set()
  150. def _check_for_immutable_hints(self, hints):
  151. loc = self.classdef.classdesc.lookup('_immutable_')
  152. if loc is not None:
  153. if loc is not self.classdef.classdesc:
  154. raise ImmutableConflictError(
  155. "class %r inherits from its parent _immutable_=True, "
  156. "so it should also declare _immutable_=True" % (
  157. self.classdef,))
  158. if loc.classdict.get('_immutable_').value is not True:
  159. raise TyperError(
  160. "class %r: _immutable_ = something else than True" % (
  161. self.classdef,))
  162. hints = hints.copy()
  163. hints['immutable'] = True
  164. self.immutable_field_set = set() # unless overwritten below
  165. if self.classdef.classdesc.lookup('_immutable_fields_') is not None:
  166. hints = hints.copy()
  167. immutable_fields = self.classdef.classdesc.classdict.get(
  168. '_immutable_fields_')
  169. if immutable_fields is not None:
  170. self.immutable_field_set = set(immutable_fields.value)
  171. accessor = FieldListAccessor()
  172. hints['immutable_fields'] = accessor
  173. return hints
  174. def __repr__(self):
  175. if self.classdef is None:
  176. clsname = 'object'
  177. else:
  178. clsname = self.classdef.name
  179. return '<InstanceRepr for %s>' % (clsname,)
  180. def compact_repr(self):
  181. if self.classdef is None:
  182. clsname = 'object'
  183. else:
  184. clsname = self.classdef.name
  185. return 'InstanceR %s' % (clsname,)
  186. def _setup_repr_final(self):
  187. self._setup_immutable_field_list()
  188. self._check_for_immutable_conflicts()
  189. def _setup_immutable_field_list(self):
  190. hints = self.object_type._hints
  191. if "immutable_fields" in hints:
  192. accessor = hints["immutable_fields"]
  193. if not hasattr(accessor, 'fields'):
  194. immutable_fields = set()
  195. rbase = self
  196. while rbase.classdef is not None:
  197. immutable_fields.update(rbase.immutable_field_set)
  198. rbase = rbase.rbase
  199. self._parse_field_list(immutable_fields, accessor)
  200. def _parse_field_list(self, fields, accessor):
  201. ranking = {}
  202. for name in fields:
  203. if name.endswith('?[*]'): # a quasi-immutable field pointing to
  204. name = name[:-4] # an immutable array
  205. rank = IR_QUASIIMMUTABLE_ARRAY
  206. elif name.endswith('[*]'): # for virtualizables' lists
  207. name = name[:-3]
  208. rank = IR_IMMUTABLE_ARRAY
  209. elif name.endswith('?'): # a quasi-immutable field
  210. name = name[:-1]
  211. rank = IR_QUASIIMMUTABLE
  212. else: # a regular immutable/green field
  213. rank = IR_IMMUTABLE
  214. try:
  215. mangled_name, r = self._get_field(name)
  216. except KeyError:
  217. continue
  218. ranking[mangled_name] = rank
  219. accessor.initialize(self.object_type, ranking)
  220. return ranking
  221. def _check_for_immutable_conflicts(self):
  222. # check for conflicts, i.e. a field that is defined normally as
  223. # mutable in some parent class but that is now declared immutable
  224. is_self_immutable = "immutable" in self.object_type._hints
  225. base = self
  226. while base.classdef is not None:
  227. base = base.rbase
  228. for fieldname in base.fields:
  229. try:
  230. mangled, r = base._get_field(fieldname)
  231. except KeyError:
  232. continue
  233. if r.lowleveltype == Void:
  234. continue
  235. base._setup_immutable_field_list()
  236. if base.object_type._immutable_field(mangled):
  237. continue
  238. # 'fieldname' is a mutable, non-Void field in the parent
  239. if is_self_immutable:
  240. raise ImmutableConflictError(
  241. "class %r has _immutable_=True, but parent class %r "
  242. "defines (at least) the mutable field %r" % (
  243. self, base, fieldname))
  244. if (fieldname in self.immutable_field_set or
  245. (fieldname + '?') in self.immutable_field_set):
  246. raise ImmutableConflictError(
  247. "field %r is defined mutable in class %r, but "
  248. "listed in _immutable_fields_ in subclass %r" % (
  249. fieldname, base, self))
  250. def hook_access_field(self, vinst, cname, llops, flags):
  251. pass # for virtualizables; see rvirtualizable2.py
  252. def hook_setfield(self, vinst, fieldname, llops):
  253. if self.is_quasi_immutable(fieldname):
  254. c_fieldname = inputconst(Void, 'mutate_' + fieldname)
  255. llops.genop('jit_force_quasi_immutable', [vinst, c_fieldname])
  256. def is_quasi_immutable(self, fieldname):
  257. search1 = fieldname + '?'
  258. search2 = fieldname + '?[*]'
  259. rbase = self
  260. while rbase.classdef is not None:
  261. if (search1 in rbase.immutable_field_set or
  262. search2 in rbase.immutable_field_set):
  263. return True
  264. rbase = rbase.rbase
  265. return False
  266. def new_instance(self, llops, classcallhop=None):
  267. raise NotImplementedError
  268. def convert_const(self, value):
  269. if value is None:
  270. return self.null_instance()
  271. if isinstance(value, types.MethodType):
  272. value = value.im_self # bound method -> instance
  273. bk = self.rtyper.annotator.bookkeeper
  274. try:
  275. classdef = bk.getuniqueclassdef(value.__class__)
  276. except KeyError:
  277. raise TyperError("no classdef: %r" % (value.__class__,))
  278. if classdef != self.classdef:
  279. # if the class does not match exactly, check that 'value' is an
  280. # instance of a subclass and delegate to that InstanceRepr
  281. if classdef.commonbase(self.classdef) != self.classdef:
  282. raise TyperError("not an instance of %r: %r" % (
  283. self.classdef.name, value))
  284. rinstance = getinstancerepr(self.rtyper, classdef)
  285. result = rinstance.convert_const(value)
  286. return self.upcast(result)
  287. # common case
  288. return self.convert_const_exact(value)
  289. def convert_const_exact(self, value):
  290. try:
  291. return self.iprebuiltinstances[value]
  292. except KeyError:
  293. self.setup()
  294. result = self.create_instance()
  295. self.iprebuiltinstances[value] = result
  296. self.initialize_prebuilt_instance(value, self.classdef, result)
  297. return result
  298. def get_reusable_prebuilt_instance(self):
  299. "Get a dummy prebuilt instance. Multiple calls reuse the same one."
  300. try:
  301. return self._reusable_prebuilt_instance
  302. except AttributeError:
  303. self.setup()
  304. result = self.create_instance()
  305. self._reusable_prebuilt_instance = result
  306. self.initialize_prebuilt_data(Ellipsis, self.classdef, result)
  307. return result
  308. def initialize_prebuilt_instance(self, value, classdef, result):
  309. # must fill in the hash cache before the other ones
  310. # (see test_circular_hash_initialization)
  311. self.initialize_prebuilt_hash(value, result)
  312. self.initialize_prebuilt_data(value, classdef, result)
  313. def get_ll_hash_function(self):
  314. return ll_inst_hash
  315. get_ll_fasthash_function = get_ll_hash_function
  316. def rtype_type(self, hop):
  317. raise NotImplementedError
  318. def rtype_getattr(self, hop):
  319. raise NotImplementedError
  320. def rtype_setattr(self, hop):
  321. raise NotImplementedError
  322. def rtype_is_true(self, hop):
  323. raise NotImplementedError
  324. def ll_str(self, i):
  325. raise NotImplementedError
  326. def get_ll_eq_function(self):
  327. return None # defaults to compare by identity ('==' on pointers)
  328. def can_ll_be_null(self, s_value):
  329. return s_value.can_be_none()
  330. def check_graph_of_del_does_not_call_too_much(self, graph):
  331. # RPython-level __del__() methods should not do "too much".
  332. # In the PyPy Python interpreter, they usually do simple things
  333. # like file.__del__() closing the file descriptor; or if they
  334. # want to do more like call an app-level __del__() method, they
  335. # enqueue the object instead, and the actual call is done later.
  336. #
  337. # Here, as a quick way to check "not doing too much", we check
  338. # that from no RPython-level __del__() method we can reach a
  339. # JitDriver.
  340. #
  341. # XXX wrong complexity, but good enough because the set of
  342. # reachable graphs should be small
  343. callgraph = self.rtyper.annotator.translator.callgraph.values()
  344. seen = {graph: None}
  345. while True:
  346. oldlength = len(seen)
  347. for caller, callee in callgraph:
  348. if caller in seen and callee not in seen:
  349. func = getattr(callee, 'func', None)
  350. if getattr(func, '_dont_reach_me_in_del_', False):
  351. lst = [str(callee)]
  352. g = caller
  353. while g:
  354. lst.append(str(g))
  355. g = seen.get(g)
  356. lst.append('')
  357. raise TyperError("the RPython-level __del__() method "
  358. "in %r calls:%s" % (
  359. graph, '\n\t'.join(lst[::-1])))
  360. if getattr(func, '_cannot_really_call_random_things_',
  361. False):
  362. continue
  363. seen[callee] = caller
  364. if len(seen) == oldlength:
  365. break
  366. # ____________________________________________________________
  367. def rtype_new_instance(rtyper, classdef, llops, classcallhop=None):
  368. rinstance = getinstancerepr(rtyper, classdef)
  369. return rinstance.new_instance(llops, classcallhop)
  370. def ll_inst_hash(ins):
  371. if not ins:
  372. return 0 # for None
  373. else:
  374. from pypy.rpython.lltypesystem import lltype
  375. return lltype.identityhash(ins) # also works for ootype
  376. _missing = object()
  377. def fishllattr(inst, name, default=_missing):
  378. from pypy.rpython.lltypesystem import lltype
  379. from pypy.rpython.ootypesystem import ootype
  380. if isinstance(inst, (ootype._instance, ootype._view)):
  381. # XXX: we need to call ootypesystem.rclass.mangle, but we
  382. # can't because we don't have a config object
  383. mangled = 'o' + name
  384. if default is _missing:
  385. return getattr(inst, mangled)
  386. else:
  387. return getattr(inst, mangled, default)
  388. else:
  389. p = widest = lltype.normalizeptr(inst)
  390. while True:
  391. try:
  392. return getattr(p, 'inst_' + name)
  393. except AttributeError:
  394. pass
  395. try:
  396. p = p.super
  397. except AttributeError:
  398. break
  399. if default is _missing:
  400. raise AttributeError("%s has no field %s" % (lltype.typeOf(widest),
  401. name))
  402. return default