PageRenderTime 31ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 1ms

/rpython/jit/metainterp/compile.py

https://bitbucket.org/pypy/pypy/
Python | 1161 lines | 972 code | 88 blank | 101 comment | 103 complexity | b0a584d82ca39492be0254dc4949b48c MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import weakref
  2. from rpython.rtyper.lltypesystem import lltype, llmemory
  3. from rpython.rtyper.annlowlevel import cast_instance_to_gcref
  4. from rpython.rlib.objectmodel import we_are_translated
  5. from rpython.rlib.debug import debug_start, debug_stop, debug_print, have_debug_prints
  6. from rpython.rlib.rarithmetic import r_uint, intmask
  7. from rpython.rlib import rstack
  8. from rpython.rlib.jit import JitDebugInfo, Counters, dont_look_inside
  9. from rpython.rlib.rjitlog import rjitlog as jl
  10. from rpython.conftest import option
  11. from rpython.jit.metainterp.resoperation import ResOperation, rop,\
  12. get_deep_immutable_oplist, OpHelpers, InputArgInt, InputArgRef,\
  13. InputArgFloat
  14. from rpython.jit.metainterp.history import (TreeLoop, Const, JitCellToken,
  15. TargetToken, AbstractFailDescr, ConstInt)
  16. from rpython.jit.metainterp import history, jitexc
  17. from rpython.jit.metainterp.optimize import InvalidLoop
  18. from rpython.jit.metainterp.resume import (PENDINGFIELDSP,
  19. ResumeDataDirectReader, AccumInfo)
  20. from rpython.jit.metainterp.resumecode import NUMBERING
  21. from rpython.jit.codewriter import heaptracker, longlong
  22. def giveup():
  23. from rpython.jit.metainterp.pyjitpl import SwitchToBlackhole
  24. raise SwitchToBlackhole(Counters.ABORT_BRIDGE)
  25. class CompileData(object):
  26. memo = None
  27. log_noopt = True
  28. def forget_optimization_info(self):
  29. for arg in self.trace.inputargs:
  30. arg.set_forwarded(None)
  31. class LoopCompileData(CompileData):
  32. """ An object that accumulates all of the necessary info for
  33. the optimization phase, but does not actually have any other state
  34. This is the case of label() ops label()
  35. """
  36. def __init__(self, trace, runtime_boxes, call_pure_results=None,
  37. enable_opts=None):
  38. self.enable_opts = enable_opts
  39. self.trace = trace
  40. self.call_pure_results = call_pure_results
  41. assert runtime_boxes is not None
  42. self.runtime_boxes = runtime_boxes
  43. def optimize(self, metainterp_sd, jitdriver_sd, optimizations, unroll):
  44. from rpython.jit.metainterp.optimizeopt.unroll import (UnrollOptimizer,
  45. Optimizer)
  46. if unroll:
  47. opt = UnrollOptimizer(metainterp_sd, jitdriver_sd, optimizations)
  48. return opt.optimize_preamble(self.trace,
  49. self.runtime_boxes,
  50. self.call_pure_results,
  51. self.box_names_memo)
  52. else:
  53. opt = Optimizer(metainterp_sd, jitdriver_sd, optimizations)
  54. return opt.propagate_all_forward(self.trace, self.call_pure_results)
  55. class SimpleCompileData(CompileData):
  56. """ This represents label() ops jump with no extra info associated with
  57. the label
  58. """
  59. def __init__(self, trace, call_pure_results=None,
  60. enable_opts=None):
  61. self.trace = trace
  62. self.call_pure_results = call_pure_results
  63. self.enable_opts = enable_opts
  64. def optimize(self, metainterp_sd, jitdriver_sd, optimizations, unroll):
  65. from rpython.jit.metainterp.optimizeopt.optimizer import Optimizer
  66. #assert not unroll
  67. opt = Optimizer(metainterp_sd, jitdriver_sd, optimizations)
  68. return opt.propagate_all_forward(self.trace.get_iter(),
  69. self.call_pure_results)
  70. class BridgeCompileData(CompileData):
  71. """ This represents ops() with a jump at the end that goes to some
  72. loop, we need to deal with virtual state and inlining of short preamble
  73. """
  74. def __init__(self, trace, runtime_boxes, call_pure_results=None,
  75. enable_opts=None, inline_short_preamble=False):
  76. self.trace = trace
  77. self.runtime_boxes = runtime_boxes
  78. self.call_pure_results = call_pure_results
  79. self.enable_opts = enable_opts
  80. self.inline_short_preamble = inline_short_preamble
  81. def optimize(self, metainterp_sd, jitdriver_sd, optimizations, unroll):
  82. from rpython.jit.metainterp.optimizeopt.unroll import UnrollOptimizer
  83. opt = UnrollOptimizer(metainterp_sd, jitdriver_sd, optimizations)
  84. return opt.optimize_bridge(self.trace, self.runtime_boxes,
  85. self.call_pure_results,
  86. self.inline_short_preamble,
  87. self.box_names_memo)
  88. class UnrolledLoopData(CompileData):
  89. """ This represents label() ops jump with extra info that's from the
  90. run of LoopCompileData. Jump goes to the same label
  91. """
  92. log_noopt = False
  93. def __init__(self, trace, celltoken, state,
  94. call_pure_results=None, enable_opts=None,
  95. inline_short_preamble=True):
  96. self.trace = trace
  97. self.celltoken = celltoken
  98. self.enable_opts = enable_opts
  99. self.state = state
  100. self.call_pure_results = call_pure_results
  101. self.inline_short_preamble = inline_short_preamble
  102. def optimize(self, metainterp_sd, jitdriver_sd, optimizations, unroll):
  103. from rpython.jit.metainterp.optimizeopt.unroll import UnrollOptimizer
  104. assert unroll # we should not be here if it's disabled
  105. opt = UnrollOptimizer(metainterp_sd, jitdriver_sd, optimizations)
  106. return opt.optimize_peeled_loop(self.trace, self.celltoken, self.state,
  107. self.call_pure_results, self.inline_short_preamble)
  108. def show_procedures(metainterp_sd, procedure=None, error=None):
  109. # debugging
  110. if option and (option.view or option.viewloops):
  111. if error:
  112. errmsg = error.__class__.__name__
  113. if str(error):
  114. errmsg += ': ' + str(error)
  115. else:
  116. errmsg = None
  117. if procedure is None:
  118. extraprocedures = []
  119. else:
  120. extraprocedures = [procedure]
  121. metainterp_sd.stats.view(errmsg=errmsg,
  122. extraprocedures=extraprocedures,
  123. metainterp_sd=metainterp_sd)
  124. def create_empty_loop(metainterp, name_prefix=''):
  125. name = metainterp.staticdata.stats.name_for_new_loop()
  126. loop = TreeLoop(name_prefix + name)
  127. return loop
  128. def make_jitcell_token(jitdriver_sd):
  129. jitcell_token = JitCellToken()
  130. jitcell_token.outermost_jitdriver_sd = jitdriver_sd
  131. return jitcell_token
  132. def record_loop_or_bridge(metainterp_sd, loop):
  133. """Do post-backend recordings and cleanups on 'loop'.
  134. """
  135. # get the original jitcell token corresponding to jitcell form which
  136. # this trace starts
  137. original_jitcell_token = loop.original_jitcell_token
  138. assert original_jitcell_token is not None
  139. if metainterp_sd.warmrunnerdesc is not None: # for tests
  140. assert original_jitcell_token.generation > 0 # has been registered with memmgr
  141. wref = weakref.ref(original_jitcell_token)
  142. clt = original_jitcell_token.compiled_loop_token
  143. clt.loop_token_wref = wref
  144. for op in loop.operations:
  145. descr = op.getdescr()
  146. # not sure what descr.index is about
  147. if isinstance(descr, ResumeDescr):
  148. descr.rd_loop_token = clt # stick it there
  149. #n = descr.index
  150. #if n >= 0: # we also record the resumedescr number
  151. # original_jitcell_token.compiled_loop_token.record_faildescr_index(n)
  152. # pass
  153. if isinstance(descr, JitCellToken):
  154. # for a CALL_ASSEMBLER: record it as a potential jump.
  155. if descr is not original_jitcell_token:
  156. original_jitcell_token.record_jump_to(descr)
  157. op.cleardescr() # clear reference, mostly for tests
  158. elif isinstance(descr, TargetToken):
  159. # for a JUMP: record it as a potential jump.
  160. # (the following test is not enough to prevent more complicated
  161. # cases of cycles, but at least it helps in simple tests of
  162. # test_memgr.py)
  163. if descr.original_jitcell_token is not original_jitcell_token:
  164. assert descr.original_jitcell_token is not None
  165. original_jitcell_token.record_jump_to(descr.original_jitcell_token)
  166. if not we_are_translated():
  167. op._descr_wref = weakref.ref(op._descr)
  168. op.cleardescr() # clear reference to prevent the history.Stats
  169. # from keeping the loop alive during tests
  170. # record this looptoken on the QuasiImmut used in the code
  171. if loop.quasi_immutable_deps is not None:
  172. for qmut in loop.quasi_immutable_deps:
  173. qmut.register_loop_token(wref)
  174. # XXX maybe we should clear the dictionary here
  175. # mostly for tests: make sure we don't keep a reference to the LoopToken
  176. loop.original_jitcell_token = None
  177. if not we_are_translated():
  178. loop._looptoken_number = original_jitcell_token.number
  179. # ____________________________________________________________
  180. def compile_simple_loop(metainterp, greenkey, trace, runtime_args, enable_opts,
  181. cut_at):
  182. from rpython.jit.metainterp.optimizeopt import optimize_trace
  183. jitdriver_sd = metainterp.jitdriver_sd
  184. metainterp_sd = metainterp.staticdata
  185. jitcell_token = make_jitcell_token(jitdriver_sd)
  186. call_pure_results = metainterp.call_pure_results
  187. data = SimpleCompileData(trace, call_pure_results=call_pure_results,
  188. enable_opts=enable_opts)
  189. try:
  190. loop_info, ops = optimize_trace(metainterp_sd, jitdriver_sd,
  191. data, metainterp.box_names_memo)
  192. except InvalidLoop:
  193. metainterp_sd.jitlog.trace_aborted()
  194. trace.cut_at(cut_at)
  195. return None
  196. loop = create_empty_loop(metainterp)
  197. loop.original_jitcell_token = jitcell_token
  198. loop.inputargs = loop_info.inputargs
  199. if loop_info.quasi_immutable_deps:
  200. loop.quasi_immutable_deps = loop_info.quasi_immutable_deps
  201. jump_op = ops[-1]
  202. target_token = TargetToken(jitcell_token)
  203. target_token.original_jitcell_token = jitcell_token
  204. label = ResOperation(rop.LABEL, loop_info.inputargs[:], descr=target_token)
  205. jump_op.setdescr(target_token)
  206. loop.operations = [label] + ops
  207. if not we_are_translated():
  208. loop.check_consistency()
  209. jitcell_token.target_tokens = [target_token]
  210. send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, "loop",
  211. runtime_args, metainterp.box_names_memo)
  212. record_loop_or_bridge(metainterp_sd, loop)
  213. return target_token
  214. def compile_loop(metainterp, greenkey, start, inputargs, jumpargs,
  215. full_preamble_needed=True, try_disabling_unroll=False):
  216. """Try to compile a new procedure by closing the current history back
  217. to the first operation.
  218. """
  219. from rpython.jit.metainterp.optimizeopt import optimize_trace
  220. metainterp_sd = metainterp.staticdata
  221. jitdriver_sd = metainterp.jitdriver_sd
  222. history = metainterp.history
  223. trace = history.trace
  224. warmstate = jitdriver_sd.warmstate
  225. #
  226. metainterp_sd.jitlog.start_new_trace(metainterp_sd,
  227. faildescr=None, entry_bridge=False)
  228. #
  229. enable_opts = jitdriver_sd.warmstate.enable_opts
  230. if try_disabling_unroll:
  231. if 'unroll' not in enable_opts:
  232. return None
  233. enable_opts = enable_opts.copy()
  234. del enable_opts['unroll']
  235. jitcell_token = make_jitcell_token(jitdriver_sd)
  236. cut_at = history.get_trace_position()
  237. history.record(rop.JUMP, jumpargs, None, descr=jitcell_token)
  238. if start != (0, 0, 0):
  239. trace = trace.cut_trace_from(start, inputargs)
  240. if 'unroll' not in enable_opts or not metainterp.cpu.supports_guard_gc_type:
  241. return compile_simple_loop(metainterp, greenkey, trace, jumpargs,
  242. enable_opts, cut_at)
  243. call_pure_results = metainterp.call_pure_results
  244. preamble_data = LoopCompileData(trace, jumpargs,
  245. call_pure_results=call_pure_results,
  246. enable_opts=enable_opts)
  247. try:
  248. start_state, preamble_ops = optimize_trace(metainterp_sd, jitdriver_sd,
  249. preamble_data,
  250. metainterp.box_names_memo)
  251. except InvalidLoop:
  252. metainterp_sd.jitlog.trace_aborted()
  253. history.cut(cut_at)
  254. return None
  255. metainterp_sd = metainterp.staticdata
  256. jitdriver_sd = metainterp.jitdriver_sd
  257. start_descr = TargetToken(jitcell_token,
  258. original_jitcell_token=jitcell_token)
  259. jitcell_token.target_tokens = [start_descr]
  260. loop_data = UnrolledLoopData(trace, jitcell_token, start_state,
  261. call_pure_results=call_pure_results,
  262. enable_opts=enable_opts)
  263. try:
  264. loop_info, loop_ops = optimize_trace(metainterp_sd, jitdriver_sd,
  265. loop_data,
  266. metainterp.box_names_memo)
  267. except InvalidLoop:
  268. metainterp_sd.jitlog.trace_aborted()
  269. history.cut(cut_at)
  270. return None
  271. if ((warmstate.vec and jitdriver_sd.vec) or warmstate.vec_all):
  272. from rpython.jit.metainterp.optimizeopt.vector import optimize_vector
  273. loop_info, loop_ops = optimize_vector(trace, metainterp_sd,
  274. jitdriver_sd, warmstate,
  275. loop_info, loop_ops,
  276. jitcell_token)
  277. #
  278. loop = create_empty_loop(metainterp)
  279. loop.original_jitcell_token = jitcell_token
  280. loop.inputargs = start_state.renamed_inputargs
  281. quasi_immutable_deps = {}
  282. if start_state.quasi_immutable_deps:
  283. quasi_immutable_deps.update(start_state.quasi_immutable_deps)
  284. if loop_info.quasi_immutable_deps:
  285. quasi_immutable_deps.update(loop_info.quasi_immutable_deps)
  286. if quasi_immutable_deps:
  287. loop.quasi_immutable_deps = quasi_immutable_deps
  288. start_label = ResOperation(rop.LABEL, start_state.renamed_inputargs,
  289. descr=start_descr)
  290. label_token = loop_info.label_op.getdescr()
  291. assert isinstance(label_token, TargetToken)
  292. if label_token.short_preamble:
  293. metainterp_sd.logger_ops.log_short_preamble([],
  294. label_token.short_preamble, metainterp.box_names_memo)
  295. loop.operations = ([start_label] + preamble_ops + loop_info.extra_same_as +
  296. [loop_info.label_op] + loop_ops)
  297. if not we_are_translated():
  298. loop.check_consistency()
  299. send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, "loop",
  300. inputargs, metainterp.box_names_memo)
  301. record_loop_or_bridge(metainterp_sd, loop)
  302. loop_info.post_loop_compilation(loop, jitdriver_sd, metainterp, jitcell_token)
  303. return start_descr
  304. def compile_retrace(metainterp, greenkey, start,
  305. inputargs, jumpargs,
  306. partial_trace, resumekey, start_state):
  307. """Try to compile a new procedure by closing the current history back
  308. to the first operation.
  309. """
  310. from rpython.jit.metainterp.optimizeopt import optimize_trace
  311. trace = metainterp.history.trace.cut_trace_from(start, inputargs)
  312. metainterp_sd = metainterp.staticdata
  313. jitdriver_sd = metainterp.jitdriver_sd
  314. history = metainterp.history
  315. #
  316. metainterp_sd.jitlog.start_new_trace(metainterp_sd,
  317. faildescr=resumekey, entry_bridge=False)
  318. #
  319. loop_jitcell_token = metainterp.get_procedure_token(greenkey)
  320. assert loop_jitcell_token
  321. cut = history.get_trace_position()
  322. history.record(rop.JUMP, jumpargs[:], None, descr=loop_jitcell_token)
  323. enable_opts = jitdriver_sd.warmstate.enable_opts
  324. call_pure_results = metainterp.call_pure_results
  325. loop_data = UnrolledLoopData(trace, loop_jitcell_token, start_state,
  326. call_pure_results=call_pure_results,
  327. enable_opts=enable_opts)
  328. try:
  329. loop_info, loop_ops = optimize_trace(metainterp_sd, jitdriver_sd,
  330. loop_data,
  331. metainterp.box_names_memo)
  332. except InvalidLoop:
  333. # Fall back on jumping directly to preamble
  334. history.cut(cut)
  335. history.record(rop.JUMP, jumpargs[:], None, descr=loop_jitcell_token)
  336. loop_data = UnrolledLoopData(trace, loop_jitcell_token, start_state,
  337. call_pure_results=call_pure_results,
  338. enable_opts=enable_opts,
  339. inline_short_preamble=False)
  340. try:
  341. loop_info, loop_ops = optimize_trace(metainterp_sd, jitdriver_sd,
  342. loop_data,
  343. metainterp.box_names_memo)
  344. except InvalidLoop:
  345. metainterp_sd.jitlog.trace_aborted()
  346. history.cut(cut)
  347. return None
  348. label_op = loop_info.label_op
  349. if label_op is None:
  350. assert False, "unreachable code" # hint for some strange tests
  351. label_token = label_op.getdescr()
  352. assert isinstance(label_token, TargetToken)
  353. if label_token.short_preamble:
  354. metainterp_sd.logger_ops.log_short_preamble([],
  355. label_token.short_preamble, metainterp.box_names_memo)
  356. loop = partial_trace
  357. loop.original_jitcell_token = loop_jitcell_token
  358. loop.operations = (loop.operations + loop_info.extra_same_as +
  359. [loop_info.label_op]
  360. + loop_ops)
  361. quasi_immutable_deps = {}
  362. if loop_info.quasi_immutable_deps:
  363. quasi_immutable_deps.update(loop_info.quasi_immutable_deps)
  364. if start_state.quasi_immutable_deps:
  365. quasi_immutable_deps.update(start_state.quasi_immutable_deps)
  366. if quasi_immutable_deps:
  367. loop.quasi_immutable_deps = quasi_immutable_deps
  368. target_token = loop.operations[-1].getdescr()
  369. resumekey.compile_and_attach(metainterp, loop, inputargs)
  370. record_loop_or_bridge(metainterp_sd, loop)
  371. return target_token
  372. def get_box_replacement(op, allow_none=False):
  373. if allow_none and op is None:
  374. return None # for failargs
  375. while op.get_forwarded():
  376. op = op.get_forwarded()
  377. return op
  378. def emit_op(lst, op):
  379. op = get_box_replacement(op)
  380. orig_op = op
  381. # XXX specialize on number of args
  382. replaced = False
  383. for i in range(op.numargs()):
  384. orig_arg = op.getarg(i)
  385. arg = get_box_replacement(orig_arg)
  386. if orig_arg is not arg:
  387. if not replaced:
  388. op = op.copy_and_change(op.getopnum())
  389. orig_op.set_forwarded(op)
  390. replaced = True
  391. op.setarg(i, arg)
  392. if op.is_guard():
  393. if not replaced:
  394. op = op.copy_and_change(op.getopnum())
  395. orig_op.set_forwarded(op)
  396. op.setfailargs([get_box_replacement(a, True)
  397. for a in op.getfailargs()])
  398. lst.append(op)
  399. def patch_new_loop_to_load_virtualizable_fields(loop, jitdriver_sd, vable):
  400. # XXX merge with rewriting
  401. vinfo = jitdriver_sd.virtualizable_info
  402. extra_ops = []
  403. inputargs = loop.inputargs
  404. vable_box = inputargs[jitdriver_sd.index_of_virtualizable]
  405. i = jitdriver_sd.num_red_args
  406. loop.inputargs = inputargs[:i]
  407. for descr in vinfo.static_field_descrs:
  408. assert i < len(inputargs)
  409. box = inputargs[i]
  410. opnum = OpHelpers.getfield_for_descr(descr)
  411. emit_op(extra_ops,
  412. ResOperation(opnum, [vable_box], descr=descr))
  413. box.set_forwarded(extra_ops[-1])
  414. i += 1
  415. arrayindex = 0
  416. for descr in vinfo.array_field_descrs:
  417. arraylen = vinfo.get_array_length(vable, arrayindex)
  418. arrayop = ResOperation(rop.GETFIELD_GC_R, [vable_box], descr=descr)
  419. emit_op(extra_ops, arrayop)
  420. arraydescr = vinfo.array_descrs[arrayindex]
  421. assert i + arraylen <= len(inputargs)
  422. for index in range(arraylen):
  423. opnum = OpHelpers.getarrayitem_for_descr(arraydescr)
  424. box = inputargs[i]
  425. emit_op(extra_ops,
  426. ResOperation(opnum,
  427. [arrayop, ConstInt(index)],
  428. descr=arraydescr))
  429. i += 1
  430. box.set_forwarded(extra_ops[-1])
  431. arrayindex += 1
  432. assert i == len(inputargs)
  433. for op in loop.operations:
  434. emit_op(extra_ops, op)
  435. loop.operations = extra_ops
  436. def propagate_original_jitcell_token(trace):
  437. for op in trace.operations:
  438. if op.getopnum() == rop.LABEL:
  439. token = op.getdescr()
  440. assert isinstance(token, TargetToken)
  441. token.original_jitcell_token = trace.original_jitcell_token
  442. def do_compile_loop(jd_id, unique_id, metainterp_sd, inputargs, operations,
  443. looptoken, log=True, name='', memo=None):
  444. # legacy
  445. metainterp_sd.logger_ops.log_loop(inputargs, operations, -2,
  446. 'compiling', None, name, memo)
  447. _log = metainterp_sd.jitlog.log_trace(jl.MARK_TRACE_OPT, metainterp_sd, None)
  448. _log.write(inputargs, operations)
  449. return metainterp_sd.cpu.compile_loop(inputargs,
  450. operations, looptoken,
  451. jd_id=jd_id, unique_id=unique_id,
  452. log=log, name=name,
  453. logger=metainterp_sd.jitlog)
  454. def do_compile_bridge(metainterp_sd, faildescr, inputargs, operations,
  455. original_loop_token, log=True, memo=None):
  456. # legacy
  457. metainterp_sd.logger_ops.log_bridge(inputargs, operations, "compiling",
  458. memo=memo)
  459. _log = metainterp_sd.jitlog.log_trace(jl.MARK_TRACE_OPT, metainterp_sd, None)
  460. _log.write(inputargs, operations)
  461. assert isinstance(faildescr, AbstractFailDescr)
  462. return metainterp_sd.cpu.compile_bridge(faildescr, inputargs, operations,
  463. original_loop_token, log=log,
  464. logger=metainterp_sd.jitlog)
  465. def forget_optimization_info(lst, reset_values=False):
  466. for item in lst:
  467. item.set_forwarded(None)
  468. # XXX we should really do it, but we need to remember the values
  469. # somehoe for ContinueRunningNormally
  470. if reset_values:
  471. item.reset_value()
  472. def send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, type,
  473. orig_inpargs, memo):
  474. forget_optimization_info(loop.operations)
  475. forget_optimization_info(loop.inputargs)
  476. vinfo = jitdriver_sd.virtualizable_info
  477. if vinfo is not None:
  478. vable = orig_inpargs[jitdriver_sd.index_of_virtualizable].getref_base()
  479. patch_new_loop_to_load_virtualizable_fields(loop, jitdriver_sd, vable)
  480. original_jitcell_token = loop.original_jitcell_token
  481. original_jitcell_token.number = n = metainterp_sd.jitlog.trace_id
  482. if not we_are_translated():
  483. show_procedures(metainterp_sd, loop)
  484. loop.check_consistency()
  485. if metainterp_sd.warmrunnerdesc is not None:
  486. hooks = metainterp_sd.warmrunnerdesc.hooks
  487. debug_info = JitDebugInfo(jitdriver_sd, metainterp_sd.logger_ops,
  488. original_jitcell_token, loop.operations,
  489. type, greenkey)
  490. hooks.before_compile(debug_info)
  491. else:
  492. debug_info = None
  493. hooks = None
  494. operations = get_deep_immutable_oplist(loop.operations)
  495. metainterp_sd.profiler.start_backend()
  496. debug_start("jit-backend")
  497. log = have_debug_prints() or jl.jitlog_enabled()
  498. try:
  499. loopname = jitdriver_sd.warmstate.get_location_str(greenkey)
  500. unique_id = jitdriver_sd.warmstate.get_unique_id(greenkey)
  501. asminfo = do_compile_loop(jitdriver_sd.index, unique_id, metainterp_sd,
  502. loop.inputargs,
  503. operations, original_jitcell_token,
  504. name=loopname,
  505. log=log,
  506. memo=memo)
  507. finally:
  508. debug_stop("jit-backend")
  509. metainterp_sd.profiler.end_backend()
  510. if hooks is not None:
  511. debug_info.asminfo = asminfo
  512. hooks.after_compile(debug_info)
  513. metainterp_sd.stats.add_new_loop(loop)
  514. if not we_are_translated():
  515. metainterp_sd.stats.compiled()
  516. metainterp_sd.log("compiled new " + type)
  517. #
  518. if asminfo is not None:
  519. ops_offset = asminfo.ops_offset
  520. else:
  521. ops_offset = None
  522. metainterp_sd.logger_ops.log_loop(loop.inputargs, loop.operations, n,
  523. type, ops_offset,
  524. name=loopname)
  525. #
  526. if metainterp_sd.warmrunnerdesc is not None: # for tests
  527. metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive(original_jitcell_token)
  528. def send_bridge_to_backend(jitdriver_sd, metainterp_sd, faildescr, inputargs,
  529. operations, original_loop_token, memo):
  530. forget_optimization_info(operations)
  531. forget_optimization_info(inputargs)
  532. if not we_are_translated():
  533. show_procedures(metainterp_sd)
  534. seen = dict.fromkeys(inputargs)
  535. TreeLoop.check_consistency_of_branch(operations, seen)
  536. if metainterp_sd.warmrunnerdesc is not None:
  537. hooks = metainterp_sd.warmrunnerdesc.hooks
  538. debug_info = JitDebugInfo(jitdriver_sd, metainterp_sd.logger_ops,
  539. original_loop_token, operations, 'bridge',
  540. fail_descr=faildescr)
  541. hooks.before_compile_bridge(debug_info)
  542. else:
  543. hooks = None
  544. debug_info = None
  545. operations = get_deep_immutable_oplist(operations)
  546. metainterp_sd.profiler.start_backend()
  547. debug_start("jit-backend")
  548. log = have_debug_prints() or jl.jitlog_enabled()
  549. try:
  550. asminfo = do_compile_bridge(metainterp_sd, faildescr, inputargs,
  551. operations,
  552. original_loop_token, log,
  553. memo)
  554. finally:
  555. debug_stop("jit-backend")
  556. metainterp_sd.profiler.end_backend()
  557. if hooks is not None:
  558. debug_info.asminfo = asminfo
  559. hooks.after_compile_bridge(debug_info)
  560. if not we_are_translated():
  561. metainterp_sd.stats.compiled()
  562. metainterp_sd.log("compiled new bridge")
  563. #
  564. if asminfo is not None:
  565. ops_offset = asminfo.ops_offset
  566. else:
  567. ops_offset = None
  568. metainterp_sd.logger_ops.log_bridge(inputargs, operations, None, faildescr,
  569. ops_offset, memo=memo)
  570. #
  571. #if metainterp_sd.warmrunnerdesc is not None: # for tests
  572. # metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive(
  573. # original_loop_token)
  574. return asminfo
  575. # ____________________________________________________________
  576. class _DoneWithThisFrameDescr(AbstractFailDescr):
  577. final_descr = True
  578. class DoneWithThisFrameDescrVoid(_DoneWithThisFrameDescr):
  579. def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd):
  580. assert jitdriver_sd.result_type == history.VOID
  581. raise jitexc.DoneWithThisFrameVoid()
  582. class DoneWithThisFrameDescrInt(_DoneWithThisFrameDescr):
  583. def get_result(self, cpu, deadframe):
  584. return cpu.get_int_value(deadframe, 0)
  585. def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd):
  586. assert jitdriver_sd.result_type == history.INT
  587. cpu = metainterp_sd.cpu
  588. raise jitexc.DoneWithThisFrameInt(self.get_result(cpu, deadframe))
  589. class DoneWithThisFrameDescrRef(_DoneWithThisFrameDescr):
  590. def get_result(self, cpu, deadframe):
  591. return cpu.get_ref_value(deadframe, 0)
  592. def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd):
  593. assert jitdriver_sd.result_type == history.REF
  594. cpu = metainterp_sd.cpu
  595. raise jitexc.DoneWithThisFrameRef(cpu, self.get_result(cpu, deadframe))
  596. class DoneWithThisFrameDescrFloat(_DoneWithThisFrameDescr):
  597. def get_result(self, cpu, deadframe):
  598. return cpu.get_float_value(deadframe, 0)
  599. def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd):
  600. assert jitdriver_sd.result_type == history.FLOAT
  601. cpu = metainterp_sd.cpu
  602. raise jitexc.DoneWithThisFrameFloat(self.get_result(cpu, deadframe))
  603. class ExitFrameWithExceptionDescrRef(_DoneWithThisFrameDescr):
  604. def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd):
  605. cpu = metainterp_sd.cpu
  606. value = cpu.get_ref_value(deadframe, 0)
  607. raise jitexc.ExitFrameWithExceptionRef(cpu, value)
  608. class TerminatingLoopToken(JitCellToken): # FIXME: kill?
  609. terminating = True
  610. def __init__(self, nargs, finishdescr):
  611. self.finishdescr = finishdescr
  612. def make_done_loop_tokens():
  613. done_with_this_frame_descr_void = DoneWithThisFrameDescrVoid()
  614. done_with_this_frame_descr_int = DoneWithThisFrameDescrInt()
  615. done_with_this_frame_descr_ref = DoneWithThisFrameDescrRef()
  616. done_with_this_frame_descr_float = DoneWithThisFrameDescrFloat()
  617. exit_frame_with_exception_descr_ref = ExitFrameWithExceptionDescrRef()
  618. # pseudo loop tokens to make the life of optimize.py easier
  619. d = {'loop_tokens_done_with_this_frame_int': [
  620. TerminatingLoopToken(1, done_with_this_frame_descr_int)
  621. ],
  622. 'loop_tokens_done_with_this_frame_ref': [
  623. TerminatingLoopToken(1, done_with_this_frame_descr_ref)
  624. ],
  625. 'loop_tokens_done_with_this_frame_float': [
  626. TerminatingLoopToken(1, done_with_this_frame_descr_float)
  627. ],
  628. 'loop_tokens_done_with_this_frame_void': [
  629. TerminatingLoopToken(0, done_with_this_frame_descr_void)
  630. ],
  631. 'loop_tokens_exit_frame_with_exception_ref': [
  632. TerminatingLoopToken(1, exit_frame_with_exception_descr_ref)
  633. ],
  634. }
  635. d.update(locals())
  636. return d
  637. class ResumeDescr(AbstractFailDescr):
  638. _attrs_ = ()
  639. def clone(self):
  640. return self
  641. class AbstractResumeGuardDescr(ResumeDescr):
  642. _attrs_ = ('status',)
  643. status = r_uint(0)
  644. ST_BUSY_FLAG = 0x01 # if set, busy tracing from the guard
  645. ST_TYPE_MASK = 0x06 # mask for the type (TY_xxx)
  646. ST_SHIFT = 3 # in "status >> ST_SHIFT" is stored:
  647. # - if TY_NONE, the jitcounter hash directly
  648. # - otherwise, the guard_value failarg index
  649. ST_SHIFT_MASK = -(1 << ST_SHIFT)
  650. TY_NONE = 0x00
  651. TY_INT = 0x02
  652. TY_REF = 0x04
  653. TY_FLOAT = 0x06
  654. def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd):
  655. if self.must_compile(deadframe, metainterp_sd, jitdriver_sd):
  656. self.start_compiling()
  657. try:
  658. self._trace_and_compile_from_bridge(deadframe, metainterp_sd,
  659. jitdriver_sd)
  660. finally:
  661. self.done_compiling()
  662. else:
  663. from rpython.jit.metainterp.blackhole import resume_in_blackhole
  664. if isinstance(self, ResumeGuardCopiedDescr):
  665. resume_in_blackhole(metainterp_sd, jitdriver_sd, self.prev, deadframe)
  666. else:
  667. assert isinstance(self, ResumeGuardDescr)
  668. resume_in_blackhole(metainterp_sd, jitdriver_sd, self, deadframe)
  669. assert 0, "unreachable"
  670. def _trace_and_compile_from_bridge(self, deadframe, metainterp_sd,
  671. jitdriver_sd):
  672. # 'jitdriver_sd' corresponds to the outermost one, i.e. the one
  673. # of the jit_merge_point where we started the loop, even if the
  674. # loop itself may contain temporarily recursion into other
  675. # jitdrivers.
  676. from rpython.jit.metainterp.pyjitpl import MetaInterp
  677. metainterp = MetaInterp(metainterp_sd, jitdriver_sd)
  678. metainterp.handle_guard_failure(self, deadframe)
  679. _trace_and_compile_from_bridge._dont_inline_ = True
  680. def get_jitcounter_hash(self):
  681. return self.status & self.ST_SHIFT_MASK
  682. def must_compile(self, deadframe, metainterp_sd, jitdriver_sd):
  683. jitcounter = metainterp_sd.warmrunnerdesc.jitcounter
  684. #
  685. if self.status & (self.ST_BUSY_FLAG | self.ST_TYPE_MASK) == 0:
  686. # common case: this is not a guard_value, and we are not
  687. # already busy tracing. The rest of self.status stores a
  688. # valid per-guard index in the jitcounter.
  689. hash = self.status
  690. assert hash == (self.status & self.ST_SHIFT_MASK)
  691. #
  692. # do we have the BUSY flag? If so, we're tracing right now, e.g. in an
  693. # outer invocation of the same function, so don't trace again for now.
  694. elif self.status & self.ST_BUSY_FLAG:
  695. return False
  696. #
  697. else: # we have a GUARD_VALUE that fails.
  698. from rpython.rlib.objectmodel import current_object_addr_as_int
  699. index = intmask(self.status >> self.ST_SHIFT)
  700. typetag = intmask(self.status & self.ST_TYPE_MASK)
  701. # fetch the actual value of the guard_value, possibly turning
  702. # it to an integer
  703. if typetag == self.TY_INT:
  704. intval = metainterp_sd.cpu.get_value_direct(deadframe, 'i',
  705. index)
  706. elif typetag == self.TY_REF:
  707. refval = metainterp_sd.cpu.get_value_direct(deadframe, 'r',
  708. index)
  709. intval = lltype.cast_ptr_to_int(refval)
  710. elif typetag == self.TY_FLOAT:
  711. floatval = metainterp_sd.cpu.get_value_direct(deadframe, 'f',
  712. index)
  713. intval = longlong.gethash_fast(floatval)
  714. else:
  715. assert 0, typetag
  716. if not we_are_translated():
  717. if isinstance(intval, llmemory.AddressAsInt):
  718. intval = llmemory.cast_adr_to_int(
  719. llmemory.cast_int_to_adr(intval), "forced")
  720. hash = r_uint(current_object_addr_as_int(self) * 777767777 +
  721. intval * 1442968193)
  722. #
  723. increment = jitdriver_sd.warmstate.increment_trace_eagerness
  724. return jitcounter.tick(hash, increment)
  725. def start_compiling(self):
  726. # start tracing and compiling from this guard.
  727. self.status |= self.ST_BUSY_FLAG
  728. def done_compiling(self):
  729. # done tracing and compiling from this guard. Note that if the
  730. # bridge has not been successfully compiled, the jitcounter for
  731. # it was reset to 0 already by jitcounter.tick() and not
  732. # incremented at all as long as ST_BUSY_FLAG was set.
  733. self.status &= ~self.ST_BUSY_FLAG
  734. def compile_and_attach(self, metainterp, new_loop, orig_inputargs):
  735. # We managed to create a bridge. Attach the new operations
  736. # to the corresponding guard_op and compile from there
  737. assert metainterp.resumekey_original_loop_token is not None
  738. new_loop.original_jitcell_token = metainterp.resumekey_original_loop_token
  739. inputargs = new_loop.inputargs
  740. if not we_are_translated():
  741. self._debug_subinputargs = new_loop.inputargs
  742. self._debug_suboperations = new_loop.operations
  743. propagate_original_jitcell_token(new_loop)
  744. send_bridge_to_backend(metainterp.jitdriver_sd, metainterp.staticdata,
  745. self, inputargs, new_loop.operations,
  746. new_loop.original_jitcell_token,
  747. metainterp.box_names_memo)
  748. def make_a_counter_per_value(self, guard_value_op, index):
  749. assert guard_value_op.getopnum() == rop.GUARD_VALUE
  750. box = guard_value_op.getarg(0)
  751. if box.type == history.INT:
  752. ty = self.TY_INT
  753. elif box.type == history.REF:
  754. ty = self.TY_REF
  755. elif box.type == history.FLOAT:
  756. ty = self.TY_FLOAT
  757. else:
  758. assert 0, box.type
  759. self.status = ty | (r_uint(index) << self.ST_SHIFT)
  760. def store_hash(self, metainterp_sd):
  761. if metainterp_sd.warmrunnerdesc is not None: # for tests
  762. jitcounter = metainterp_sd.warmrunnerdesc.jitcounter
  763. hash = jitcounter.fetch_next_hash()
  764. self.status = hash & self.ST_SHIFT_MASK
  765. class ResumeGuardCopiedDescr(AbstractResumeGuardDescr):
  766. _attrs_ = ('status', 'prev')
  767. def copy_all_attributes_from(self, other):
  768. assert isinstance(other, ResumeGuardCopiedDescr)
  769. self.prev = other.prev
  770. def clone(self):
  771. cloned = ResumeGuardCopiedDescr()
  772. cloned.copy_all_attributes_from(self)
  773. return cloned
  774. class ResumeGuardDescr(AbstractResumeGuardDescr):
  775. _attrs_ = ('rd_numb', 'rd_count', 'rd_consts', 'rd_virtuals',
  776. 'rd_pendingfields', 'status')
  777. rd_numb = lltype.nullptr(NUMBERING)
  778. rd_count = 0
  779. rd_consts = None
  780. rd_virtuals = None
  781. rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO)
  782. def copy_all_attributes_from(self, other):
  783. if isinstance(other, ResumeGuardCopiedDescr):
  784. other = other.prev
  785. assert isinstance(other, ResumeGuardDescr)
  786. self.rd_count = other.rd_count
  787. self.rd_consts = other.rd_consts
  788. self.rd_pendingfields = other.rd_pendingfields
  789. self.rd_virtuals = other.rd_virtuals
  790. self.rd_numb = other.rd_numb
  791. # we don't copy status
  792. if other.rd_vector_info:
  793. self.rd_vector_info = other.rd_vector_info.clone()
  794. else:
  795. other.rd_vector_info = None
  796. def store_final_boxes(self, guard_op, boxes, metainterp_sd):
  797. guard_op.setfailargs(boxes)
  798. self.rd_count = len(boxes)
  799. self.store_hash(metainterp_sd)
  800. def clone(self):
  801. cloned = ResumeGuardDescr()
  802. cloned.copy_all_attributes_from(self)
  803. return cloned
  804. class ResumeGuardExcDescr(ResumeGuardDescr):
  805. pass
  806. class ResumeGuardCopiedExcDescr(ResumeGuardCopiedDescr):
  807. pass
  808. class ResumeAtPositionDescr(ResumeGuardDescr):
  809. pass
  810. class CompileLoopVersionDescr(ResumeGuardDescr):
  811. def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd):
  812. assert 0, "this guard must never fail"
  813. def exits_early(self):
  814. return True
  815. def loop_version(self):
  816. return True
  817. def clone(self):
  818. cloned = CompileLoopVersionDescr()
  819. cloned.copy_all_attributes_from(self)
  820. return cloned
  821. class AllVirtuals:
  822. llopaque = True
  823. cache = None
  824. def __init__(self, cache):
  825. self.cache = cache
  826. def hide(self, cpu):
  827. ptr = cpu.ts.cast_instance_to_base_ref(self)
  828. return cpu.ts.cast_to_ref(ptr)
  829. @staticmethod
  830. def show(cpu, gcref):
  831. from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance
  832. ptr = cpu.ts.cast_to_baseclass(gcref)
  833. return cast_base_ptr_to_instance(AllVirtuals, ptr)
  834. def invent_fail_descr_for_op(opnum, optimizer, copied_guard=False):
  835. if opnum == rop.GUARD_NOT_FORCED or opnum == rop.GUARD_NOT_FORCED_2:
  836. assert not copied_guard
  837. resumedescr = ResumeGuardForcedDescr()
  838. resumedescr._init(optimizer.metainterp_sd, optimizer.jitdriver_sd)
  839. elif opnum in (rop.GUARD_IS_OBJECT, rop.GUARD_SUBCLASS, rop.GUARD_GC_TYPE):
  840. # note - this only happens in tests
  841. resumedescr = ResumeAtPositionDescr()
  842. elif opnum in (rop.GUARD_EXCEPTION, rop.GUARD_NO_EXCEPTION):
  843. if copied_guard:
  844. resumedescr = ResumeGuardCopiedExcDescr()
  845. else:
  846. resumedescr = ResumeGuardExcDescr()
  847. else:
  848. if copied_guard:
  849. resumedescr = ResumeGuardCopiedDescr()
  850. else:
  851. resumedescr = ResumeGuardDescr()
  852. return resumedescr
  853. class ResumeGuardForcedDescr(ResumeGuardDescr):
  854. def _init(self, metainterp_sd, jitdriver_sd):
  855. # to please the annotator
  856. self.metainterp_sd = metainterp_sd
  857. self.jitdriver_sd = jitdriver_sd
  858. def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd):
  859. # Failures of a GUARD_NOT_FORCED are never compiled, but
  860. # always just blackholed. First fish for the data saved when
  861. # the virtualrefs and virtualizable have been forced by
  862. # handle_async_forcing() just a moment ago.
  863. from rpython.jit.metainterp.blackhole import resume_in_blackhole
  864. hidden_all_virtuals = metainterp_sd.cpu.get_savedata_ref(deadframe)
  865. obj = AllVirtuals.show(metainterp_sd.cpu, hidden_all_virtuals)
  866. all_virtuals = obj.cache
  867. if all_virtuals is None:
  868. all_virtuals = ResumeDataDirectReader.VirtualCache([], [])
  869. assert jitdriver_sd is self.jitdriver_sd
  870. resume_in_blackhole(metainterp_sd, jitdriver_sd, self, deadframe,
  871. all_virtuals)
  872. assert 0, "unreachable"
  873. @staticmethod
  874. @dont_look_inside
  875. def force_now(cpu, token):
  876. # Called during a residual call from the assembler, if the code
  877. # actually needs to force one of the virtualrefs or the virtualizable.
  878. # Implemented by forcing *all* virtualrefs and the virtualizable.
  879. # don't interrupt me! If the stack runs out in force_from_resumedata()
  880. # then we have seen cpu.force() but not self.save_data(), leaving in
  881. # an inconsistent state
  882. rstack._stack_criticalcode_start()
  883. try:
  884. deadframe = cpu.force(token)
  885. # this should set descr to ResumeGuardForcedDescr, if it
  886. # was not that already
  887. faildescr = cpu.get_latest_descr(deadframe)
  888. assert isinstance(faildescr, ResumeGuardForcedDescr)
  889. faildescr.handle_async_forcing(deadframe)
  890. finally:
  891. rstack._stack_criticalcode_stop()
  892. def handle_async_forcing(self, deadframe):
  893. from rpython.jit.metainterp.resume import force_from_resumedata
  894. metainterp_sd = self.metainterp_sd
  895. vinfo = self.jitdriver_sd.virtualizable_info
  896. ginfo = self.jitdriver_sd.greenfield_info
  897. # there is some chance that this is already forced. In this case
  898. # the virtualizable would have a token = NULL
  899. all_virtuals = force_from_resumedata(metainterp_sd, self, deadframe,
  900. vinfo, ginfo)
  901. # The virtualizable data was stored on the real virtualizable above.
  902. # Handle all_virtuals: keep them for later blackholing from the
  903. # future failure of the GUARD_NOT_FORCED
  904. obj = AllVirtuals(all_virtuals)
  905. hidden_all_virtuals = obj.hide(metainterp_sd.cpu)
  906. metainterp_sd.cpu.set_savedata_ref(deadframe, hidden_all_virtuals)
  907. class ResumeFromInterpDescr(ResumeDescr):
  908. def __init__(self, original_greenkey):
  909. self.original_greenkey = original_greenkey
  910. def compile_and_attach(self, metainterp, new_loop, orig_inputargs):
  911. # We managed to create a bridge going from the interpreter
  912. # to previously-compiled code. We keep 'new_loop', which is not
  913. # a loop at all but ends in a jump to the target loop. It starts
  914. # with completely unoptimized arguments, as in the interpreter.
  915. metainterp_sd = metainterp.staticdata
  916. jitdriver_sd = metainterp.jitdriver_sd
  917. new_loop.original_jitcell_token = jitcell_token = make_jitcell_token(jitdriver_sd)
  918. propagate_original_jitcell_token(new_loop)
  919. send_loop_to_backend(self.original_greenkey, metainterp.jitdriver_sd,
  920. metainterp_sd, new_loop, "entry bridge",
  921. orig_inputargs, metainterp.box_names_memo)
  922. # send the new_loop to warmspot.py, to be called directly the next time
  923. jitdriver_sd.warmstate.attach_procedure_to_interp(
  924. self.original_greenkey, jitcell_token)
  925. metainterp_sd.stats.add_jitcell_token(jitcell_token)
  926. def compile_trace(metainterp, resumekey, runtime_boxes):
  927. """Try to compile a new bridge leading from the beginning of the history
  928. to some existing place.
  929. """
  930. from rpython.jit.metainterp.optimizeopt import optimize_trace
  931. # The history contains new operations to attach as the code for the
  932. # failure of 'resumekey.guard_op'.
  933. #
  934. # Attempt to use optimize_bridge(). This may return None in case
  935. # it does not work -- i.e. none of the existing old_loop_tokens match.
  936. metainterp_sd = metainterp.staticdata
  937. jitdriver_sd = metainterp.jitdriver_sd
  938. #
  939. jd_name = jitdriver_sd.jitdriver.name
  940. metainterp_sd.jitlog.start_new_trace(metainterp_sd,
  941. faildescr=resumekey, entry_bridge=False, jd_name=jd_name)
  942. #
  943. if isinstance(resumekey, ResumeAtPositionDescr):
  944. inline_short_preamble = False
  945. else:
  946. inline_short_preamble = True
  947. inputargs = metainterp.history.inputargs[:]
  948. trace = metainterp.history.trace
  949. jitdriver_sd = metainterp.jitdriver_sd
  950. enable_opts = jitdriver_sd.warmstate.enable_opts
  951. call_pure_results = metainterp.call_pure_results
  952. if metainterp.history.ends_with_jump:
  953. data = BridgeCompileData(trace, runtime_boxes,
  954. call_pure_results=call_pure_results,
  955. enable_opts=enable_opts,
  956. inline_short_preamble=inline_short_preamble)
  957. else:
  958. data = SimpleCompileData(trace,
  959. call_pure_results=call_pure_results,
  960. enable_opts=enable_opts)
  961. try:
  962. info, newops = optimize_trace(metainterp_sd, jitdriver_sd,
  963. data, metainterp.box_names_memo)
  964. except InvalidLoop:
  965. metainterp_sd.jitlog.trace_aborted()
  966. #pdb.post_mortem(sys.exc_info()[2])
  967. debug_print("compile_new_bridge: got an InvalidLoop")
  968. # XXX I am fairly convinced that optimize_bridge cannot actually raise
  969. # InvalidLoop
  970. debug_print('InvalidLoop in compile_new_bridge')
  971. return None
  972. new_trace = create_empty_loop(metainterp)
  973. new_trace.operations = newops
  974. if info.quasi_immutable_deps:
  975. new_trace.quasi_immutable_deps = info.quasi_immutable_deps
  976. if info.final():
  977. new_trace.inputargs = info.inputargs
  978. target_token = new_trace.operations[-1].getdescr()
  979. resumekey.compile_and_attach(metainterp, new_trace, inputargs)
  980. record_loop_or_bridge(metainterp_sd, new_trace)
  981. return target_token
  982. new_trace.inputargs = info.renamed_inputargs
  983. metainterp.retrace_needed(new_trace, info)
  984. return None
  985. # ____________________________________________________________
  986. memory_error = MemoryError()
  987. class PropagateExceptionDescr(AbstractFailDescr):
  988. def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd):
  989. cpu = metainterp_sd.cpu
  990. exception = cpu.grab_exc_value(deadframe)
  991. if not exception:
  992. exception = cast_instance_to_gcref(memory_error)
  993. assert exception, "PropagateExceptionDescr: no exception??"
  994. raise jitexc.ExitFrameWithExceptionRef(cpu, exception)
  995. def compile_tmp_callback(cpu, jitdriver_sd, greenboxes, redargtypes,
  996. memory_manager=None):
  997. """Make a LoopToken that corresponds to assembler code that just
  998. calls back the interpreter. Used temporarily: a fully compiled
  999. version of the code may end up replacing it.
  1000. """
  1001. jitcell_token = make_jitcell_token(jitdriver_sd)
  1002. nb_red_args = jitdriver_sd.num_red_args
  1003. assert len(redargtypes) == nb_red_args
  1004. inputargs = []
  1005. for kind in redargtypes:
  1006. if kind == history.INT:
  1007. box = InputArgInt()
  1008. elif kind == history.REF:
  1009. box = InputArgRef()
  1010. elif kind == history.FLOAT:
  1011. box = InputArgFloat()
  1012. else:
  1013. raise AssertionError
  1014. inputargs.append(box)
  1015. k = jitdriver_sd.portal_runner_adr
  1016. funcbox = history.ConstInt(heaptracker.adr2int(k))
  1017. callargs = [funcbox] + greenboxes + inputargs
  1018. #
  1019. jd = jitdriver_sd
  1020. opnum = OpHelpers.call_for_descr(jd.portal_calldescr)
  1021. call_op = ResOperation(opnum, callargs, descr=jd.portal_calldescr)
  1022. if call_op.type != 'v' is not None:
  1023. finishargs = [call_op]
  1024. else:
  1025. finishargs = []
  1026. #
  1027. faildescr = jitdriver_sd.propagate_exc_descr
  1028. operations = [
  1029. call_op,
  1030. ResOperation(rop.GUARD_NO_EXCEPTION, [], descr=faildescr),
  1031. ResOperation(rop.FINISH, finishargs, descr=jd.portal_finishtoken)
  1032. ]
  1033. operations[1].setfailargs([])
  1034. operations = get_deep_immutable_oplist(operations)
  1035. cpu.compile_loop(inputargs, operations, jitcell_token, log=False)
  1036. if memory_manager is not None: # for tests
  1037. memory_manager.keep_loop_alive(jitcell_token)
  1038. return jitcell_token