PageRenderTime 49ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/pypy/jit/metainterp/compile.py

https://bitbucket.org/yrttyr/pypy
Python | 915 lines | 781 code | 64 blank | 70 comment | 96 complexity | c7cb349a2beb8afc1392f4d1992b3ce1 MD5 | raw file
  1. import weakref
  2. from pypy.rpython.lltypesystem import lltype
  3. from pypy.rpython.ootypesystem import ootype
  4. from pypy.objspace.flow.model import Constant, Variable
  5. from pypy.rlib.objectmodel import we_are_translated
  6. from pypy.rlib.debug import debug_start, debug_stop, debug_print
  7. from pypy.rlib import rstack
  8. from pypy.rlib.jit import JitDebugInfo, Counters
  9. from pypy.conftest import option
  10. from pypy.tool.sourcetools import func_with_new_name
  11. from pypy.jit.metainterp.resoperation import ResOperation, rop, get_deep_immutable_oplist
  12. from pypy.jit.metainterp.history import TreeLoop, Box, History, JitCellToken, TargetToken
  13. from pypy.jit.metainterp.history import AbstractFailDescr, BoxInt
  14. from pypy.jit.metainterp.history import BoxPtr, BoxObj, BoxFloat, Const, ConstInt
  15. from pypy.jit.metainterp import history
  16. from pypy.jit.metainterp.typesystem import llhelper, oohelper
  17. from pypy.jit.metainterp.optimize import InvalidLoop
  18. from pypy.jit.metainterp.inliner import Inliner
  19. from pypy.jit.metainterp.resume import NUMBERING, PENDINGFIELDSP
  20. from pypy.jit.codewriter import heaptracker, longlong
  21. def giveup():
  22. from pypy.jit.metainterp.pyjitpl import SwitchToBlackhole
  23. raise SwitchToBlackhole(Counters.ABORT_BRIDGE)
  24. def show_procedures(metainterp_sd, procedure=None, error=None):
  25. # debugging
  26. if option.view or option.viewloops:
  27. if error:
  28. errmsg = error.__class__.__name__
  29. if str(error):
  30. errmsg += ': ' + str(error)
  31. else:
  32. errmsg = None
  33. if procedure is None:
  34. extraprocedures = []
  35. else:
  36. extraprocedures = [procedure]
  37. metainterp_sd.stats.view(errmsg=errmsg,
  38. extraprocedures=extraprocedures,
  39. metainterp_sd=metainterp_sd)
  40. def create_empty_loop(metainterp, name_prefix=''):
  41. name = metainterp.staticdata.stats.name_for_new_loop()
  42. loop = TreeLoop(name_prefix + name)
  43. loop.call_pure_results = metainterp.call_pure_results
  44. return loop
  45. def make_jitcell_token(jitdriver_sd):
  46. jitcell_token = JitCellToken()
  47. jitcell_token.outermost_jitdriver_sd = jitdriver_sd
  48. return jitcell_token
  49. def record_loop_or_bridge(metainterp_sd, loop):
  50. """Do post-backend recordings and cleanups on 'loop'.
  51. """
  52. # get the original jitcell token corresponding to jitcell form which
  53. # this trace starts
  54. original_jitcell_token = loop.original_jitcell_token
  55. assert original_jitcell_token is not None
  56. if metainterp_sd.warmrunnerdesc is not None: # for tests
  57. assert original_jitcell_token.generation > 0 # has been registered with memmgr
  58. wref = weakref.ref(original_jitcell_token)
  59. for op in loop.operations:
  60. descr = op.getdescr()
  61. if isinstance(descr, ResumeDescr):
  62. descr.wref_original_loop_token = wref # stick it there
  63. n = descr.index
  64. if n >= 0: # we also record the resumedescr number
  65. original_jitcell_token.compiled_loop_token.record_faildescr_index(n)
  66. elif isinstance(descr, JitCellToken):
  67. # for a CALL_ASSEMBLER: record it as a potential jump.
  68. if descr is not original_jitcell_token:
  69. original_jitcell_token.record_jump_to(descr)
  70. descr.exported_state = None
  71. op.cleardescr() # clear reference, mostly for tests
  72. elif isinstance(descr, TargetToken):
  73. # for a JUMP: record it as a potential jump.
  74. # (the following test is not enough to prevent more complicated
  75. # cases of cycles, but at least it helps in simple tests of
  76. # test_memgr.py)
  77. if descr.original_jitcell_token is not original_jitcell_token:
  78. assert descr.original_jitcell_token is not None
  79. original_jitcell_token.record_jump_to(descr.original_jitcell_token)
  80. # exported_state is clear by optimizeopt when the short preamble is
  81. # constrcucted. if that did not happen the label should not show up
  82. # in a trace that will be used
  83. assert descr.exported_state is None
  84. if not we_are_translated():
  85. op._descr_wref = weakref.ref(op._descr)
  86. op.cleardescr() # clear reference to prevent the history.Stats
  87. # from keeping the loop alive during tests
  88. # record this looptoken on the QuasiImmut used in the code
  89. if loop.quasi_immutable_deps is not None:
  90. for qmut in loop.quasi_immutable_deps:
  91. qmut.register_loop_token(wref)
  92. # XXX maybe we should clear the dictionary here
  93. # mostly for tests: make sure we don't keep a reference to the LoopToken
  94. loop.original_jitcell_token = None
  95. if not we_are_translated():
  96. loop._looptoken_number = original_jitcell_token.number
  97. # ____________________________________________________________
  98. def compile_loop(metainterp, greenkey, start,
  99. inputargs, jumpargs,
  100. resume_at_jump_descr, full_preamble_needed=True,
  101. try_disabling_unroll=False):
  102. """Try to compile a new procedure by closing the current history back
  103. to the first operation.
  104. """
  105. from pypy.jit.metainterp.optimizeopt import optimize_trace
  106. metainterp_sd = metainterp.staticdata
  107. jitdriver_sd = metainterp.jitdriver_sd
  108. history = metainterp.history
  109. enable_opts = jitdriver_sd.warmstate.enable_opts
  110. if try_disabling_unroll:
  111. if 'unroll' not in enable_opts:
  112. return None
  113. enable_opts = enable_opts.copy()
  114. del enable_opts['unroll']
  115. jitcell_token = make_jitcell_token(jitdriver_sd)
  116. part = create_empty_loop(metainterp)
  117. part.inputargs = inputargs[:]
  118. h_ops = history.operations
  119. part.resume_at_jump_descr = resume_at_jump_descr
  120. part.operations = [ResOperation(rop.LABEL, inputargs, None, descr=TargetToken(jitcell_token))] + \
  121. [h_ops[i].clone() for i in range(start, len(h_ops))] + \
  122. [ResOperation(rop.LABEL, jumpargs, None, descr=jitcell_token)]
  123. try:
  124. optimize_trace(metainterp_sd, part, enable_opts)
  125. except InvalidLoop:
  126. return None
  127. target_token = part.operations[0].getdescr()
  128. assert isinstance(target_token, TargetToken)
  129. all_target_tokens = [target_token]
  130. loop = create_empty_loop(metainterp)
  131. loop.inputargs = part.inputargs
  132. loop.operations = part.operations
  133. loop.quasi_immutable_deps = {}
  134. if part.quasi_immutable_deps:
  135. loop.quasi_immutable_deps.update(part.quasi_immutable_deps)
  136. while part.operations[-1].getopnum() == rop.LABEL:
  137. inliner = Inliner(inputargs, jumpargs)
  138. part.quasi_immutable_deps = None
  139. part.operations = [part.operations[-1]] + \
  140. [inliner.inline_op(h_ops[i]) for i in range(start, len(h_ops))] + \
  141. [ResOperation(rop.JUMP, [inliner.inline_arg(a) for a in jumpargs],
  142. None, descr=jitcell_token)]
  143. target_token = part.operations[0].getdescr()
  144. assert isinstance(target_token, TargetToken)
  145. all_target_tokens.append(target_token)
  146. inputargs = jumpargs
  147. jumpargs = part.operations[-1].getarglist()
  148. try:
  149. optimize_trace(metainterp_sd, part, enable_opts)
  150. except InvalidLoop:
  151. return None
  152. loop.operations = loop.operations[:-1] + part.operations
  153. if part.quasi_immutable_deps:
  154. loop.quasi_immutable_deps.update(part.quasi_immutable_deps)
  155. if not loop.quasi_immutable_deps:
  156. loop.quasi_immutable_deps = None
  157. for box in loop.inputargs:
  158. assert isinstance(box, Box)
  159. loop.original_jitcell_token = jitcell_token
  160. for label in all_target_tokens:
  161. assert isinstance(label, TargetToken)
  162. if label.virtual_state and label.short_preamble:
  163. metainterp_sd.logger_ops.log_short_preamble([], label.short_preamble)
  164. jitcell_token.target_tokens = all_target_tokens
  165. propagate_original_jitcell_token(loop)
  166. send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, "loop")
  167. record_loop_or_bridge(metainterp_sd, loop)
  168. return all_target_tokens[0]
  169. def compile_retrace(metainterp, greenkey, start,
  170. inputargs, jumpargs,
  171. resume_at_jump_descr, partial_trace, resumekey):
  172. """Try to compile a new procedure by closing the current history back
  173. to the first operation.
  174. """
  175. from pypy.jit.metainterp.optimizeopt import optimize_trace
  176. history = metainterp.history
  177. metainterp_sd = metainterp.staticdata
  178. jitdriver_sd = metainterp.jitdriver_sd
  179. loop_jitcell_token = metainterp.get_procedure_token(greenkey)
  180. assert loop_jitcell_token
  181. assert partial_trace.operations[-1].getopnum() == rop.LABEL
  182. part = create_empty_loop(metainterp)
  183. part.inputargs = inputargs[:]
  184. part.resume_at_jump_descr = resume_at_jump_descr
  185. h_ops = history.operations
  186. part.operations = [partial_trace.operations[-1]] + \
  187. [h_ops[i].clone() for i in range(start, len(h_ops))] + \
  188. [ResOperation(rop.JUMP, jumpargs, None, descr=loop_jitcell_token)]
  189. label = part.operations[0]
  190. orignial_label = label.clone()
  191. assert label.getopnum() == rop.LABEL
  192. try:
  193. optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts)
  194. except InvalidLoop:
  195. # Fall back on jumping to preamble
  196. target_token = label.getdescr()
  197. assert isinstance(target_token, TargetToken)
  198. assert target_token.exported_state
  199. part.operations = [orignial_label] + \
  200. [ResOperation(rop.JUMP, inputargs[:],
  201. None, descr=loop_jitcell_token)]
  202. try:
  203. optimize_trace(metainterp_sd, part, jitdriver_sd.warmstate.enable_opts,
  204. inline_short_preamble=False)
  205. except InvalidLoop:
  206. return None
  207. assert part.operations[-1].getopnum() != rop.LABEL
  208. target_token = label.getdescr()
  209. assert isinstance(target_token, TargetToken)
  210. assert loop_jitcell_token.target_tokens
  211. loop_jitcell_token.target_tokens.append(target_token)
  212. if target_token.short_preamble:
  213. metainterp_sd.logger_ops.log_short_preamble([], target_token.short_preamble)
  214. loop = partial_trace
  215. loop.operations = loop.operations[:-1] + part.operations
  216. quasi_immutable_deps = {}
  217. if loop.quasi_immutable_deps:
  218. quasi_immutable_deps.update(loop.quasi_immutable_deps)
  219. if part.quasi_immutable_deps:
  220. quasi_immutable_deps.update(part.quasi_immutable_deps)
  221. if quasi_immutable_deps:
  222. loop.quasi_immutable_deps = quasi_immutable_deps
  223. for box in loop.inputargs:
  224. assert isinstance(box, Box)
  225. target_token = loop.operations[-1].getdescr()
  226. resumekey.compile_and_attach(metainterp, loop)
  227. target_token = label.getdescr()
  228. assert isinstance(target_token, TargetToken)
  229. record_loop_or_bridge(metainterp_sd, loop)
  230. return target_token
  231. def patch_new_loop_to_load_virtualizable_fields(loop, jitdriver_sd):
  232. vinfo = jitdriver_sd.virtualizable_info
  233. extra_ops = []
  234. inputargs = loop.inputargs
  235. vable_box = inputargs[jitdriver_sd.index_of_virtualizable]
  236. i = jitdriver_sd.num_red_args
  237. loop.inputargs = inputargs[:i]
  238. for descr in vinfo.static_field_descrs:
  239. assert i < len(inputargs)
  240. box = inputargs[i]
  241. extra_ops.append(
  242. ResOperation(rop.GETFIELD_GC, [vable_box], box, descr))
  243. i += 1
  244. arrayindex = 0
  245. for descr in vinfo.array_field_descrs:
  246. vable = vable_box.getref_base()
  247. arraylen = vinfo.get_array_length(vable, arrayindex)
  248. arraybox = BoxPtr()
  249. extra_ops.append(
  250. ResOperation(rop.GETFIELD_GC, [vable_box], arraybox, descr))
  251. arraydescr = vinfo.array_descrs[arrayindex]
  252. assert i + arraylen <= len(inputargs)
  253. for index in range(arraylen):
  254. box = inputargs[i]
  255. extra_ops.append(
  256. ResOperation(rop.GETARRAYITEM_GC,
  257. [arraybox, ConstInt(index)],
  258. box, descr=arraydescr))
  259. i += 1
  260. arrayindex += 1
  261. assert i == len(inputargs)
  262. loop.operations = extra_ops + loop.operations
  263. def propagate_original_jitcell_token(trace):
  264. for op in trace.operations:
  265. if op.getopnum() == rop.LABEL:
  266. token = op.getdescr()
  267. assert isinstance(token, TargetToken)
  268. assert token.original_jitcell_token is None
  269. token.original_jitcell_token = trace.original_jitcell_token
  270. def do_compile_loop(metainterp_sd, inputargs, operations, looptoken,
  271. log=True, name=''):
  272. metainterp_sd.logger_ops.log_loop(inputargs, operations, -2,
  273. 'compiling', name=name)
  274. return metainterp_sd.cpu.compile_loop(inputargs, operations, looptoken,
  275. log=log, name=name)
  276. def do_compile_bridge(metainterp_sd, faildescr, inputargs, operations,
  277. original_loop_token, log=True):
  278. metainterp_sd.logger_ops.log_bridge(inputargs, operations, -2)
  279. return metainterp_sd.cpu.compile_bridge(faildescr, inputargs, operations,
  280. original_loop_token, log=log)
  281. def send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, type):
  282. vinfo = jitdriver_sd.virtualizable_info
  283. if vinfo is not None:
  284. patch_new_loop_to_load_virtualizable_fields(loop, jitdriver_sd)
  285. original_jitcell_token = loop.original_jitcell_token
  286. loopname = jitdriver_sd.warmstate.get_location_str(greenkey)
  287. globaldata = metainterp_sd.globaldata
  288. original_jitcell_token.number = n = globaldata.loopnumbering
  289. globaldata.loopnumbering += 1
  290. if not we_are_translated():
  291. show_procedures(metainterp_sd, loop)
  292. loop.check_consistency()
  293. if metainterp_sd.warmrunnerdesc is not None:
  294. hooks = metainterp_sd.warmrunnerdesc.hooks
  295. debug_info = JitDebugInfo(jitdriver_sd, metainterp_sd.logger_ops,
  296. original_jitcell_token, loop.operations,
  297. type, greenkey)
  298. hooks.before_compile(debug_info)
  299. else:
  300. debug_info = None
  301. hooks = None
  302. operations = get_deep_immutable_oplist(loop.operations)
  303. metainterp_sd.profiler.start_backend()
  304. debug_start("jit-backend")
  305. try:
  306. asminfo = do_compile_loop(metainterp_sd, loop.inputargs,
  307. operations, original_jitcell_token,
  308. name=loopname)
  309. finally:
  310. debug_stop("jit-backend")
  311. metainterp_sd.profiler.end_backend()
  312. if hooks is not None:
  313. debug_info.asminfo = asminfo
  314. hooks.after_compile(debug_info)
  315. metainterp_sd.stats.add_new_loop(loop)
  316. if not we_are_translated():
  317. metainterp_sd.stats.compiled()
  318. metainterp_sd.log("compiled new " + type)
  319. #
  320. if asminfo is not None:
  321. ops_offset = asminfo.ops_offset
  322. else:
  323. ops_offset = None
  324. metainterp_sd.logger_ops.log_loop(loop.inputargs, loop.operations, n,
  325. type, ops_offset,
  326. name=loopname)
  327. #
  328. if metainterp_sd.warmrunnerdesc is not None: # for tests
  329. metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive(original_jitcell_token)
  330. def send_bridge_to_backend(jitdriver_sd, metainterp_sd, faildescr, inputargs,
  331. operations, original_loop_token):
  332. n = metainterp_sd.cpu.get_fail_descr_number(faildescr)
  333. if not we_are_translated():
  334. show_procedures(metainterp_sd)
  335. seen = dict.fromkeys(inputargs)
  336. TreeLoop.check_consistency_of_branch(operations, seen)
  337. if metainterp_sd.warmrunnerdesc is not None:
  338. hooks = metainterp_sd.warmrunnerdesc.hooks
  339. debug_info = JitDebugInfo(jitdriver_sd, metainterp_sd.logger_ops,
  340. original_loop_token, operations, 'bridge',
  341. fail_descr_no=n)
  342. hooks.before_compile_bridge(debug_info)
  343. else:
  344. hooks = None
  345. debug_info = None
  346. operations = get_deep_immutable_oplist(operations)
  347. metainterp_sd.profiler.start_backend()
  348. debug_start("jit-backend")
  349. try:
  350. asminfo = do_compile_bridge(metainterp_sd, faildescr, inputargs,
  351. operations,
  352. original_loop_token)
  353. finally:
  354. debug_stop("jit-backend")
  355. metainterp_sd.profiler.end_backend()
  356. if hooks is not None:
  357. debug_info.asminfo = asminfo
  358. hooks.after_compile_bridge(debug_info)
  359. if not we_are_translated():
  360. metainterp_sd.stats.compiled()
  361. metainterp_sd.log("compiled new bridge")
  362. #
  363. if asminfo is not None:
  364. ops_offset = asminfo.ops_offset
  365. else:
  366. ops_offset = None
  367. metainterp_sd.logger_ops.log_bridge(inputargs, operations, n, ops_offset)
  368. #
  369. #if metainterp_sd.warmrunnerdesc is not None: # for tests
  370. # metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive(
  371. # original_loop_token)
  372. # ____________________________________________________________
  373. class _DoneWithThisFrameDescr(AbstractFailDescr):
  374. pass
  375. class DoneWithThisFrameDescrVoid(_DoneWithThisFrameDescr):
  376. def handle_fail(self, metainterp_sd, jitdriver_sd):
  377. assert jitdriver_sd.result_type == history.VOID
  378. raise metainterp_sd.DoneWithThisFrameVoid()
  379. class DoneWithThisFrameDescrInt(_DoneWithThisFrameDescr):
  380. def handle_fail(self, metainterp_sd, jitdriver_sd):
  381. assert jitdriver_sd.result_type == history.INT
  382. result = metainterp_sd.cpu.get_latest_value_int(0)
  383. raise metainterp_sd.DoneWithThisFrameInt(result)
  384. class DoneWithThisFrameDescrRef(_DoneWithThisFrameDescr):
  385. def handle_fail(self, metainterp_sd, jitdriver_sd):
  386. assert jitdriver_sd.result_type == history.REF
  387. cpu = metainterp_sd.cpu
  388. result = cpu.get_latest_value_ref(0)
  389. cpu.clear_latest_values(1)
  390. raise metainterp_sd.DoneWithThisFrameRef(cpu, result)
  391. class DoneWithThisFrameDescrFloat(_DoneWithThisFrameDescr):
  392. def handle_fail(self, metainterp_sd, jitdriver_sd):
  393. assert jitdriver_sd.result_type == history.FLOAT
  394. result = metainterp_sd.cpu.get_latest_value_float(0)
  395. raise metainterp_sd.DoneWithThisFrameFloat(result)
  396. class ExitFrameWithExceptionDescrRef(_DoneWithThisFrameDescr):
  397. def handle_fail(self, metainterp_sd, jitdriver_sd):
  398. cpu = metainterp_sd.cpu
  399. value = cpu.get_latest_value_ref(0)
  400. cpu.clear_latest_values(1)
  401. raise metainterp_sd.ExitFrameWithExceptionRef(cpu, value)
  402. class TerminatingLoopToken(JitCellToken): # FIXME: kill?
  403. terminating = True
  404. def __init__(self, nargs, finishdescr):
  405. self.finishdescr = finishdescr
  406. def make_done_loop_tokens():
  407. done_with_this_frame_descr_void = DoneWithThisFrameDescrVoid()
  408. done_with_this_frame_descr_int = DoneWithThisFrameDescrInt()
  409. done_with_this_frame_descr_ref = DoneWithThisFrameDescrRef()
  410. done_with_this_frame_descr_float = DoneWithThisFrameDescrFloat()
  411. exit_frame_with_exception_descr_ref = ExitFrameWithExceptionDescrRef()
  412. # pseudo loop tokens to make the life of optimize.py easier
  413. return {'loop_tokens_done_with_this_frame_int': [
  414. TerminatingLoopToken(1, done_with_this_frame_descr_int)
  415. ],
  416. 'loop_tokens_done_with_this_frame_ref': [
  417. TerminatingLoopToken(1, done_with_this_frame_descr_ref)
  418. ],
  419. 'loop_tokens_done_with_this_frame_float': [
  420. TerminatingLoopToken(1, done_with_this_frame_descr_float)
  421. ],
  422. 'loop_tokens_done_with_this_frame_void': [
  423. TerminatingLoopToken(0, done_with_this_frame_descr_void)
  424. ],
  425. 'loop_tokens_exit_frame_with_exception_ref': [
  426. TerminatingLoopToken(1, exit_frame_with_exception_descr_ref)
  427. ],
  428. }
  429. class ResumeDescr(AbstractFailDescr):
  430. pass
  431. class ResumeGuardDescr(ResumeDescr):
  432. _counter = 0 # on a GUARD_VALUE, there is one counter per value;
  433. _counters = None # they get stored in _counters then.
  434. # this class also gets the following attributes stored by resume.py code
  435. rd_snapshot = None
  436. rd_frame_info_list = None
  437. rd_numb = lltype.nullptr(NUMBERING)
  438. rd_consts = None
  439. rd_virtuals = None
  440. rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO)
  441. CNT_BASE_MASK = 0x0FFFFFFF # the base counter value
  442. CNT_BUSY_FLAG = 0x10000000 # if set, busy tracing from the guard
  443. CNT_TYPE_MASK = 0x60000000 # mask for the type
  444. CNT_INT = 0x20000000
  445. CNT_REF = 0x40000000
  446. CNT_FLOAT = 0x60000000
  447. def store_final_boxes(self, guard_op, boxes):
  448. guard_op.setfailargs(boxes)
  449. self.guard_opnum = guard_op.getopnum()
  450. def make_a_counter_per_value(self, guard_value_op):
  451. assert guard_value_op.getopnum() == rop.GUARD_VALUE
  452. box = guard_value_op.getarg(0)
  453. try:
  454. i = guard_value_op.getfailargs().index(box)
  455. except ValueError:
  456. return # xxx probably very rare
  457. else:
  458. if i > self.CNT_BASE_MASK:
  459. return # probably never, but better safe than sorry
  460. if box.type == history.INT:
  461. cnt = self.CNT_INT
  462. elif box.type == history.REF:
  463. cnt = self.CNT_REF
  464. elif box.type == history.FLOAT:
  465. cnt = self.CNT_FLOAT
  466. else:
  467. assert 0, box.type
  468. assert cnt > self.CNT_BASE_MASK
  469. self._counter = cnt | i
  470. def handle_fail(self, metainterp_sd, jitdriver_sd):
  471. if self.must_compile(metainterp_sd, jitdriver_sd):
  472. self.start_compiling()
  473. try:
  474. self._trace_and_compile_from_bridge(metainterp_sd,
  475. jitdriver_sd)
  476. finally:
  477. self.done_compiling()
  478. else:
  479. from pypy.jit.metainterp.blackhole import resume_in_blackhole
  480. resume_in_blackhole(metainterp_sd, jitdriver_sd, self)
  481. assert 0, "unreachable"
  482. def _trace_and_compile_from_bridge(self, metainterp_sd, jitdriver_sd):
  483. # 'jitdriver_sd' corresponds to the outermost one, i.e. the one
  484. # of the jit_merge_point where we started the loop, even if the
  485. # loop itself may contain temporarily recursion into other
  486. # jitdrivers.
  487. from pypy.jit.metainterp.pyjitpl import MetaInterp
  488. metainterp = MetaInterp(metainterp_sd, jitdriver_sd)
  489. metainterp.handle_guard_failure(self)
  490. _trace_and_compile_from_bridge._dont_inline_ = True
  491. def must_compile(self, metainterp_sd, jitdriver_sd):
  492. trace_eagerness = jitdriver_sd.warmstate.trace_eagerness
  493. #
  494. if self._counter <= self.CNT_BASE_MASK:
  495. # simple case: just counting from 0 to trace_eagerness
  496. self._counter += 1
  497. return self._counter >= trace_eagerness
  498. #
  499. # do we have the BUSY flag? If so, we're tracing right now, e.g. in an
  500. # outer invocation of the same function, so don't trace again for now.
  501. elif self._counter & self.CNT_BUSY_FLAG:
  502. return False
  503. #
  504. else: # we have a GUARD_VALUE that fails. Make a _counters instance
  505. # (only now, when the guard is actually failing at least once),
  506. # and use it to record some statistics about the failing values.
  507. index = self._counter & self.CNT_BASE_MASK
  508. typetag = self._counter & self.CNT_TYPE_MASK
  509. counters = self._counters
  510. if typetag == self.CNT_INT:
  511. intvalue = metainterp_sd.cpu.get_latest_value_int(index)
  512. if counters is None:
  513. self._counters = counters = ResumeGuardCountersInt()
  514. else:
  515. assert isinstance(counters, ResumeGuardCountersInt)
  516. counter = counters.see_int(intvalue)
  517. elif typetag == self.CNT_REF:
  518. refvalue = metainterp_sd.cpu.get_latest_value_ref(index)
  519. if counters is None:
  520. self._counters = counters = ResumeGuardCountersRef()
  521. else:
  522. assert isinstance(counters, ResumeGuardCountersRef)
  523. counter = counters.see_ref(refvalue)
  524. elif typetag == self.CNT_FLOAT:
  525. floatvalue = metainterp_sd.cpu.get_latest_value_float(index)
  526. if counters is None:
  527. self._counters = counters = ResumeGuardCountersFloat()
  528. else:
  529. assert isinstance(counters, ResumeGuardCountersFloat)
  530. counter = counters.see_float(floatvalue)
  531. else:
  532. assert 0, typetag
  533. return counter >= trace_eagerness
  534. def start_compiling(self):
  535. # start tracing and compiling from this guard.
  536. self._counter |= self.CNT_BUSY_FLAG
  537. def done_compiling(self):
  538. # done tracing and compiling from this guard. Either the bridge has
  539. # been successfully compiled, in which case whatever value we store
  540. # in self._counter will not be seen any more, or not, in which case
  541. # we should reset the counter to 0, in order to wait a bit until the
  542. # next attempt.
  543. if self._counter >= 0:
  544. self._counter = 0
  545. self._counters = None
  546. def compile_and_attach(self, metainterp, new_loop):
  547. # We managed to create a bridge. Attach the new operations
  548. # to the corresponding guard_op and compile from there
  549. assert metainterp.resumekey_original_loop_token is not None
  550. new_loop.original_jitcell_token = metainterp.resumekey_original_loop_token
  551. inputargs = metainterp.history.inputargs
  552. if not we_are_translated():
  553. self._debug_suboperations = new_loop.operations
  554. propagate_original_jitcell_token(new_loop)
  555. send_bridge_to_backend(metainterp.jitdriver_sd, metainterp.staticdata,
  556. self, inputargs, new_loop.operations,
  557. new_loop.original_jitcell_token)
  558. def copy_all_attributes_into(self, res):
  559. # XXX a bit ugly to have to list them all here
  560. res.rd_snapshot = self.rd_snapshot
  561. res.rd_frame_info_list = self.rd_frame_info_list
  562. res.rd_numb = self.rd_numb
  563. res.rd_consts = self.rd_consts
  564. res.rd_virtuals = self.rd_virtuals
  565. res.rd_pendingfields = self.rd_pendingfields
  566. def _clone_if_mutable(self):
  567. res = ResumeGuardDescr()
  568. self.copy_all_attributes_into(res)
  569. return res
  570. class ResumeGuardNotInvalidated(ResumeGuardDescr):
  571. def _clone_if_mutable(self):
  572. res = ResumeGuardNotInvalidated()
  573. self.copy_all_attributes_into(res)
  574. return res
  575. class ResumeAtPositionDescr(ResumeGuardDescr):
  576. def _clone_if_mutable(self):
  577. res = ResumeAtPositionDescr()
  578. self.copy_all_attributes_into(res)
  579. return res
  580. class ResumeGuardForcedDescr(ResumeGuardDescr):
  581. def __init__(self, metainterp_sd, jitdriver_sd):
  582. self.metainterp_sd = metainterp_sd
  583. self.jitdriver_sd = jitdriver_sd
  584. def handle_fail(self, metainterp_sd, jitdriver_sd):
  585. # Failures of a GUARD_NOT_FORCED are never compiled, but
  586. # always just blackholed. First fish for the data saved when
  587. # the virtualrefs and virtualizable have been forced by
  588. # handle_async_forcing() just a moment ago.
  589. from pypy.jit.metainterp.blackhole import resume_in_blackhole
  590. token = metainterp_sd.cpu.get_latest_force_token()
  591. all_virtuals = self.fetch_data(token)
  592. if all_virtuals is None:
  593. all_virtuals = []
  594. assert jitdriver_sd is self.jitdriver_sd
  595. resume_in_blackhole(metainterp_sd, jitdriver_sd, self, all_virtuals)
  596. assert 0, "unreachable"
  597. @staticmethod
  598. def force_now(cpu, token):
  599. # Called during a residual call from the assembler, if the code
  600. # actually needs to force one of the virtualrefs or the virtualizable.
  601. # Implemented by forcing *all* virtualrefs and the virtualizable.
  602. # don't interrupt me! If the stack runs out in force_from_resumedata()
  603. # then we have seen cpu.force() but not self.save_data(), leaving in
  604. # an inconsistent state
  605. rstack._stack_criticalcode_start()
  606. try:
  607. faildescr = cpu.force(token)
  608. assert isinstance(faildescr, ResumeGuardForcedDescr)
  609. faildescr.handle_async_forcing(token)
  610. finally:
  611. rstack._stack_criticalcode_stop()
  612. def handle_async_forcing(self, force_token):
  613. from pypy.jit.metainterp.resume import force_from_resumedata
  614. metainterp_sd = self.metainterp_sd
  615. vinfo = self.jitdriver_sd.virtualizable_info
  616. ginfo = self.jitdriver_sd.greenfield_info
  617. all_virtuals = force_from_resumedata(metainterp_sd, self, vinfo, ginfo)
  618. # The virtualizable data was stored on the real virtualizable above.
  619. # Handle all_virtuals: keep them for later blackholing from the
  620. # future failure of the GUARD_NOT_FORCED
  621. self.save_data(force_token, all_virtuals)
  622. def save_data(self, key, value):
  623. globaldata = self.metainterp_sd.globaldata
  624. if we_are_translated():
  625. assert key not in globaldata.resume_virtuals
  626. globaldata.resume_virtuals[key] = value
  627. else:
  628. rv = globaldata.resume_virtuals_not_translated
  629. for key1, value1 in rv:
  630. assert key1 != key
  631. rv.append((key, value))
  632. def fetch_data(self, key):
  633. globaldata = self.metainterp_sd.globaldata
  634. if we_are_translated():
  635. assert key in globaldata.resume_virtuals
  636. data = globaldata.resume_virtuals[key]
  637. del globaldata.resume_virtuals[key]
  638. else:
  639. rv = globaldata.resume_virtuals_not_translated
  640. for i in range(len(rv)):
  641. if rv[i][0] == key:
  642. data = rv[i][1]
  643. del rv[i]
  644. break
  645. else:
  646. assert 0, "not found: %r" % (key,)
  647. return data
  648. def _clone_if_mutable(self):
  649. res = ResumeGuardForcedDescr(self.metainterp_sd,
  650. self.jitdriver_sd)
  651. self.copy_all_attributes_into(res)
  652. return res
  653. class AbstractResumeGuardCounters(object):
  654. # Completely custom algorithm for now: keep 5 pairs (value, counter),
  655. # and when we need more, we discard the middle pair (middle in the
  656. # current value of the counter). That way, we tend to keep the
  657. # values with a high counter, but also we avoid always throwing away
  658. # the most recently added value. **THIS ALGO MUST GO AWAY AT SOME POINT**
  659. pass
  660. def _see(self, newvalue):
  661. # find and update an existing counter
  662. unused = -1
  663. for i in range(5):
  664. cnt = self.counters[i]
  665. if cnt:
  666. if self.values[i] == newvalue:
  667. cnt += 1
  668. self.counters[i] = cnt
  669. return cnt
  670. else:
  671. unused = i
  672. # not found. Use a previously unused entry, if there is one
  673. if unused >= 0:
  674. self.counters[unused] = 1
  675. self.values[unused] = newvalue
  676. return 1
  677. # no unused entry. Overwrite the middle one. Computed with indices
  678. # a, b, c meaning the highest, second highest, and third highest
  679. # entries.
  680. a = 0
  681. b = c = -1
  682. for i in range(1, 5):
  683. if self.counters[i] > self.counters[a]:
  684. c = b; b = a; a = i
  685. elif b < 0 or self.counters[i] > self.counters[b]:
  686. c = b; b = i
  687. elif c < 0 or self.counters[i] > self.counters[c]:
  688. c = i
  689. self.counters[c] = 1
  690. self.values[c] = newvalue
  691. return 1
  692. class ResumeGuardCountersInt(AbstractResumeGuardCounters):
  693. def __init__(self):
  694. self.counters = [0] * 5
  695. self.values = [0] * 5
  696. see_int = func_with_new_name(_see, 'see_int')
  697. class ResumeGuardCountersRef(AbstractResumeGuardCounters):
  698. def __init__(self):
  699. self.counters = [0] * 5
  700. self.values = [history.ConstPtr.value] * 5
  701. see_ref = func_with_new_name(_see, 'see_ref')
  702. class ResumeGuardCountersFloat(AbstractResumeGuardCounters):
  703. def __init__(self):
  704. self.counters = [0] * 5
  705. self.values = [longlong.ZEROF] * 5
  706. see_float = func_with_new_name(_see, 'see_float')
  707. class ResumeFromInterpDescr(ResumeDescr):
  708. def __init__(self, original_greenkey):
  709. self.original_greenkey = original_greenkey
  710. def compile_and_attach(self, metainterp, new_loop):
  711. # We managed to create a bridge going from the interpreter
  712. # to previously-compiled code. We keep 'new_loop', which is not
  713. # a loop at all but ends in a jump to the target loop. It starts
  714. # with completely unoptimized arguments, as in the interpreter.
  715. metainterp_sd = metainterp.staticdata
  716. jitdriver_sd = metainterp.jitdriver_sd
  717. redargs = new_loop.inputargs
  718. new_loop.original_jitcell_token = jitcell_token = make_jitcell_token(jitdriver_sd)
  719. propagate_original_jitcell_token(new_loop)
  720. send_loop_to_backend(self.original_greenkey, metainterp.jitdriver_sd,
  721. metainterp_sd, new_loop, "entry bridge")
  722. # send the new_loop to warmspot.py, to be called directly the next time
  723. jitdriver_sd.warmstate.attach_procedure_to_interp(
  724. self.original_greenkey, jitcell_token)
  725. metainterp_sd.stats.add_jitcell_token(jitcell_token)
  726. def compile_trace(metainterp, resumekey, resume_at_jump_descr=None):
  727. """Try to compile a new bridge leading from the beginning of the history
  728. to some existing place.
  729. """
  730. from pypy.jit.metainterp.optimizeopt import optimize_trace
  731. # The history contains new operations to attach as the code for the
  732. # failure of 'resumekey.guard_op'.
  733. #
  734. # Attempt to use optimize_bridge(). This may return None in case
  735. # it does not work -- i.e. none of the existing old_loop_tokens match.
  736. new_trace = create_empty_loop(metainterp)
  737. new_trace.inputargs = inputargs = metainterp.history.inputargs[:]
  738. # clone ops, as optimize_bridge can mutate the ops
  739. new_trace.operations = [op.clone() for op in metainterp.history.operations]
  740. new_trace.resume_at_jump_descr = resume_at_jump_descr
  741. metainterp_sd = metainterp.staticdata
  742. state = metainterp.jitdriver_sd.warmstate
  743. if isinstance(resumekey, ResumeAtPositionDescr):
  744. inline_short_preamble = False
  745. else:
  746. inline_short_preamble = True
  747. try:
  748. optimize_trace(metainterp_sd, new_trace, state.enable_opts, inline_short_preamble)
  749. except InvalidLoop:
  750. debug_print("compile_new_bridge: got an InvalidLoop")
  751. # XXX I am fairly convinced that optimize_bridge cannot actually raise
  752. # InvalidLoop
  753. debug_print('InvalidLoop in compile_new_bridge')
  754. return None
  755. if new_trace.operations[-1].getopnum() != rop.LABEL:
  756. # We managed to create a bridge. Dispatch to resumekey to
  757. # know exactly what we must do (ResumeGuardDescr/ResumeFromInterpDescr)
  758. target_token = new_trace.operations[-1].getdescr()
  759. resumekey.compile_and_attach(metainterp, new_trace)
  760. record_loop_or_bridge(metainterp_sd, new_trace)
  761. return target_token
  762. else:
  763. metainterp.retrace_needed(new_trace)
  764. return None
  765. # ____________________________________________________________
  766. class PropagateExceptionDescr(AbstractFailDescr):
  767. def handle_fail(self, metainterp_sd, jitdriver_sd):
  768. cpu = metainterp_sd.cpu
  769. exception = cpu.grab_exc_value()
  770. assert exception, "PropagateExceptionDescr: no exception??"
  771. raise metainterp_sd.ExitFrameWithExceptionRef(cpu, exception)
  772. def compile_tmp_callback(cpu, jitdriver_sd, greenboxes, redargtypes,
  773. memory_manager=None):
  774. """Make a LoopToken that corresponds to assembler code that just
  775. calls back the interpreter. Used temporarily: a fully compiled
  776. version of the code may end up replacing it.
  777. """
  778. jitcell_token = make_jitcell_token(jitdriver_sd)
  779. nb_red_args = jitdriver_sd.num_red_args
  780. assert len(redargtypes) == nb_red_args
  781. inputargs = []
  782. for kind in redargtypes:
  783. if kind == history.INT: box = BoxInt()
  784. elif kind == history.REF: box = BoxPtr()
  785. elif kind == history.FLOAT: box = BoxFloat()
  786. else: raise AssertionError
  787. inputargs.append(box)
  788. k = jitdriver_sd.portal_runner_adr
  789. funcbox = history.ConstInt(heaptracker.adr2int(k))
  790. callargs = [funcbox] + greenboxes + inputargs
  791. #
  792. result_type = jitdriver_sd.result_type
  793. if result_type == history.INT:
  794. result = BoxInt()
  795. elif result_type == history.REF:
  796. result = BoxPtr()
  797. elif result_type == history.FLOAT:
  798. result = BoxFloat()
  799. elif result_type == history.VOID:
  800. result = None
  801. else:
  802. assert 0, "bad result_type"
  803. if result is not None:
  804. finishargs = [result]
  805. else:
  806. finishargs = []
  807. #
  808. jd = jitdriver_sd
  809. faildescr = PropagateExceptionDescr()
  810. operations = [
  811. ResOperation(rop.CALL, callargs, result, descr=jd.portal_calldescr),
  812. ResOperation(rop.GUARD_NO_EXCEPTION, [], None, descr=faildescr),
  813. ResOperation(rop.FINISH, finishargs, None, descr=jd.portal_finishtoken)
  814. ]
  815. operations[1].setfailargs([])
  816. operations = get_deep_immutable_oplist(operations)
  817. cpu.compile_loop(inputargs, operations, jitcell_token, log=False)
  818. if memory_manager is not None: # for tests
  819. memory_manager.keep_loop_alive(jitcell_token)
  820. return jitcell_token