PageRenderTime 62ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/jit/metainterp/history.py

https://bitbucket.org/pypy/pypy/
Python | 1115 lines | 842 code | 225 blank | 48 comment | 130 complexity | 84ef7038e1001c2284a6abf38f193f3d MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from pypy.rpython.extregistry import ExtRegistryEntry
  2. from pypy.rpython.lltypesystem import lltype, llmemory, rffi
  3. from pypy.rpython.ootypesystem import ootype
  4. from pypy.rlib.objectmodel import we_are_translated, Symbolic
  5. from pypy.rlib.objectmodel import compute_unique_id
  6. from pypy.rlib.rarithmetic import r_int64
  7. from pypy.conftest import option
  8. from pypy.jit.metainterp.resoperation import ResOperation, rop
  9. from pypy.jit.codewriter import heaptracker, longlong
  10. from pypy.rlib.objectmodel import compute_identity_hash
  11. import weakref
  12. # ____________________________________________________________
  13. INT = 'i'
  14. REF = 'r'
  15. FLOAT = 'f'
  16. STRUCT = 's'
  17. HOLE = '_'
  18. VOID = 'v'
  19. FAILARGS_LIMIT = 1000
  20. def getkind(TYPE, supports_floats=True,
  21. supports_longlong=True,
  22. supports_singlefloats=True):
  23. if TYPE is lltype.Void:
  24. return "void"
  25. elif isinstance(TYPE, lltype.Primitive):
  26. if TYPE is lltype.Float and supports_floats:
  27. return 'float'
  28. if TYPE is lltype.SingleFloat and supports_singlefloats:
  29. return 'int' # singlefloats are stored in an int
  30. if TYPE in (lltype.Float, lltype.SingleFloat):
  31. raise NotImplementedError("type %s not supported" % TYPE)
  32. # XXX fix this for oo...
  33. if (TYPE != llmemory.Address and
  34. rffi.sizeof(TYPE) > rffi.sizeof(lltype.Signed)):
  35. if supports_longlong:
  36. assert rffi.sizeof(TYPE) == 8
  37. return 'float'
  38. raise NotImplementedError("type %s is too large" % TYPE)
  39. return "int"
  40. elif isinstance(TYPE, lltype.Ptr):
  41. if TYPE.TO._gckind == 'raw':
  42. return "int"
  43. else:
  44. return "ref"
  45. elif isinstance(TYPE, ootype.OOType):
  46. return "ref"
  47. else:
  48. raise NotImplementedError("type %s not supported" % TYPE)
  49. getkind._annspecialcase_ = 'specialize:memo'
  50. def repr_pointer(box):
  51. from pypy.rpython.lltypesystem import rstr
  52. try:
  53. T = box.value._obj.container._normalizedcontainer(check=False)._TYPE
  54. if T is rstr.STR:
  55. return repr(box._get_str())
  56. return '*%s' % (T._name,)
  57. except AttributeError:
  58. return box.value
  59. def repr_object(box):
  60. try:
  61. TYPE = box.value.obj._TYPE
  62. if TYPE is ootype.String:
  63. return '(%r)' % box.value.obj._str
  64. if TYPE is ootype.Class or isinstance(TYPE, ootype.StaticMethod):
  65. return '(%r)' % box.value.obj
  66. if isinstance(box.value.obj, ootype._view):
  67. return repr(box.value.obj._inst._TYPE)
  68. else:
  69. return repr(TYPE)
  70. except AttributeError:
  71. return box.value
  72. def repr_rpython(box, typechars):
  73. return '%s/%s%d' % (box._get_hash_(), typechars,
  74. compute_unique_id(box))
  75. class AbstractValue(object):
  76. __slots__ = ()
  77. def getint(self):
  78. raise NotImplementedError
  79. def getfloatstorage(self):
  80. raise NotImplementedError
  81. def getfloat(self):
  82. return longlong.getrealfloat(self.getfloatstorage())
  83. def getlonglong(self):
  84. assert longlong.supports_longlong
  85. return self.getfloatstorage()
  86. def getref_base(self):
  87. raise NotImplementedError
  88. def getref(self, TYPE):
  89. raise NotImplementedError
  90. getref._annspecialcase_ = 'specialize:arg(1)'
  91. def _get_hash_(self):
  92. return compute_identity_hash(self)
  93. def clonebox(self):
  94. raise NotImplementedError
  95. def constbox(self):
  96. raise NotImplementedError
  97. def nonconstbox(self):
  98. raise NotImplementedError
  99. def getaddr(self):
  100. raise NotImplementedError
  101. def sort_key(self):
  102. raise NotImplementedError
  103. def nonnull(self):
  104. raise NotImplementedError
  105. def repr_rpython(self):
  106. return '%s' % self
  107. def _get_str(self):
  108. raise NotImplementedError
  109. def same_box(self, other):
  110. return self is other
  111. class AbstractDescr(AbstractValue):
  112. __slots__ = ()
  113. def repr_of_descr(self):
  114. return '%r' % (self,)
  115. def _clone_if_mutable(self):
  116. return self
  117. def clone_if_mutable(self):
  118. clone = self._clone_if_mutable()
  119. if not we_are_translated():
  120. assert clone.__class__ is self.__class__
  121. return clone
  122. class AbstractFailDescr(AbstractDescr):
  123. index = -1
  124. def handle_fail(self, metainterp_sd, jitdriver_sd):
  125. raise NotImplementedError
  126. def compile_and_attach(self, metainterp, new_loop):
  127. raise NotImplementedError
  128. class BasicFailDescr(AbstractFailDescr):
  129. def __init__(self, identifier=None):
  130. self.identifier = identifier # for testing
  131. class AbstractMethDescr(AbstractDescr):
  132. # the base class of the result of cpu.methdescrof()
  133. jitcodes = None
  134. def setup(self, jitcodes):
  135. # jitcodes maps { runtimeClass -> jitcode for runtimeClass.methname }
  136. self.jitcodes = jitcodes
  137. def get_jitcode_for_class(self, oocls):
  138. return self.jitcodes[oocls]
  139. class Const(AbstractValue):
  140. __slots__ = ()
  141. @staticmethod
  142. def _new(x):
  143. "NOT_RPYTHON"
  144. T = lltype.typeOf(x)
  145. kind = getkind(T)
  146. if kind == "int":
  147. if isinstance(T, lltype.Ptr):
  148. intval = heaptracker.adr2int(llmemory.cast_ptr_to_adr(x))
  149. else:
  150. intval = lltype.cast_primitive(lltype.Signed, x)
  151. return ConstInt(intval)
  152. elif kind == "ref":
  153. return cpu.ts.new_ConstRef(x)
  154. elif kind == "float":
  155. return ConstFloat(longlong.getfloatstorage(x))
  156. else:
  157. raise NotImplementedError(kind)
  158. def constbox(self):
  159. return self
  160. def same_box(self, other):
  161. return self.same_constant(other)
  162. def same_constant(self, other):
  163. raise NotImplementedError
  164. def __repr__(self):
  165. return 'Const(%s)' % self._getrepr_()
  166. class ConstInt(Const):
  167. type = INT
  168. value = 0
  169. _attrs_ = ('value',)
  170. def __init__(self, value):
  171. if not we_are_translated():
  172. if isinstance(value, int):
  173. value = int(value) # bool -> int
  174. else:
  175. assert isinstance(value, Symbolic)
  176. self.value = value
  177. def clonebox(self):
  178. return BoxInt(self.value)
  179. nonconstbox = clonebox
  180. def getint(self):
  181. return self.value
  182. def getaddr(self):
  183. return heaptracker.int2adr(self.value)
  184. def _get_hash_(self):
  185. return make_hashable_int(self.value)
  186. def same_constant(self, other):
  187. if isinstance(other, ConstInt):
  188. return self.value == other.value
  189. return False
  190. def nonnull(self):
  191. return self.value != 0
  192. def _getrepr_(self):
  193. return self.value
  194. def repr_rpython(self):
  195. return repr_rpython(self, 'ci')
  196. CONST_FALSE = ConstInt(0)
  197. CONST_TRUE = ConstInt(1)
  198. class ConstFloat(Const):
  199. type = FLOAT
  200. value = longlong.ZEROF
  201. _attrs_ = ('value',)
  202. def __init__(self, valuestorage):
  203. assert lltype.typeOf(valuestorage) is longlong.FLOATSTORAGE
  204. self.value = valuestorage
  205. def clonebox(self):
  206. return BoxFloat(self.value)
  207. nonconstbox = clonebox
  208. def getfloatstorage(self):
  209. return self.value
  210. def _get_hash_(self):
  211. return longlong.gethash(self.value)
  212. def same_constant(self, other):
  213. if isinstance(other, ConstFloat):
  214. return self.value == other.value
  215. return False
  216. def nonnull(self):
  217. return self.value != longlong.ZEROF
  218. def _getrepr_(self):
  219. return self.getfloat()
  220. def repr_rpython(self):
  221. return repr_rpython(self, 'cf')
  222. CONST_FZERO = ConstFloat(longlong.ZEROF)
  223. class ConstPtr(Const):
  224. type = REF
  225. value = lltype.nullptr(llmemory.GCREF.TO)
  226. _attrs_ = ('value',)
  227. def __init__(self, value):
  228. assert lltype.typeOf(value) == llmemory.GCREF
  229. self.value = value
  230. def clonebox(self):
  231. return BoxPtr(self.value)
  232. nonconstbox = clonebox
  233. def getref_base(self):
  234. return self.value
  235. def getref(self, PTR):
  236. return lltype.cast_opaque_ptr(PTR, self.getref_base())
  237. getref._annspecialcase_ = 'specialize:arg(1)'
  238. def _get_hash_(self):
  239. if self.value:
  240. return lltype.identityhash(self.value)
  241. else:
  242. return 0
  243. def getaddr(self):
  244. return llmemory.cast_ptr_to_adr(self.value)
  245. def same_constant(self, other):
  246. if isinstance(other, ConstPtr):
  247. return self.value == other.value
  248. return False
  249. def nonnull(self):
  250. return bool(self.value)
  251. _getrepr_ = repr_pointer
  252. def repr_rpython(self):
  253. return repr_rpython(self, 'cp')
  254. def _get_str(self): # for debugging only
  255. from pypy.rpython.annlowlevel import hlstr
  256. from pypy.rpython.lltypesystem import rstr
  257. try:
  258. return hlstr(lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR),
  259. self.value))
  260. except lltype.UninitializedMemoryAccess:
  261. return '<uninitialized string>'
  262. CONST_NULL = ConstPtr(ConstPtr.value)
  263. class ConstObj(Const):
  264. type = REF
  265. value = ootype.NULL
  266. _attrs_ = ('value',)
  267. def __init__(self, value):
  268. assert ootype.typeOf(value) is ootype.Object
  269. self.value = value
  270. def clonebox(self):
  271. return BoxObj(self.value)
  272. nonconstbox = clonebox
  273. def getref_base(self):
  274. return self.value
  275. def getref(self, OBJ):
  276. return ootype.cast_from_object(OBJ, self.getref_base())
  277. getref._annspecialcase_ = 'specialize:arg(1)'
  278. def _get_hash_(self):
  279. if self.value:
  280. return ootype.identityhash(self.value)
  281. else:
  282. return 0
  283. ## def getaddr(self):
  284. ## # so far this is used only when calling
  285. ## # CodeWriter.IndirectCallset.bytecode_for_address. We don't need a
  286. ## # real addr, but just a key for the dictionary
  287. ## return self.value
  288. def same_constant(self, other):
  289. if isinstance(other, ConstObj):
  290. return self.value == other.value
  291. return False
  292. def nonnull(self):
  293. return bool(self.value)
  294. _getrepr_ = repr_object
  295. def repr_rpython(self):
  296. return repr_rpython(self, 'co')
  297. def _get_str(self): # for debugging only
  298. from pypy.rpython.annlowlevel import hlstr
  299. return hlstr(ootype.cast_from_object(ootype.String, self.value))
  300. class Box(AbstractValue):
  301. __slots__ = ()
  302. _extended_display = True
  303. _counter = 0
  304. is_box = True # hint that we want to make links in graphviz from this
  305. @staticmethod
  306. def _new(x):
  307. "NOT_RPYTHON"
  308. kind = getkind(lltype.typeOf(x))
  309. if kind == "int":
  310. intval = lltype.cast_primitive(lltype.Signed, x)
  311. return BoxInt(intval)
  312. elif kind == "ref":
  313. # XXX add ootype support?
  314. ptrval = lltype.cast_opaque_ptr(llmemory.GCREF, x)
  315. return BoxPtr(ptrval)
  316. elif kind == "float":
  317. return BoxFloat(longlong.getfloatstorage(x))
  318. else:
  319. raise NotImplementedError(kind)
  320. def nonconstbox(self):
  321. return self
  322. def __repr__(self):
  323. result = str(self)
  324. if self._extended_display:
  325. result += '(%s)' % self._getrepr_()
  326. return result
  327. def __str__(self):
  328. if not hasattr(self, '_str'):
  329. try:
  330. if self.type == INT:
  331. t = 'i'
  332. elif self.type == FLOAT:
  333. t = 'f'
  334. else:
  335. t = 'p'
  336. except AttributeError:
  337. t = 'b'
  338. self._str = '%s%d' % (t, Box._counter)
  339. Box._counter += 1
  340. return self._str
  341. def _get_str(self): # for debugging only
  342. return self.constbox()._get_str()
  343. def forget_value(self):
  344. raise NotImplementedError
  345. class BoxInt(Box):
  346. type = INT
  347. _attrs_ = ('value',)
  348. def __init__(self, value=0):
  349. if not we_are_translated():
  350. if isinstance(value, int):
  351. value = int(value) # bool -> int
  352. else:
  353. assert isinstance(value, Symbolic)
  354. self.value = value
  355. def forget_value(self):
  356. self.value = 0
  357. def clonebox(self):
  358. return BoxInt(self.value)
  359. def constbox(self):
  360. return ConstInt(self.value)
  361. def getint(self):
  362. return self.value
  363. def getaddr(self):
  364. return heaptracker.int2adr(self.value)
  365. def _get_hash_(self):
  366. return make_hashable_int(self.value)
  367. def nonnull(self):
  368. return self.value != 0
  369. def _getrepr_(self):
  370. return self.value
  371. def repr_rpython(self):
  372. return repr_rpython(self, 'bi')
  373. class BoxFloat(Box):
  374. type = FLOAT
  375. _attrs_ = ('value',)
  376. def __init__(self, valuestorage=longlong.ZEROF):
  377. assert lltype.typeOf(valuestorage) is longlong.FLOATSTORAGE
  378. self.value = valuestorage
  379. def forget_value(self):
  380. self.value = longlong.ZEROF
  381. def clonebox(self):
  382. return BoxFloat(self.value)
  383. def constbox(self):
  384. return ConstFloat(self.value)
  385. def getfloatstorage(self):
  386. return self.value
  387. def _get_hash_(self):
  388. return longlong.gethash(self.value)
  389. def nonnull(self):
  390. return self.value != longlong.ZEROF
  391. def _getrepr_(self):
  392. return self.getfloat()
  393. def repr_rpython(self):
  394. return repr_rpython(self, 'bf')
  395. class BoxPtr(Box):
  396. type = REF
  397. _attrs_ = ('value',)
  398. def __init__(self, value=lltype.nullptr(llmemory.GCREF.TO)):
  399. assert lltype.typeOf(value) == llmemory.GCREF
  400. self.value = value
  401. def forget_value(self):
  402. self.value = lltype.nullptr(llmemory.GCREF.TO)
  403. def clonebox(self):
  404. return BoxPtr(self.value)
  405. def constbox(self):
  406. return ConstPtr(self.value)
  407. def getref_base(self):
  408. return self.value
  409. def getref(self, PTR):
  410. return lltype.cast_opaque_ptr(PTR, self.getref_base())
  411. getref._annspecialcase_ = 'specialize:arg(1)'
  412. def getaddr(self):
  413. return llmemory.cast_ptr_to_adr(self.value)
  414. def _get_hash_(self):
  415. if self.value:
  416. return lltype.identityhash(self.value)
  417. else:
  418. return 0
  419. def nonnull(self):
  420. return bool(self.value)
  421. def repr_rpython(self):
  422. return repr_rpython(self, 'bp')
  423. _getrepr_ = repr_pointer
  424. NULLBOX = BoxPtr()
  425. class BoxObj(Box):
  426. type = REF
  427. _attrs_ = ('value',)
  428. def __init__(self, value=ootype.NULL):
  429. assert ootype.typeOf(value) is ootype.Object
  430. self.value = value
  431. def forget_value(self):
  432. self.value = ootype.NULL
  433. def clonebox(self):
  434. return BoxObj(self.value)
  435. def constbox(self):
  436. return ConstObj(self.value)
  437. def getref_base(self):
  438. return self.value
  439. def getref(self, OBJ):
  440. return ootype.cast_from_object(OBJ, self.getref_base())
  441. getref._annspecialcase_ = 'specialize:arg(1)'
  442. def _get_hash_(self):
  443. if self.value:
  444. return ootype.identityhash(self.value)
  445. else:
  446. return 0
  447. def nonnull(self):
  448. return bool(self.value)
  449. def repr_rpython(self):
  450. return repr_rpython(self, 'bo')
  451. _getrepr_ = repr_object
  452. # ____________________________________________________________
  453. def make_hashable_int(i):
  454. from pypy.rpython.lltypesystem.ll2ctypes import NotCtypesAllocatedStructure
  455. if not we_are_translated() and isinstance(i, llmemory.AddressAsInt):
  456. # Warning: such a hash changes at the time of translation
  457. adr = heaptracker.int2adr(i)
  458. try:
  459. return llmemory.cast_adr_to_int(adr, "emulated")
  460. except NotCtypesAllocatedStructure:
  461. return 12345 # use an arbitrary number for the hash
  462. return i
  463. def get_const_ptr_for_string(s):
  464. from pypy.rpython.annlowlevel import llstr
  465. if not we_are_translated():
  466. try:
  467. return _const_ptr_for_string[s]
  468. except KeyError:
  469. pass
  470. result = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, llstr(s)))
  471. if not we_are_translated():
  472. _const_ptr_for_string[s] = result
  473. return result
  474. _const_ptr_for_string = {}
  475. def get_const_ptr_for_unicode(s):
  476. from pypy.rpython.annlowlevel import llunicode
  477. if not we_are_translated():
  478. try:
  479. return _const_ptr_for_unicode[s]
  480. except KeyError:
  481. pass
  482. if isinstance(s, str):
  483. s = unicode(s)
  484. result = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, llunicode(s)))
  485. if not we_are_translated():
  486. _const_ptr_for_unicode[s] = result
  487. return result
  488. _const_ptr_for_unicode = {}
  489. # ____________________________________________________________
  490. # The JitCellToken class is the root of a tree of traces. Each branch ends
  491. # in a jump which goes to a LABEL operation; or it ends in a FINISH.
  492. class JitCellToken(AbstractDescr):
  493. """Used for rop.JUMP, giving the target of the jump.
  494. This is different from TreeLoop: the TreeLoop class contains the
  495. whole loop, including 'operations', and goes away after the loop
  496. was compiled; but the LoopDescr remains alive and points to the
  497. generated assembler.
  498. """
  499. target_tokens = None
  500. failed_states = None
  501. retraced_count = 0
  502. terminating = False # see TerminatingLoopToken in compile.py
  503. invalidated = False
  504. outermost_jitdriver_sd = None
  505. # and more data specified by the backend when the loop is compiled
  506. number = -1
  507. generation = r_int64(0)
  508. # one purpose of LoopToken is to keep alive the CompiledLoopToken
  509. # returned by the backend. When the LoopToken goes away, the
  510. # CompiledLoopToken has its __del__ called, which frees the assembler
  511. # memory and the ResumeGuards.
  512. compiled_loop_token = None
  513. def __init__(self):
  514. # For memory management of assembled loops
  515. self._keepalive_jitcell_tokens = {} # set of other JitCellToken
  516. def record_jump_to(self, jitcell_token):
  517. assert isinstance(jitcell_token, JitCellToken)
  518. self._keepalive_jitcell_tokens[jitcell_token] = None
  519. def __repr__(self):
  520. return '<Loop %d, gen=%d>' % (self.number, self.generation)
  521. def repr_of_descr(self):
  522. return '<Loop%d>' % self.number
  523. def dump(self):
  524. self.compiled_loop_token.cpu.dump_loop_token(self)
  525. class TargetToken(AbstractDescr):
  526. def __init__(self, targeting_jitcell_token=None):
  527. # Warning, two different jitcell_tokens here!
  528. #
  529. # * 'targeting_jitcell_token' is only useful for the front-end,
  530. # and it means: consider the LABEL that uses this TargetToken.
  531. # At this position, the state is logically the one given
  532. # by targeting_jitcell_token. So e.g. if we want to enter the
  533. # JIT with some given green args, if the jitcell matches, then
  534. # we can jump to this LABEL.
  535. #
  536. # * 'original_jitcell_token' is information from the backend's
  537. # point of view: it means that this TargetToken is used in
  538. # a LABEL that belongs to either:
  539. # - a loop; then 'original_jitcell_token' is this loop
  540. # - or a bridge; then 'original_jitcell_token' is the loop
  541. # out of which we made this bridge
  542. #
  543. self.targeting_jitcell_token = targeting_jitcell_token
  544. self.original_jitcell_token = None
  545. self.virtual_state = None
  546. self.exported_state = None
  547. def repr_of_descr(self):
  548. return 'TargetToken(%d)' % compute_unique_id(self)
  549. class TreeLoop(object):
  550. inputargs = None
  551. operations = None
  552. call_pure_results = None
  553. logops = None
  554. quasi_immutable_deps = None
  555. resume_at_jump_descr = None
  556. def _token(*args):
  557. raise Exception("TreeLoop.token is killed")
  558. token = property(_token, _token)
  559. # This is the jitcell where the trace starts. Labels within the trace might
  560. # belong to some other jitcells in the sens that jumping to this other
  561. # jitcell will result in a jump to the label.
  562. original_jitcell_token = None
  563. def __init__(self, name):
  564. self.name = name
  565. # self.operations = list of ResOperations
  566. # ops of the kind 'guard_xxx' contain a further list of operations,
  567. # which may itself contain 'guard_xxx' and so on, making a tree.
  568. def _all_operations(self, omit_finish=False):
  569. "NOT_RPYTHON"
  570. result = []
  571. _list_all_operations(result, self.operations, omit_finish)
  572. return result
  573. def summary(self, adding_insns={}): # for debugging
  574. "NOT_RPYTHON"
  575. insns = adding_insns.copy()
  576. for op in self._all_operations(omit_finish=True):
  577. opname = op.getopname()
  578. insns[opname] = insns.get(opname, 0) + 1
  579. return insns
  580. def get_operations(self):
  581. return self.operations
  582. def get_display_text(self): # for graphpage.py
  583. return self.name + '\n' + repr(self.inputargs)
  584. def show(self, errmsg=None):
  585. "NOT_RPYTHON"
  586. from pypy.jit.metainterp.graphpage import display_loops
  587. display_loops([self], errmsg)
  588. def check_consistency(self): # for testing
  589. "NOT_RPYTHON"
  590. self.check_consistency_of(self.inputargs, self.operations)
  591. for op in self.operations:
  592. descr = op.getdescr()
  593. if op.getopnum() == rop.LABEL and isinstance(descr, TargetToken):
  594. assert descr.original_jitcell_token is self.original_jitcell_token
  595. @staticmethod
  596. def check_consistency_of(inputargs, operations):
  597. for box in inputargs:
  598. assert isinstance(box, Box), "Loop.inputargs contains %r" % (box,)
  599. seen = dict.fromkeys(inputargs)
  600. assert len(seen) == len(inputargs), (
  601. "duplicate Box in the Loop.inputargs")
  602. TreeLoop.check_consistency_of_branch(operations, seen)
  603. @staticmethod
  604. def check_consistency_of_branch(operations, seen):
  605. "NOT_RPYTHON"
  606. for op in operations:
  607. for i in range(op.numargs()):
  608. box = op.getarg(i)
  609. if isinstance(box, Box):
  610. assert box in seen
  611. if op.is_guard():
  612. assert op.getdescr() is not None
  613. if hasattr(op.getdescr(), '_debug_suboperations'):
  614. ops = op.getdescr()._debug_suboperations
  615. TreeLoop.check_consistency_of_branch(ops, seen.copy())
  616. for box in op.getfailargs() or []:
  617. if box is not None:
  618. assert isinstance(box, Box)
  619. assert box in seen
  620. else:
  621. assert op.getfailargs() is None
  622. box = op.result
  623. if box is not None:
  624. assert isinstance(box, Box)
  625. assert box not in seen
  626. seen[box] = True
  627. if op.getopnum() == rop.LABEL:
  628. inputargs = op.getarglist()
  629. for box in inputargs:
  630. assert isinstance(box, Box), "LABEL contains %r" % (box,)
  631. seen = dict.fromkeys(inputargs)
  632. assert len(seen) == len(inputargs), (
  633. "duplicate Box in the LABEL arguments")
  634. assert operations[-1].is_final()
  635. if operations[-1].getopnum() == rop.JUMP:
  636. target = operations[-1].getdescr()
  637. if target is not None:
  638. assert isinstance(target, TargetToken)
  639. def dump(self):
  640. # RPython-friendly
  641. print '%r: inputargs =' % self, self._dump_args(self.inputargs)
  642. for op in self.operations:
  643. args = op.getarglist()
  644. print '\t', op.getopname(), self._dump_args(args), \
  645. self._dump_box(op.result)
  646. def _dump_args(self, boxes):
  647. return '[' + ', '.join([self._dump_box(box) for box in boxes]) + ']'
  648. def _dump_box(self, box):
  649. if box is None:
  650. return 'None'
  651. else:
  652. return box.repr_rpython()
  653. def __repr__(self):
  654. return '<%s>' % (self.name,)
  655. def _list_all_operations(result, operations, omit_finish=True):
  656. if omit_finish and operations[-1].getopnum() == rop.FINISH:
  657. # xxx obscure
  658. return
  659. result.extend(operations)
  660. for op in operations:
  661. if op.is_guard() and op.getdescr():
  662. if hasattr(op.getdescr(), '_debug_suboperations'):
  663. ops = op.getdescr()._debug_suboperations
  664. _list_all_operations(result, ops, omit_finish)
  665. # ____________________________________________________________
  666. class History(object):
  667. def __init__(self):
  668. self.inputargs = None
  669. self.operations = []
  670. def record(self, opnum, argboxes, resbox, descr=None):
  671. op = ResOperation(opnum, argboxes, resbox, descr)
  672. self.operations.append(op)
  673. return op
  674. def substitute_operation(self, position, opnum, argboxes, descr=None):
  675. resbox = self.operations[position].result
  676. op = ResOperation(opnum, argboxes, resbox, descr)
  677. self.operations[position] = op
  678. # ____________________________________________________________
  679. class NoStats(object):
  680. def set_history(self, history):
  681. pass
  682. def aborted(self):
  683. pass
  684. def entered(self):
  685. pass
  686. def compiled(self):
  687. pass
  688. def add_merge_point_location(self, loc):
  689. pass
  690. def name_for_new_loop(self):
  691. return 'Loop'
  692. def add_new_loop(self, loop):
  693. pass
  694. def record_aborted(self, greenkey):
  695. pass
  696. def view(self, **kwds):
  697. pass
  698. def clear(self):
  699. pass
  700. def add_jitcell_token(self, token):
  701. pass
  702. class Stats(object):
  703. """For tests."""
  704. compiled_count = 0
  705. enter_count = 0
  706. aborted_count = 0
  707. operations = None
  708. def __init__(self):
  709. self.loops = []
  710. self.locations = []
  711. self.aborted_keys = []
  712. self.invalidated_token_numbers = set() # <- not RPython
  713. self.jitcell_token_wrefs = []
  714. self.jitcell_dicts = [] # <- not RPython
  715. def clear(self):
  716. del self.loops[:]
  717. del self.locations[:]
  718. del self.aborted_keys[:]
  719. del self.jitcell_token_wrefs[:]
  720. self.invalidated_token_numbers.clear()
  721. self.compiled_count = 0
  722. self.enter_count = 0
  723. self.aborted_count = 0
  724. for dict in self.jitcell_dicts:
  725. dict.clear()
  726. def add_jitcell_token(self, token):
  727. assert isinstance(token, JitCellToken)
  728. self.jitcell_token_wrefs.append(weakref.ref(token))
  729. def set_history(self, history):
  730. self.operations = history.operations
  731. def aborted(self):
  732. self.aborted_count += 1
  733. def entered(self):
  734. self.enter_count += 1
  735. def compiled(self):
  736. self.compiled_count += 1
  737. def add_merge_point_location(self, loc):
  738. self.locations.append(loc)
  739. def name_for_new_loop(self):
  740. return 'Loop #%d' % len(self.loops)
  741. def add_new_loop(self, loop):
  742. self.loops.append(loop)
  743. def record_aborted(self, greenkey):
  744. self.aborted_keys.append(greenkey)
  745. # test read interface
  746. def get_all_loops(self):
  747. return self.loops
  748. def get_all_jitcell_tokens(self):
  749. tokens = [t() for t in self.jitcell_token_wrefs]
  750. if None in tokens:
  751. assert False, "get_all_jitcell_tokens will not work as "+\
  752. "loops have been freed"
  753. return tokens
  754. def check_history(self, expected=None, **check):
  755. insns = {}
  756. for op in self.operations:
  757. opname = op.getopname()
  758. insns[opname] = insns.get(opname, 0) + 1
  759. if expected is not None:
  760. insns.pop('debug_merge_point', None)
  761. assert insns == expected
  762. for insn, expected_count in check.items():
  763. getattr(rop, insn.upper()) # fails if 'rop.INSN' does not exist
  764. found = insns.get(insn, 0)
  765. assert found == expected_count, (
  766. "found %d %r, expected %d" % (found, insn, expected_count))
  767. return insns
  768. def check_resops(self, expected=None, **check):
  769. insns = {}
  770. for loop in self.get_all_loops():
  771. insns = loop.summary(adding_insns=insns)
  772. return self._check_insns(insns, expected, check)
  773. def _check_insns(self, insns, expected, check):
  774. if expected is not None:
  775. insns.pop('debug_merge_point', None)
  776. insns.pop('label', None)
  777. assert insns == expected
  778. for insn, expected_count in check.items():
  779. getattr(rop, insn.upper()) # fails if 'rop.INSN' does not exist
  780. found = insns.get(insn, 0)
  781. assert found == expected_count, (
  782. "found %d %r, expected %d" % (found, insn, expected_count))
  783. return insns
  784. def check_simple_loop(self, expected=None, **check):
  785. """ Usefull in the simplest case when we have only one trace ending with
  786. a jump back to itself and possibly a few bridges.
  787. Only the operations within the loop formed by that single jump will
  788. be counted.
  789. """
  790. loops = self.get_all_loops()
  791. assert len(loops) == 1
  792. loop = loops[0]
  793. jumpop = loop.operations[-1]
  794. assert jumpop.getopnum() == rop.JUMP
  795. labels = [op for op in loop.operations if op.getopnum() == rop.LABEL]
  796. targets = [op._descr_wref() for op in labels]
  797. assert None not in targets # TargetToken was freed, give up
  798. target = jumpop._descr_wref()
  799. assert target
  800. assert targets.count(target) == 1
  801. i = loop.operations.index(labels[targets.index(target)])
  802. insns = {}
  803. for op in loop.operations[i:]:
  804. opname = op.getopname()
  805. insns[opname] = insns.get(opname, 0) + 1
  806. return self._check_insns(insns, expected, check)
  807. def check_loops(self, expected=None, everywhere=False, **check):
  808. insns = {}
  809. for loop in self.get_all_loops():
  810. #if not everywhere:
  811. # if getattr(loop, '_ignore_during_counting', False):
  812. # continue
  813. insns = loop.summary(adding_insns=insns)
  814. if expected is not None:
  815. insns.pop('debug_merge_point', None)
  816. print
  817. print
  818. print " self.check_resops(%s)" % str(insns)
  819. print
  820. import pdb; pdb.set_trace()
  821. else:
  822. chk = ['%s=%d' % (i, insns.get(i, 0)) for i in check]
  823. print
  824. print
  825. print " self.check_resops(%s)" % ', '.join(chk)
  826. print
  827. import pdb; pdb.set_trace()
  828. return
  829. for insn, expected_count in check.items():
  830. getattr(rop, insn.upper()) # fails if 'rop.INSN' does not exist
  831. found = insns.get(insn, 0)
  832. assert found == expected_count, (
  833. "found %d %r, expected %d" % (found, insn, expected_count))
  834. return insns
  835. def check_consistency(self):
  836. "NOT_RPYTHON"
  837. for loop in self.get_all_loops():
  838. loop.check_consistency()
  839. def maybe_view(self):
  840. if option.view:
  841. self.view()
  842. def view(self, errmsg=None, extraprocedures=[], metainterp_sd=None):
  843. from pypy.jit.metainterp.graphpage import display_procedures
  844. procedures = self.get_all_loops()[:]
  845. for procedure in extraprocedures:
  846. if procedure in procedures:
  847. procedures.remove(procedure)
  848. procedures.append(procedure)
  849. highlight_procedures = dict.fromkeys(extraprocedures, 1)
  850. for procedure in procedures:
  851. if hasattr(procedure, '_looptoken_number') and (
  852. procedure._looptoken_number in self.invalidated_token_numbers):
  853. highlight_procedures.setdefault(procedure, 2)
  854. display_procedures(procedures, errmsg, highlight_procedures, metainterp_sd)
  855. # ----------------------------------------------------------------
  856. class Options:
  857. def __init__(self, listops=False, failargs_limit=FAILARGS_LIMIT):
  858. self.listops = listops
  859. self.failargs_limit = failargs_limit
  860. def _freeze_(self):
  861. return True
  862. # ----------------------------------------------------------------
  863. def check_descr(x):
  864. """Check that 'x' is None or an instance of AbstractDescr.
  865. Explodes if the annotator only thinks it is an instance of AbstractValue.
  866. """
  867. if x is not None:
  868. assert isinstance(x, AbstractDescr)
  869. class Entry(ExtRegistryEntry):
  870. _about_ = check_descr
  871. def compute_result_annotation(self, s_x):
  872. # Failures here mean that 'descr' is not correctly an AbstractDescr.
  873. # Please don't check in disabling of this test!
  874. from pypy.annotation import model as annmodel
  875. if not annmodel.s_None.contains(s_x):
  876. assert isinstance(s_x, annmodel.SomeInstance)
  877. # the following assert fails if we somehow did not manage
  878. # to ensure that the 'descr' field of ResOperation is really
  879. # an instance of AbstractDescr, a subclass of AbstractValue.
  880. assert issubclass(s_x.classdef.classdesc.pyobj, AbstractDescr)
  881. def specialize_call(self, hop):
  882. hop.exception_cannot_occur()