/pypy/module/pypyjit/interp_resop.py

http://github.com/pypy/pypy · Python · 260 lines · 245 code · 8 blank · 7 comment · 5 complexity · dce41ff29bebb676f545ec055190e8a3 MD5 · raw file

  1. from pypy.interpreter.typedef import (TypeDef, GetSetProperty,
  2. interp_attrproperty, interp_attrproperty_w)
  3. from pypy.interpreter.baseobjspace import Wrappable
  4. from pypy.interpreter.gateway import unwrap_spec, interp2app, NoneNotWrapped
  5. from pypy.interpreter.pycode import PyCode
  6. from pypy.interpreter.error import OperationError
  7. from pypy.rpython.lltypesystem import lltype, llmemory
  8. from pypy.rpython.annlowlevel import cast_base_ptr_to_instance, hlstr
  9. from pypy.rpython.lltypesystem.rclass import OBJECT
  10. from pypy.jit.metainterp.resoperation import rop, AbstractResOp
  11. from pypy.rlib.nonconst import NonConstant
  12. from pypy.rlib import jit_hooks
  13. from pypy.module.pypyjit.interp_jit import pypyjitdriver
  14. class Cache(object):
  15. in_recursion = False
  16. def __init__(self, space):
  17. self.w_compile_hook = space.w_None
  18. self.w_abort_hook = space.w_None
  19. self.w_optimize_hook = space.w_None
  20. def wrap_greenkey(space, jitdriver, greenkey, greenkey_repr):
  21. if greenkey is None:
  22. return space.w_None
  23. jitdriver_name = jitdriver.name
  24. if jitdriver_name == 'pypyjit':
  25. next_instr = greenkey[0].getint()
  26. is_being_profiled = greenkey[1].getint()
  27. ll_code = lltype.cast_opaque_ptr(lltype.Ptr(OBJECT),
  28. greenkey[2].getref_base())
  29. pycode = cast_base_ptr_to_instance(PyCode, ll_code)
  30. return space.newtuple([space.wrap(pycode), space.wrap(next_instr),
  31. space.newbool(bool(is_being_profiled))])
  32. else:
  33. return space.wrap(greenkey_repr)
  34. def set_compile_hook(space, w_hook):
  35. """ set_compile_hook(hook)
  36. Set a compiling hook that will be called each time a loop is compiled.
  37. The hook will be called with the following signature:
  38. hook(jitdriver_name, loop_type, greenkey or guard_number, operations,
  39. assembler_addr, assembler_length)
  40. jitdriver_name is the name of this particular jitdriver, 'pypyjit' is
  41. the main interpreter loop
  42. loop_type can be either `loop` `entry_bridge` or `bridge`
  43. in case loop is not `bridge`, greenkey will be a tuple of constants
  44. or a string describing it.
  45. for the interpreter loop` it'll be a tuple
  46. (code, offset, is_being_profiled)
  47. assembler_addr is an integer describing where assembler starts,
  48. can be accessed via ctypes, assembler_lenght is the lenght of compiled
  49. asm
  50. Note that jit hook is not reentrant. It means that if the code
  51. inside the jit hook is itself jitted, it will get compiled, but the
  52. jit hook won't be called for that.
  53. """
  54. cache = space.fromcache(Cache)
  55. cache.w_compile_hook = w_hook
  56. cache.in_recursion = NonConstant(False)
  57. def set_optimize_hook(space, w_hook):
  58. """ set_optimize_hook(hook)
  59. Set a compiling hook that will be called each time a loop is optimized,
  60. but before assembler compilation. This allows to add additional
  61. optimizations on Python level.
  62. The hook will be called with the following signature:
  63. hook(jitdriver_name, loop_type, greenkey or guard_number, operations)
  64. jitdriver_name is the name of this particular jitdriver, 'pypyjit' is
  65. the main interpreter loop
  66. loop_type can be either `loop` `entry_bridge` or `bridge`
  67. in case loop is not `bridge`, greenkey will be a tuple of constants
  68. or a string describing it.
  69. for the interpreter loop` it'll be a tuple
  70. (code, offset, is_being_profiled)
  71. Note that jit hook is not reentrant. It means that if the code
  72. inside the jit hook is itself jitted, it will get compiled, but the
  73. jit hook won't be called for that.
  74. Result value will be the resulting list of operations, or None
  75. """
  76. cache = space.fromcache(Cache)
  77. cache.w_optimize_hook = w_hook
  78. cache.in_recursion = NonConstant(False)
  79. def set_abort_hook(space, w_hook):
  80. """ set_abort_hook(hook)
  81. Set a hook (callable) that will be called each time there is tracing
  82. aborted due to some reason.
  83. The hook will be called as in: hook(jitdriver_name, greenkey, reason)
  84. Where reason is the reason for abort, see documentation for set_compile_hook
  85. for descriptions of other arguments.
  86. """
  87. cache = space.fromcache(Cache)
  88. cache.w_abort_hook = w_hook
  89. cache.in_recursion = NonConstant(False)
  90. def wrap_oplist(space, logops, operations, ops_offset=None):
  91. l_w = []
  92. jitdrivers_sd = logops.metainterp_sd.jitdrivers_sd
  93. for op in operations:
  94. if ops_offset is None:
  95. ofs = -1
  96. else:
  97. ofs = ops_offset.get(op, 0)
  98. if op.opnum == rop.DEBUG_MERGE_POINT:
  99. jd_sd = jitdrivers_sd[op.getarg(0).getint()]
  100. greenkey = op.getarglist()[3:]
  101. repr = jd_sd.warmstate.get_location_str(greenkey)
  102. w_greenkey = wrap_greenkey(space, jd_sd.jitdriver, greenkey, repr)
  103. l_w.append(DebugMergePoint(space, jit_hooks._cast_to_gcref(op),
  104. logops.repr_of_resop(op),
  105. jd_sd.jitdriver.name,
  106. op.getarg(1).getint(),
  107. op.getarg(2).getint(),
  108. w_greenkey))
  109. else:
  110. l_w.append(WrappedOp(jit_hooks._cast_to_gcref(op), ofs,
  111. logops.repr_of_resop(op)))
  112. return l_w
  113. class WrappedBox(Wrappable):
  114. """ A class representing a single box
  115. """
  116. def __init__(self, llbox):
  117. self.llbox = llbox
  118. def descr_getint(self, space):
  119. return space.wrap(jit_hooks.box_getint(self.llbox))
  120. @unwrap_spec(no=int)
  121. def descr_new_box(space, w_tp, no):
  122. return WrappedBox(jit_hooks.boxint_new(no))
  123. WrappedBox.typedef = TypeDef(
  124. 'Box',
  125. __new__ = interp2app(descr_new_box),
  126. getint = interp2app(WrappedBox.descr_getint),
  127. )
  128. @unwrap_spec(num=int, offset=int, repr=str, res=WrappedBox)
  129. def descr_new_resop(space, w_tp, num, w_args, res, offset=-1,
  130. repr=''):
  131. args = [space.interp_w(WrappedBox, w_arg).llbox for w_arg in
  132. space.listview(w_args)]
  133. if res is None:
  134. llres = jit_hooks.emptyval()
  135. else:
  136. llres = res.llbox
  137. return WrappedOp(jit_hooks.resop_new(num, args, llres), offset, repr)
  138. @unwrap_spec(repr=str, jd_name=str, call_depth=int, call_id=int)
  139. def descr_new_dmp(space, w_tp, w_args, repr, jd_name, call_depth, call_id,
  140. w_greenkey):
  141. args = [space.interp_w(WrappedBox, w_arg).llbox for w_arg in
  142. space.listview(w_args)]
  143. num = rop.DEBUG_MERGE_POINT
  144. return DebugMergePoint(space,
  145. jit_hooks.resop_new(num, args, jit_hooks.emptyval()),
  146. repr, jd_name, call_depth, call_id, w_greenkey)
  147. class WrappedOp(Wrappable):
  148. """ A class representing a single ResOperation, wrapped nicely
  149. """
  150. def __init__(self, op, offset, repr_of_resop):
  151. self.op = op
  152. self.offset = offset
  153. self.repr_of_resop = repr_of_resop
  154. def descr_repr(self, space):
  155. return space.wrap(self.repr_of_resop)
  156. def descr_num(self, space):
  157. return space.wrap(jit_hooks.resop_getopnum(self.op))
  158. def descr_name(self, space):
  159. return space.wrap(hlstr(jit_hooks.resop_getopname(self.op)))
  160. @unwrap_spec(no=int)
  161. def descr_getarg(self, space, no):
  162. return WrappedBox(jit_hooks.resop_getarg(self.op, no))
  163. @unwrap_spec(no=int, box=WrappedBox)
  164. def descr_setarg(self, space, no, box):
  165. jit_hooks.resop_setarg(self.op, no, box.llbox)
  166. def descr_getresult(self, space):
  167. return WrappedBox(jit_hooks.resop_getresult(self.op))
  168. def descr_setresult(self, space, w_box):
  169. box = space.interp_w(WrappedBox, w_box)
  170. jit_hooks.resop_setresult(self.op, box.llbox)
  171. class DebugMergePoint(WrappedOp):
  172. def __init__(self, space, op, repr_of_resop, jd_name, call_depth, call_id,
  173. w_greenkey):
  174. WrappedOp.__init__(self, op, -1, repr_of_resop)
  175. self.jd_name = jd_name
  176. self.call_depth = call_depth
  177. self.call_id = call_id
  178. self.w_greenkey = w_greenkey
  179. def get_pycode(self, space):
  180. if self.jd_name == pypyjitdriver.name:
  181. return space.getitem(self.w_greenkey, space.wrap(0))
  182. raise OperationError(space.w_AttributeError, space.wrap("This DebugMergePoint doesn't belong to the main Python JitDriver"))
  183. def get_bytecode_no(self, space):
  184. if self.jd_name == pypyjitdriver.name:
  185. return space.getitem(self.w_greenkey, space.wrap(1))
  186. raise OperationError(space.w_AttributeError, space.wrap("This DebugMergePoint doesn't belong to the main Python JitDriver"))
  187. def get_jitdriver_name(self, space):
  188. return space.wrap(self.jd_name)
  189. WrappedOp.typedef = TypeDef(
  190. 'ResOperation',
  191. __doc__ = WrappedOp.__doc__,
  192. __new__ = interp2app(descr_new_resop),
  193. __repr__ = interp2app(WrappedOp.descr_repr),
  194. num = GetSetProperty(WrappedOp.descr_num),
  195. name = GetSetProperty(WrappedOp.descr_name),
  196. getarg = interp2app(WrappedOp.descr_getarg),
  197. setarg = interp2app(WrappedOp.descr_setarg),
  198. result = GetSetProperty(WrappedOp.descr_getresult,
  199. WrappedOp.descr_setresult)
  200. )
  201. WrappedOp.acceptable_as_base_class = False
  202. DebugMergePoint.typedef = TypeDef(
  203. 'DebugMergePoint', WrappedOp.typedef,
  204. __new__ = interp2app(descr_new_dmp),
  205. greenkey = interp_attrproperty_w("w_greenkey", cls=DebugMergePoint),
  206. pycode = GetSetProperty(DebugMergePoint.get_pycode),
  207. bytecode_no = GetSetProperty(DebugMergePoint.get_bytecode_no),
  208. call_depth = interp_attrproperty("call_depth", cls=DebugMergePoint),
  209. call_id = interp_attrproperty("call_id", cls=DebugMergePoint),
  210. jitdriver_name = GetSetProperty(DebugMergePoint.get_jitdriver_name),
  211. )
  212. DebugMergePoint.acceptable_as_base_class = False