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

/rpython/jit/metainterp/virtualref.py

https://bitbucket.org/pypy/pypy/
Python | 177 lines | 131 code | 15 blank | 31 comment | 23 complexity | 8e77d3029652e3cf401bada30a49bd36 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from rpython.rtyper.rmodel import inputconst, log
  2. from rpython.rtyper.lltypesystem import lltype, llmemory
  3. from rpython.rtyper import rclass
  4. from rpython.jit.metainterp import history
  5. from rpython.jit.metainterp.virtualizable import TOKEN_NONE
  6. from rpython.jit.metainterp.virtualizable import TOKEN_TRACING_RESCALL
  7. from rpython.jit.codewriter import heaptracker
  8. from rpython.rlib.jit import InvalidVirtualRef
  9. class VirtualRefInfo:
  10. def __init__(self, warmrunnerdesc):
  11. self.warmrunnerdesc = warmrunnerdesc
  12. self.cpu = warmrunnerdesc.cpu
  13. # we make the low-level type of an RPython class directly
  14. self.JIT_VIRTUAL_REF = lltype.GcStruct('JitVirtualRef',
  15. ('super', rclass.OBJECT),
  16. ('virtual_token', llmemory.GCREF),
  17. ('forced', rclass.OBJECTPTR))
  18. self.jit_virtual_ref_vtable = lltype.malloc(rclass.OBJECT_VTABLE,
  19. zero=True, flavor='raw',
  20. immortal=True)
  21. if hasattr(self.cpu, 'gc_ll_descr'):
  22. heaptracker.setup_cache_gcstruct2vtable(self.cpu.gc_ll_descr)
  23. self.cpu.gc_ll_descr._cache_gcstruct2vtable[self.JIT_VIRTUAL_REF] = self.jit_virtual_ref_vtable
  24. #
  25. # record the type JIT_VIRTUAL_REF explicitly in the rtyper, too
  26. if hasattr(self.warmrunnerdesc, 'rtyper'): # <-- for tests
  27. self.warmrunnerdesc.rtyper.set_type_for_typeptr(
  28. self.jit_virtual_ref_vtable, self.JIT_VIRTUAL_REF)
  29. self.descr = self.cpu.sizeof(self.JIT_VIRTUAL_REF,
  30. vtable=self.jit_virtual_ref_vtable)
  31. self.jit_virtual_ref_vtable.name = rclass.alloc_array_name(
  32. 'jit_virtual_ref')
  33. # build some constants
  34. adr = llmemory.cast_ptr_to_adr(self.jit_virtual_ref_vtable)
  35. adr = heaptracker.adr2int(adr)
  36. self.jit_virtual_ref_const_class = history.ConstInt(adr)
  37. fielddescrof = self.cpu.fielddescrof
  38. self.descr_virtual_token = fielddescrof(self.JIT_VIRTUAL_REF,
  39. 'virtual_token')
  40. self.descr_forced = fielddescrof(self.JIT_VIRTUAL_REF, 'forced')
  41. def _freeze_(self):
  42. return True
  43. def replace_force_virtual_with_call(self, graphs):
  44. # similar to rvirtualizable.replace_force_virtualizable_with_call().
  45. c_force_virtual_ptr = None
  46. c_is_virtual_ptr = None
  47. force_virtual_count = 0
  48. for graph in graphs:
  49. for block in graph.iterblocks():
  50. for op in block.operations:
  51. if op.opname == 'jit_force_virtual':
  52. # first compute c_funcptr, but only if there is any
  53. # 'jit_force_virtual' around
  54. if c_force_virtual_ptr is None:
  55. c_force_virtual_ptr = self.get_force_virtual_fnptr()
  56. #
  57. op.opname = 'direct_call'
  58. op.args = [c_force_virtual_ptr, op.args[0]]
  59. force_virtual_count += 1
  60. #
  61. if op.opname == 'jit_is_virtual':
  62. if c_is_virtual_ptr is None:
  63. c_is_virtual_ptr = self.get_is_virtual_fnptr()
  64. #
  65. op.opname = 'direct_call'
  66. op.args = [c_is_virtual_ptr, op.args[0]]
  67. #
  68. if c_force_virtual_ptr is not None:
  69. log("replaced %d 'jit_force_virtual' with %r" % (force_virtual_count,
  70. c_force_virtual_ptr.value))
  71. # ____________________________________________________________
  72. # The 'virtual_token' field has the same meaning as the 'vable_token' field
  73. # of a virtualizable. It is equal to:
  74. # * TOKEN_NONE when tracing, except as described below;
  75. # * TOKEN_TRACING_RESCALL during tracing when we do a residual call;
  76. # * the JITFRAME (set by FORCE_TOKEN) when running the assembler;
  77. # * TOKEN_NONE after the virtual is forced, if it is forced at all.
  78. def virtual_ref_during_tracing(self, real_object):
  79. assert real_object
  80. vref = lltype.malloc(self.JIT_VIRTUAL_REF)
  81. p = lltype.cast_pointer(rclass.OBJECTPTR, vref)
  82. p.typeptr = self.jit_virtual_ref_vtable
  83. vref.virtual_token = TOKEN_NONE
  84. vref.forced = lltype.cast_opaque_ptr(rclass.OBJECTPTR, real_object)
  85. return lltype.cast_opaque_ptr(llmemory.GCREF, vref)
  86. def is_virtual_ref(self, gcref):
  87. if not gcref:
  88. return False
  89. inst = lltype.cast_opaque_ptr(rclass.OBJECTPTR, gcref)
  90. return inst.typeptr == self.jit_virtual_ref_vtable
  91. def tracing_before_residual_call(self, gcref):
  92. if not self.is_virtual_ref(gcref):
  93. return
  94. vref = lltype.cast_opaque_ptr(lltype.Ptr(self.JIT_VIRTUAL_REF), gcref)
  95. assert vref.virtual_token == TOKEN_NONE
  96. vref.virtual_token = TOKEN_TRACING_RESCALL
  97. def tracing_after_residual_call(self, gcref):
  98. if not self.is_virtual_ref(gcref):
  99. return False
  100. vref = lltype.cast_opaque_ptr(lltype.Ptr(self.JIT_VIRTUAL_REF), gcref)
  101. assert vref.forced
  102. if vref.virtual_token != TOKEN_NONE:
  103. # not modified by the residual call; assert that it is still
  104. # set to TOKEN_TRACING_RESCALL and clear it.
  105. assert vref.virtual_token == TOKEN_TRACING_RESCALL
  106. vref.virtual_token = TOKEN_NONE
  107. return False
  108. else:
  109. # marker "modified during residual call" set.
  110. return True
  111. def continue_tracing(self, gcref, real_object):
  112. if not self.is_virtual_ref(gcref):
  113. return
  114. assert real_object
  115. vref = lltype.cast_opaque_ptr(lltype.Ptr(self.JIT_VIRTUAL_REF), gcref)
  116. assert vref.virtual_token != TOKEN_TRACING_RESCALL
  117. vref.virtual_token = TOKEN_NONE
  118. vref.forced = lltype.cast_opaque_ptr(rclass.OBJECTPTR, real_object)
  119. # ____________________________________________________________
  120. def get_force_virtual_fnptr(self):
  121. #
  122. def force_virtual_if_necessary(inst):
  123. if not inst or inst.typeptr != self.jit_virtual_ref_vtable:
  124. return inst # common, fast case
  125. return self.force_virtual(inst)
  126. #
  127. FUNC = lltype.FuncType([rclass.OBJECTPTR], rclass.OBJECTPTR)
  128. funcptr = self.warmrunnerdesc.helper_func(
  129. lltype.Ptr(FUNC),
  130. force_virtual_if_necessary)
  131. return inputconst(lltype.typeOf(funcptr), funcptr)
  132. def get_is_virtual_fnptr(self):
  133. #
  134. def is_virtual(inst):
  135. if not inst:
  136. return False
  137. return inst.typeptr == self.jit_virtual_ref_vtable
  138. #
  139. FUNC = lltype.FuncType([rclass.OBJECTPTR], lltype.Bool)
  140. funcptr = self.warmrunnerdesc.helper_func(lltype.Ptr(FUNC), is_virtual)
  141. return inputconst(lltype.typeOf(funcptr), funcptr)
  142. def force_virtual(self, inst):
  143. vref = lltype.cast_pointer(lltype.Ptr(self.JIT_VIRTUAL_REF), inst)
  144. token = vref.virtual_token
  145. if token != TOKEN_NONE:
  146. if token == TOKEN_TRACING_RESCALL:
  147. # The "virtual" is not a virtual at all during tracing.
  148. # We only need to reset virtual_token to TOKEN_NONE
  149. # as a marker for the tracing, to tell it that this
  150. # "virtual" escapes.
  151. assert vref.forced
  152. vref.virtual_token = TOKEN_NONE
  153. else:
  154. assert not vref.forced
  155. from rpython.jit.metainterp.compile import ResumeGuardForcedDescr
  156. ResumeGuardForcedDescr.force_now(self.cpu, token)
  157. assert vref.virtual_token == TOKEN_NONE
  158. assert vref.forced
  159. elif not vref.forced:
  160. # token == TOKEN_NONE and the vref was not forced: it's invalid
  161. raise InvalidVirtualRef
  162. return vref.forced