PageRenderTime 48ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/jit/metainterp/warmstate.py

https://bitbucket.org/pypy/pypy/
Python | 786 lines | 623 code | 63 blank | 100 comment | 85 complexity | 356b78adaa0df241f1d0004efb46ade1 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import sys
  2. import weakref
  3. from rpython.jit.codewriter import support, heaptracker, longlong
  4. from rpython.jit.metainterp import resoperation, history, jitexc
  5. from rpython.rlib.debug import debug_start, debug_stop, debug_print
  6. from rpython.rlib.debug import have_debug_prints_for
  7. from rpython.rlib.jit import PARAMETERS
  8. from rpython.rlib.rjitlog import rjitlog as jl
  9. from rpython.rlib.nonconst import NonConstant
  10. from rpython.rlib.objectmodel import specialize, we_are_translated, r_dict
  11. from rpython.rlib.rarithmetic import intmask, r_uint
  12. from rpython.rlib.unroll import unrolling_iterable
  13. from rpython.rtyper.annlowlevel import (hlstr, cast_base_ptr_to_instance,
  14. cast_object_to_ptr)
  15. from rpython.rtyper.lltypesystem import lltype, llmemory, rstr, rffi
  16. # ____________________________________________________________
  17. @specialize.arg(0)
  18. def specialize_value(TYPE, x):
  19. """'x' must be a Signed, a GCREF or a FLOATSTORAGE.
  20. This function casts it to a more specialized type, like Char or Ptr(..).
  21. """
  22. INPUT = lltype.typeOf(x)
  23. if INPUT is lltype.Signed:
  24. if isinstance(TYPE, lltype.Ptr) and TYPE.TO._gckind == 'raw':
  25. # non-gc pointer
  26. return rffi.cast(TYPE, x)
  27. elif TYPE is lltype.SingleFloat:
  28. return longlong.int2singlefloat(x)
  29. else:
  30. return lltype.cast_primitive(TYPE, x)
  31. elif INPUT is longlong.FLOATSTORAGE:
  32. if longlong.is_longlong(TYPE):
  33. return rffi.cast(TYPE, x)
  34. assert TYPE is lltype.Float
  35. return longlong.getrealfloat(x)
  36. else:
  37. return lltype.cast_opaque_ptr(TYPE, x)
  38. @specialize.ll()
  39. def unspecialize_value(value):
  40. """Casts 'value' to a Signed, a GCREF or a FLOATSTORAGE."""
  41. if isinstance(lltype.typeOf(value), lltype.Ptr):
  42. if lltype.typeOf(value).TO._gckind == 'gc':
  43. return lltype.cast_opaque_ptr(llmemory.GCREF, value)
  44. else:
  45. adr = llmemory.cast_ptr_to_adr(value)
  46. return heaptracker.adr2int(adr)
  47. elif isinstance(value, float):
  48. return longlong.getfloatstorage(value)
  49. else:
  50. return lltype.cast_primitive(lltype.Signed, value)
  51. @specialize.arg(0)
  52. def unwrap(TYPE, box):
  53. if TYPE is lltype.Void:
  54. return None
  55. if isinstance(TYPE, lltype.Ptr):
  56. if TYPE.TO._gckind == "gc":
  57. return box.getref(TYPE)
  58. else:
  59. adr = heaptracker.int2adr(box.getint())
  60. return llmemory.cast_adr_to_ptr(adr, TYPE)
  61. if TYPE == lltype.Float:
  62. return box.getfloat()
  63. else:
  64. return lltype.cast_primitive(TYPE, box.getint())
  65. @specialize.ll()
  66. def wrap(cpu, value, in_const_box=False):
  67. if isinstance(lltype.typeOf(value), lltype.Ptr):
  68. if lltype.typeOf(value).TO._gckind == 'gc':
  69. value = lltype.cast_opaque_ptr(llmemory.GCREF, value)
  70. if in_const_box:
  71. return history.ConstPtr(value)
  72. else:
  73. res = history.RefFrontendOp(0)
  74. res.setref_base(value)
  75. return res
  76. else:
  77. adr = llmemory.cast_ptr_to_adr(value)
  78. value = heaptracker.adr2int(adr)
  79. # fall through to the end of the function
  80. elif (isinstance(value, float) or
  81. longlong.is_longlong(lltype.typeOf(value))):
  82. if isinstance(value, float):
  83. value = longlong.getfloatstorage(value)
  84. else:
  85. value = rffi.cast(lltype.SignedLongLong, value)
  86. if in_const_box:
  87. return history.ConstFloat(value)
  88. else:
  89. res = history.FloatFrontendOp(0)
  90. res.setfloatstorage(value)
  91. return res
  92. elif isinstance(value, str) or isinstance(value, unicode):
  93. assert len(value) == 1 # must be a character
  94. value = ord(value)
  95. elif lltype.typeOf(value) is lltype.SingleFloat:
  96. value = longlong.singlefloat2int(value)
  97. else:
  98. value = intmask(value)
  99. if in_const_box:
  100. return history.ConstInt(value)
  101. else:
  102. res = history.IntFrontendOp(0)
  103. res.setint(value)
  104. return res
  105. @specialize.arg(0)
  106. def equal_whatever(TYPE, x, y):
  107. if isinstance(TYPE, lltype.Ptr):
  108. if TYPE.TO is rstr.STR or TYPE.TO is rstr.UNICODE:
  109. return rstr.LLHelpers.ll_streq(x, y)
  110. return x == y
  111. @specialize.arg(0)
  112. def hash_whatever(TYPE, x):
  113. # Hash of lltype object.
  114. # Only supports strings, unicodes and regular instances,
  115. # as well as primitives that can meaningfully be cast to Signed.
  116. if isinstance(TYPE, lltype.Ptr) and TYPE.TO._gckind == 'gc':
  117. if TYPE.TO is rstr.STR or TYPE.TO is rstr.UNICODE:
  118. return rstr.LLHelpers.ll_strhash(x) # assumed not null
  119. else:
  120. if x:
  121. return lltype.identityhash(x)
  122. else:
  123. return 0
  124. else:
  125. return rffi.cast(lltype.Signed, x)
  126. JC_TRACING = 0x01
  127. JC_DONT_TRACE_HERE = 0x02
  128. JC_TEMPORARY = 0x04
  129. JC_TRACING_OCCURRED= 0x08
  130. class BaseJitCell(object):
  131. """Subclasses of BaseJitCell are used in tandem with the single
  132. JitCounter instance to record places in the JIT-tracked user program
  133. where something particular occurs with the JIT. For some
  134. 'greenkeys' (e.g. Python bytecode position), we create one instance
  135. of JitCell and attach it to that greenkey. This is implemented
  136. with jitcounter.install_new_cell(), but conceptually you can think
  137. about JitCode instances as attached to some locations of the
  138. app-level Python code.
  139. We create subclasses of BaseJitCell --one per jitdriver-- so that
  140. they can store greenkeys of different types.
  141. Note that we don't create a JitCell the first time we see a given
  142. greenkey position in the interpreter. At first, we only hash the
  143. greenkey and use that in the JitCounter to record the number of
  144. times we have seen it. We only create a JitCell when the
  145. JitCounter's total time value reaches 1.0 and we are starting to
  146. JIT-compile.
  147. A JitCell has a 'wref_procedure_token' that is non-None when we
  148. actually have a compiled procedure for that greenkey. (It is a
  149. weakref, so that it could later be freed; in this case the JitCell
  150. will likely be reclaimed a bit later by 'should_remove_jitcell()'.)
  151. There are other less-common cases where we also create a JitCell: to
  152. record some long-term flags about the greenkey. In general, a
  153. JitCell can have any combination of the following flags set:
  154. JC_TRACING: we are now tracing the loop from this greenkey.
  155. We'll likely end up with a wref_procedure_token, soonish.
  156. JC_TRACING_OCCURRED: set if JC_TRACING was set at least once.
  157. JC_TEMPORARY: a "temporary" wref_procedure_token.
  158. It's the procedure_token of a dummy loop that simply calls
  159. back the interpreter. Used for a CALL_ASSEMBLER where the
  160. target was not compiled yet. In this situation we are still
  161. ticking the JitCounter for the same hash, until we reach the
  162. threshold and start tracing the loop in earnest.
  163. JC_DONT_TRACE_HERE: when tracing, don't inline calls to
  164. this particular function. (We only set this flag when aborting
  165. due to a trace too long, so we use the same flag as a hint to
  166. also mean "please trace from here as soon as possible".)
  167. """
  168. flags = 0 # JC_xxx flags
  169. wref_procedure_token = None
  170. next = None
  171. def get_procedure_token(self):
  172. if self.wref_procedure_token is not None:
  173. token = self.wref_procedure_token()
  174. if token and not token.invalidated:
  175. return token
  176. return None
  177. def has_seen_a_procedure_token(self):
  178. return self.wref_procedure_token is not None
  179. def set_procedure_token(self, token, tmp=False):
  180. self.wref_procedure_token = self._makeref(token)
  181. if tmp:
  182. self.flags |= JC_TEMPORARY
  183. else:
  184. self.flags &= ~JC_TEMPORARY
  185. def _makeref(self, token):
  186. assert token is not None
  187. return weakref.ref(token)
  188. def should_remove_jitcell(self):
  189. if self.get_procedure_token() is not None:
  190. return False # don't remove JitCells with a procedure_token
  191. if self.flags & JC_TRACING:
  192. return False # don't remove JitCells that are being traced
  193. if self.flags & JC_DONT_TRACE_HERE:
  194. # if we have this flag, and we *had* a procedure_token but
  195. # we no longer have one, then remove me. this prevents this
  196. # JitCell from being immortal.
  197. return self.has_seen_a_procedure_token() # i.e. dead weakref
  198. return True # Other JitCells can be removed.
  199. # ____________________________________________________________
  200. class WarmEnterState(object):
  201. def __init__(self, warmrunnerdesc, jitdriver_sd):
  202. "NOT_RPYTHON"
  203. self.warmrunnerdesc = warmrunnerdesc
  204. self.jitdriver_sd = jitdriver_sd
  205. if warmrunnerdesc is not None: # for tests
  206. self.cpu = warmrunnerdesc.cpu
  207. try:
  208. self.profiler = warmrunnerdesc.metainterp_sd.profiler
  209. except AttributeError: # for tests
  210. self.profiler = None
  211. # initialize the state with the default values of the
  212. # parameters specified in rlib/jit.py
  213. if self.warmrunnerdesc is not None:
  214. for name, default_value in PARAMETERS.items():
  215. meth = getattr(self, 'set_param_' + name)
  216. meth(default_value)
  217. def _compute_threshold(self, threshold):
  218. return self.warmrunnerdesc.jitcounter.compute_threshold(threshold)
  219. def set_param_threshold(self, threshold):
  220. self.increment_threshold = self._compute_threshold(threshold)
  221. def set_param_function_threshold(self, threshold):
  222. self.increment_function_threshold = self._compute_threshold(threshold)
  223. def set_param_trace_eagerness(self, value):
  224. self.increment_trace_eagerness = self._compute_threshold(value)
  225. def set_param_trace_limit(self, value):
  226. self.trace_limit = value
  227. def set_param_decay(self, decay):
  228. self.warmrunnerdesc.jitcounter.set_decay(decay)
  229. def set_param_inlining(self, value):
  230. self.inlining = value
  231. def set_param_disable_unrolling(self, value):
  232. self.disable_unrolling_threshold = value
  233. def set_param_enable_opts(self, value):
  234. from rpython.jit.metainterp.optimizeopt import ALL_OPTS_DICT, ALL_OPTS_NAMES
  235. d = {}
  236. if NonConstant(False):
  237. value = 'blah' # not a constant ''
  238. if value is None or value == 'all':
  239. value = ALL_OPTS_NAMES
  240. for name in value.split(":"):
  241. if name:
  242. if name not in ALL_OPTS_DICT:
  243. raise ValueError('Unknown optimization ' + name)
  244. d[name] = None
  245. self.enable_opts = d
  246. def set_param_loop_longevity(self, value):
  247. # note: it's a global parameter, not a per-jitdriver one
  248. if (self.warmrunnerdesc is not None and
  249. self.warmrunnerdesc.memory_manager is not None): # all for tests
  250. self.warmrunnerdesc.memory_manager.set_max_age(value)
  251. def set_param_retrace_limit(self, value):
  252. if self.warmrunnerdesc:
  253. if self.warmrunnerdesc.memory_manager:
  254. self.warmrunnerdesc.memory_manager.retrace_limit = value
  255. def set_param_max_retrace_guards(self, value):
  256. if self.warmrunnerdesc:
  257. if self.warmrunnerdesc.memory_manager:
  258. self.warmrunnerdesc.memory_manager.max_retrace_guards = value
  259. def set_param_max_unroll_loops(self, value):
  260. if self.warmrunnerdesc:
  261. if self.warmrunnerdesc.memory_manager:
  262. self.warmrunnerdesc.memory_manager.max_unroll_loops = value
  263. def set_param_max_unroll_recursion(self, value):
  264. if self.warmrunnerdesc:
  265. if self.warmrunnerdesc.memory_manager:
  266. self.warmrunnerdesc.memory_manager.max_unroll_recursion = value
  267. def set_param_vec(self, value):
  268. self.vec = bool(value)
  269. def set_param_vec_all(self, value):
  270. self.vec_all = bool(value)
  271. def set_param_vec_cost(self, value):
  272. self.vec_cost = bool(value)
  273. def set_param_vec_length(self, value):
  274. self.vec_length = int(value)
  275. def set_param_vec_ratio(self, value):
  276. self.vec_ratio = value / 10.0
  277. def set_param_vec_guard_ratio(self, value):
  278. self.vec_guard_ratio = value / 10.0
  279. def disable_noninlinable_function(self, greenkey):
  280. cell = self.JitCell.ensure_jit_cell_at_key(greenkey)
  281. cell.flags |= JC_DONT_TRACE_HERE
  282. debug_start("jit-disableinlining")
  283. loc = self.get_location_str(greenkey)
  284. debug_print("disabled inlining", loc)
  285. debug_stop("jit-disableinlining")
  286. def attach_procedure_to_interp(self, greenkey, procedure_token):
  287. cell = self.JitCell.ensure_jit_cell_at_key(greenkey)
  288. old_token = cell.get_procedure_token()
  289. cell.set_procedure_token(procedure_token)
  290. if old_token is not None:
  291. self.cpu.redirect_call_assembler(old_token, procedure_token)
  292. # procedure_token is also kept alive by any loop that used
  293. # to point to old_token. Actually freeing old_token early
  294. # is a pointless optimization (it is tiny).
  295. old_token.record_jump_to(procedure_token)
  296. # ----------
  297. def make_entry_point(self):
  298. "NOT_RPYTHON"
  299. from rpython.jit.metainterp import compile
  300. if hasattr(self, 'entry_point_fns'):
  301. return self.entry_point_fns
  302. warmrunnerdesc = self.warmrunnerdesc
  303. metainterp_sd = warmrunnerdesc.metainterp_sd
  304. jitdriver_sd = self.jitdriver_sd
  305. vinfo = jitdriver_sd.virtualizable_info
  306. index_of_virtualizable = jitdriver_sd.index_of_virtualizable
  307. num_green_args = jitdriver_sd.num_green_args
  308. JitCell = self.make_jitcell_subclass()
  309. self.make_jitdriver_callbacks()
  310. confirm_enter_jit = self.confirm_enter_jit
  311. range_red_args = unrolling_iterable(
  312. range(num_green_args, num_green_args + jitdriver_sd.num_red_args))
  313. name_red_args = unrolling_iterable(
  314. [(i, 'arg%d' % i) for i in range(jitdriver_sd.num_red_args)])
  315. # get a new specialized copy of the method
  316. ARGS = []
  317. for kind in jitdriver_sd.red_args_types:
  318. if kind == 'int':
  319. ARGS.append(lltype.Signed)
  320. elif kind == 'ref':
  321. ARGS.append(llmemory.GCREF)
  322. elif kind == 'float':
  323. ARGS.append(longlong.FLOATSTORAGE)
  324. else:
  325. assert 0, kind
  326. func_execute_token = self.cpu.make_execute_token(*ARGS)
  327. cpu = self.cpu
  328. jitcounter = self.warmrunnerdesc.jitcounter
  329. result_type = jitdriver_sd.result_type
  330. def execute_assembler(loop_token, *args):
  331. # Call the backend to run the 'looptoken' with the given
  332. # input args.
  333. # If we have a virtualizable, we have to clear its
  334. # state, to make sure we enter with vable_token being NONE
  335. #
  336. if vinfo is not None:
  337. virtualizable = args[index_of_virtualizable]
  338. vinfo.clear_vable_token(virtualizable)
  339. deadframe = func_execute_token(loop_token, *args)
  340. #
  341. # Record in the memmgr that we just ran this loop,
  342. # so that it will keep it alive for a longer time
  343. warmrunnerdesc.memory_manager.keep_loop_alive(loop_token)
  344. #
  345. # Handle the failure
  346. fail_descr = cpu.get_latest_descr(deadframe)
  347. # First, a fast path to avoid raising and immediately catching
  348. # a DoneWithThisFrame exception
  349. if result_type == history.VOID:
  350. if isinstance(fail_descr, compile.DoneWithThisFrameDescrVoid):
  351. return None
  352. if result_type == history.INT:
  353. if isinstance(fail_descr, compile.DoneWithThisFrameDescrInt):
  354. return fail_descr.get_result(cpu, deadframe)
  355. if result_type == history.REF:
  356. if isinstance(fail_descr, compile.DoneWithThisFrameDescrRef):
  357. return fail_descr.get_result(cpu, deadframe)
  358. if result_type == history.FLOAT:
  359. if isinstance(fail_descr, compile.DoneWithThisFrameDescrFloat):
  360. return fail_descr.get_result(cpu, deadframe)
  361. #
  362. # General case
  363. fail_descr.handle_fail(deadframe, metainterp_sd, jitdriver_sd)
  364. assert 0, "should have raised"
  365. def bound_reached(hash, cell, *args):
  366. if not confirm_enter_jit(*args):
  367. return
  368. jitcounter.decay_all_counters()
  369. # start tracing
  370. from rpython.jit.metainterp.pyjitpl import MetaInterp
  371. metainterp = MetaInterp(metainterp_sd, jitdriver_sd)
  372. greenargs = args[:num_green_args]
  373. if cell is None:
  374. cell = JitCell(*greenargs)
  375. jitcounter.install_new_cell(hash, cell)
  376. cell.flags |= JC_TRACING | JC_TRACING_OCCURRED
  377. try:
  378. metainterp.compile_and_run_once(jitdriver_sd, *args)
  379. finally:
  380. cell.flags &= ~JC_TRACING
  381. def maybe_compile_and_run(increment_threshold, *args):
  382. """Entry point to the JIT. Called at the point with the
  383. can_enter_jit() hint, and at the start of a function
  384. with a different threshold.
  385. """
  386. # Look for the cell corresponding to the current greenargs.
  387. # Search for the JitCell that is of the correct subclass of
  388. # BaseJitCell, and that stores a key that compares equal.
  389. # These few lines inline some logic that is also on the
  390. # JitCell class, to avoid computing the hash several times.
  391. greenargs = args[:num_green_args]
  392. hash = JitCell.get_uhash(*greenargs)
  393. cell = jitcounter.lookup_chain(hash)
  394. while cell is not None:
  395. if isinstance(cell, JitCell) and cell.comparekey(*greenargs):
  396. break # found
  397. cell = cell.next
  398. else:
  399. # not found. increment the counter
  400. if jitcounter.tick(hash, increment_threshold):
  401. bound_reached(hash, None, *args)
  402. return
  403. # Here, we have found 'cell'.
  404. #
  405. if cell.flags & (JC_TRACING | JC_TEMPORARY):
  406. if cell.flags & JC_TRACING:
  407. # tracing already happening in some outer invocation of
  408. # this function. don't trace a second time.
  409. return
  410. # attached by compile_tmp_callback(). count normally
  411. if jitcounter.tick(hash, increment_threshold):
  412. bound_reached(hash, cell, *args)
  413. return
  414. # machine code was already compiled for these greenargs
  415. procedure_token = cell.get_procedure_token()
  416. if procedure_token is None:
  417. if cell.flags & JC_DONT_TRACE_HERE:
  418. if not cell.has_seen_a_procedure_token():
  419. # A JC_DONT_TRACE_HERE, i.e. a non-inlinable function.
  420. # If we never tried to trace it, try it now immediately.
  421. # Otherwise, count normally.
  422. if cell.flags & JC_TRACING_OCCURRED:
  423. tick = jitcounter.tick(hash, increment_threshold)
  424. else:
  425. tick = True
  426. if tick:
  427. bound_reached(hash, cell, *args)
  428. return
  429. # it was an aborted compilation, or maybe a weakref that
  430. # has been freed
  431. jitcounter.cleanup_chain(hash)
  432. return
  433. if not confirm_enter_jit(*args):
  434. return
  435. # extract and unspecialize the red arguments to pass to
  436. # the assembler
  437. execute_args = ()
  438. for i in range_red_args:
  439. execute_args += (unspecialize_value(args[i]), )
  440. # run it, but from outside in ll_portal_runner, not from here
  441. # (this avoids RPython-level recursion with no corresponding
  442. # app-level recursion, as shown by issues 2200 and 2335)
  443. raise EnterJitAssembler(procedure_token, *execute_args)
  444. class EnterJitAssembler(jitexc.JitException):
  445. def __init__(self, procedure_token, *args):
  446. self.procedure_token = procedure_token
  447. for i, argname in name_red_args:
  448. setattr(self, argname, args[i])
  449. def execute(self):
  450. args = ()
  451. for i, argname in name_red_args:
  452. args += (getattr(self, argname), )
  453. return execute_assembler(self.procedure_token, *args)
  454. maybe_compile_and_run._dont_inline_ = True
  455. self.execute_assembler = execute_assembler
  456. self.entry_point_fns = (maybe_compile_and_run,
  457. EnterJitAssembler)
  458. return self.entry_point_fns
  459. # ----------
  460. def make_unwrap_greenkey(self):
  461. "NOT_RPYTHON"
  462. if hasattr(self, 'unwrap_greenkey'):
  463. return self.unwrap_greenkey
  464. #
  465. jitdriver_sd = self.jitdriver_sd
  466. green_args_spec = unrolling_iterable(jitdriver_sd._green_args_spec)
  467. #
  468. def unwrap_greenkey(greenkey):
  469. greenargs = ()
  470. i = 0
  471. for TYPE in green_args_spec:
  472. greenbox = greenkey[i]
  473. assert isinstance(greenbox, history.Const)
  474. value = unwrap(TYPE, greenbox)
  475. greenargs += (value,)
  476. i = i + 1
  477. return greenargs
  478. #
  479. unwrap_greenkey._always_inline_ = True
  480. self.unwrap_greenkey = unwrap_greenkey
  481. return unwrap_greenkey
  482. # ----------
  483. def make_jitcell_subclass(self):
  484. "NOT_RPYTHON"
  485. if hasattr(self, 'JitCell'):
  486. return self.JitCell
  487. #
  488. jitcounter = self.warmrunnerdesc.jitcounter
  489. jitdriver_sd = self.jitdriver_sd
  490. green_args_name_spec = unrolling_iterable([('g%d' % i, TYPE)
  491. for i, TYPE in enumerate(jitdriver_sd._green_args_spec)])
  492. unwrap_greenkey = self.make_unwrap_greenkey()
  493. #
  494. class JitCell(BaseJitCell):
  495. def __init__(self, *greenargs):
  496. i = 0
  497. for attrname, _ in green_args_name_spec:
  498. setattr(self, attrname, greenargs[i])
  499. i = i + 1
  500. def comparekey(self, *greenargs2):
  501. i = 0
  502. for attrname, TYPE in green_args_name_spec:
  503. item1 = getattr(self, attrname)
  504. if not equal_whatever(TYPE, item1, greenargs2[i]):
  505. return False
  506. i = i + 1
  507. return True
  508. @staticmethod
  509. def get_uhash(*greenargs):
  510. x = r_uint(-1888132534)
  511. i = 0
  512. for _, TYPE in green_args_name_spec:
  513. item = greenargs[i]
  514. y = r_uint(hash_whatever(TYPE, item))
  515. x = (x ^ y) * r_uint(1405695061) # prime number, 2**30~31
  516. i = i + 1
  517. return x
  518. @staticmethod
  519. def get_jitcell(*greenargs):
  520. hash = JitCell.get_uhash(*greenargs)
  521. cell = jitcounter.lookup_chain(hash)
  522. while cell is not None:
  523. if (isinstance(cell, JitCell) and
  524. cell.comparekey(*greenargs)):
  525. return cell
  526. cell = cell.next
  527. return None
  528. @staticmethod
  529. def get_jit_cell_at_key(greenkey):
  530. greenargs = unwrap_greenkey(greenkey)
  531. return JitCell.get_jitcell(*greenargs)
  532. @staticmethod
  533. def trace_next_iteration(greenkey):
  534. greenargs = unwrap_greenkey(greenkey)
  535. JitCell._trace_next_iteration(*greenargs)
  536. @staticmethod
  537. def _trace_next_iteration(*greenargs):
  538. hash = JitCell.get_uhash(*greenargs)
  539. jitcounter.change_current_fraction(hash, 0.98)
  540. @staticmethod
  541. def trace_next_iteration_hash(hash):
  542. jitcounter.change_current_fraction(hash, 0.98)
  543. @staticmethod
  544. def ensure_jit_cell_at_key(greenkey):
  545. greenargs = unwrap_greenkey(greenkey)
  546. return JitCell._ensure_jit_cell_at_key(*greenargs)
  547. @staticmethod
  548. def _ensure_jit_cell_at_key(*greenargs):
  549. hash = JitCell.get_uhash(*greenargs)
  550. cell = jitcounter.lookup_chain(hash)
  551. while cell is not None:
  552. if (isinstance(cell, JitCell) and
  553. cell.comparekey(*greenargs)):
  554. return cell
  555. cell = cell.next
  556. newcell = JitCell(*greenargs)
  557. jitcounter.install_new_cell(hash, newcell)
  558. return newcell
  559. @staticmethod
  560. def dont_trace_here(*greenargs):
  561. cell = JitCell._ensure_jit_cell_at_key(*greenargs)
  562. cell.flags |= JC_DONT_TRACE_HERE
  563. #
  564. self.JitCell = JitCell
  565. return JitCell
  566. # ----------
  567. def make_jitdriver_callbacks(self):
  568. if hasattr(self, 'get_location_str'):
  569. return
  570. #
  571. warmrunnerdesc = self.warmrunnerdesc
  572. unwrap_greenkey = self.make_unwrap_greenkey()
  573. JitCell = self.make_jitcell_subclass()
  574. jd = self.jitdriver_sd
  575. cpu = self.cpu
  576. rtyper = self.warmrunnerdesc.rtyper
  577. def can_inline_callable(greenkey):
  578. greenargs = unwrap_greenkey(greenkey)
  579. if can_never_inline(*greenargs):
  580. return False
  581. cell = JitCell.get_jitcell(*greenargs)
  582. if cell is not None and (cell.flags & JC_DONT_TRACE_HERE) != 0:
  583. return False
  584. return True
  585. self.can_inline_callable = can_inline_callable
  586. def dont_trace_here(greenkey):
  587. # Set greenkey as somewhere that tracing should not occur into;
  588. # notice that, as per the description of JC_DONT_TRACE_HERE earlier,
  589. # if greenkey hasn't been traced separately, setting
  590. # JC_DONT_TRACE_HERE will force tracing the next time the function
  591. # is encountered.
  592. cell = JitCell.ensure_jit_cell_at_key(greenkey)
  593. cell.flags |= JC_DONT_TRACE_HERE
  594. self.dont_trace_here = dont_trace_here
  595. if jd._should_unroll_one_iteration_ptr is None:
  596. def should_unroll_one_iteration(greenkey):
  597. return False
  598. else:
  599. inline_ptr = jd._should_unroll_one_iteration_ptr
  600. def should_unroll_one_iteration(greenkey):
  601. greenargs = unwrap_greenkey(greenkey)
  602. fn = support.maybe_on_top_of_llinterp(rtyper, inline_ptr)
  603. return fn(*greenargs)
  604. self.should_unroll_one_iteration = should_unroll_one_iteration
  605. redargtypes = ''.join([kind[0] for kind in jd.red_args_types])
  606. def get_assembler_token(greenkey):
  607. cell = JitCell.ensure_jit_cell_at_key(greenkey)
  608. procedure_token = cell.get_procedure_token()
  609. if procedure_token is None:
  610. from rpython.jit.metainterp.compile import compile_tmp_callback
  611. memmgr = warmrunnerdesc.memory_manager
  612. procedure_token = compile_tmp_callback(cpu, jd, greenkey,
  613. redargtypes, memmgr)
  614. cell.set_procedure_token(procedure_token, tmp=True)
  615. return procedure_token
  616. self.get_assembler_token = get_assembler_token
  617. #
  618. jitdriver = self.jitdriver_sd.jitdriver
  619. if self.jitdriver_sd.jitdriver:
  620. drivername = jitdriver.name
  621. else:
  622. drivername = '<unknown jitdriver>'
  623. # get_location returns
  624. get_location_ptr = getattr(self.jitdriver_sd, '_get_location_ptr', None)
  625. if get_location_ptr is not None:
  626. types = self.jitdriver_sd._get_loc_types
  627. unwrap_greenkey = self.make_unwrap_greenkey()
  628. unrolled_types = unrolling_iterable(enumerate(types))
  629. def get_location(greenkey):
  630. greenargs = unwrap_greenkey(greenkey)
  631. fn = support.maybe_on_top_of_llinterp(rtyper, get_location_ptr)
  632. value_tuple = fn(*greenargs)
  633. values = []
  634. for i, (sem_type,gen_type) in unrolled_types:
  635. if gen_type == "s":
  636. value = getattr(value_tuple, 'item' + str(i))
  637. values.append(jl.wrap(sem_type,gen_type,hlstr(value)))
  638. elif gen_type == "i":
  639. value = getattr(value_tuple, 'item' + str(i))
  640. values.append(jl.wrap(sem_type,gen_type,intmask(value)))
  641. else:
  642. raise NotImplementedError
  643. return values
  644. self.get_location_types = list(types)
  645. self.get_location = get_location
  646. else:
  647. self.get_location_types = None
  648. self.get_location = None
  649. #
  650. printable_loc_ptr = self.jitdriver_sd._get_printable_location_ptr
  651. if printable_loc_ptr is None:
  652. missing = '(%s: no get_printable_location)' % drivername
  653. def get_location_str(greenkey):
  654. return missing
  655. else:
  656. unwrap_greenkey = self.make_unwrap_greenkey()
  657. # the following missing text should not be seen, as it is
  658. # returned only if debug_prints are currently not enabled,
  659. # but it may show up anyway (consider it bugs)
  660. missing = ('(%s: get_printable_location '
  661. 'disabled, no debug_print)' % drivername)
  662. #
  663. def get_location_str(greenkey):
  664. if not have_debug_prints_for("jit-"):
  665. return missing
  666. greenargs = unwrap_greenkey(greenkey)
  667. fn = support.maybe_on_top_of_llinterp(rtyper, printable_loc_ptr)
  668. llres = fn(*greenargs)
  669. if not we_are_translated() and isinstance(llres, str):
  670. return llres
  671. return hlstr(llres)
  672. self.get_location_str = get_location_str
  673. #
  674. confirm_enter_jit_ptr = self.jitdriver_sd._confirm_enter_jit_ptr
  675. if confirm_enter_jit_ptr is None:
  676. def confirm_enter_jit(*args):
  677. return True
  678. else:
  679. #
  680. def confirm_enter_jit(*args):
  681. fn = support.maybe_on_top_of_llinterp(rtyper,
  682. confirm_enter_jit_ptr)
  683. return fn(*args)
  684. self.confirm_enter_jit = confirm_enter_jit
  685. #
  686. can_never_inline_ptr = self.jitdriver_sd._can_never_inline_ptr
  687. if can_never_inline_ptr is None:
  688. def can_never_inline(*greenargs):
  689. return False
  690. else:
  691. #
  692. def can_never_inline(*greenargs):
  693. fn = support.maybe_on_top_of_llinterp(rtyper,
  694. can_never_inline_ptr)
  695. return fn(*greenargs)
  696. self.can_never_inline = can_never_inline
  697. get_unique_id_ptr = self.jitdriver_sd._get_unique_id_ptr
  698. def get_unique_id(greenkey):
  699. greenargs = unwrap_greenkey(greenkey)
  700. fn = support.maybe_on_top_of_llinterp(rtyper, get_unique_id_ptr)
  701. return fn(*greenargs)
  702. self.get_unique_id = get_unique_id