PageRenderTime 56ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/jit/metainterp/virtualizable.py

https://bitbucket.org/pypy/pypy/
Python | 345 lines | 271 code | 32 blank | 42 comment | 46 complexity | f76dbec336a37f0b2bacbac63875f8a3 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from rpython.jit.codewriter.effectinfo import EffectInfo
  2. from rpython.jit.metainterp import history
  3. from rpython.jit.metainterp.typesystem import deref, fieldType, arrayItem
  4. from rpython.jit.metainterp.warmstate import wrap, unwrap
  5. from rpython.jit.metainterp.resumecode import numb_next_item
  6. from rpython.rlib.unroll import unrolling_iterable
  7. from rpython.rtyper import rvirtualizable
  8. from rpython.rtyper.lltypesystem import lltype, llmemory
  9. from rpython.rtyper.rclass import IR_IMMUTABLE_ARRAY, IR_IMMUTABLE
  10. class VirtualizableInfo(object):
  11. def __init__(self, warmrunnerdesc, VTYPEPTR):
  12. self.warmrunnerdesc = warmrunnerdesc
  13. cpu = warmrunnerdesc.cpu
  14. self.cpu = cpu
  15. #
  16. VTYPEPTR1 = VTYPEPTR
  17. while 'virtualizable_accessor' not in deref(VTYPEPTR)._hints:
  18. VTYPEPTR = cpu.ts.get_superclass(VTYPEPTR)
  19. assert VTYPEPTR is not None, (
  20. "%r is listed in the jit driver's 'virtualizables', "
  21. "but that class doesn't have a '_virtualizable_' attribute "
  22. "(if it has _virtualizable2_, rename it to _virtualizable_)"
  23. % (VTYPEPTR1,))
  24. self.VTYPEPTR = VTYPEPTR
  25. self.VTYPE = VTYPE = deref(VTYPEPTR)
  26. self.vable_token_descr = cpu.fielddescrof(VTYPE, 'vable_token')
  27. #
  28. accessor = VTYPE._hints['virtualizable_accessor']
  29. all_fields = accessor.fields
  30. static_fields = []
  31. array_fields = []
  32. for name, tp in all_fields.iteritems():
  33. if tp == IR_IMMUTABLE_ARRAY:
  34. array_fields.append(name)
  35. elif tp == IR_IMMUTABLE:
  36. static_fields.append(name)
  37. else:
  38. raise Exception("unknown type: %s" % tp)
  39. self.static_fields = static_fields
  40. self.array_fields = array_fields
  41. #
  42. FIELDTYPES = [fieldType(VTYPE, name) for name in static_fields]
  43. ARRAYITEMTYPES = []
  44. for name in array_fields:
  45. ARRAYPTR = fieldType(VTYPE, name)
  46. ARRAY = deref(ARRAYPTR)
  47. assert isinstance(ARRAYPTR, lltype.Ptr)
  48. if not isinstance(ARRAY, lltype.GcArray):
  49. raise Exception(
  50. "The virtualizable field '%s' is not an array (found %r)."
  51. " It usually means that you must try harder to ensure that"
  52. " the list is not resized at run-time. You can do that by"
  53. " using rpython.rlib.debug.make_sure_not_resized()." %
  54. (name, ARRAY))
  55. ARRAYITEMTYPES.append(arrayItem(ARRAY))
  56. self.array_descrs = [cpu.arraydescrof(deref(fieldType(VTYPE, name)))
  57. for name in array_fields]
  58. #
  59. self.num_static_extra_boxes = len(static_fields)
  60. self.num_arrays = len(array_fields)
  61. self.static_field_to_extra_box = dict(
  62. [(name, i) for (i, name) in enumerate(static_fields)])
  63. self.array_field_counter = dict(
  64. [(name, i) for (i, name) in enumerate(array_fields)])
  65. self.static_extra_types = [history.getkind(TYPE)
  66. for TYPE in FIELDTYPES]
  67. self.arrayitem_extra_types = [history.getkind(ITEM)
  68. for ITEM in ARRAYITEMTYPES]
  69. self.static_field_descrs = [cpu.fielddescrof(VTYPE, name)
  70. for name in static_fields]
  71. self.array_field_descrs = [cpu.fielddescrof(VTYPE, name)
  72. for name in array_fields]
  73. for descr in self.static_field_descrs:
  74. descr.vinfo = self
  75. for descr in self.array_field_descrs:
  76. descr.vinfo = self
  77. self.static_field_by_descrs = dict(
  78. [(descr, i) for (i, descr) in enumerate(self.static_field_descrs)])
  79. self.array_field_by_descrs = dict(
  80. [(descr, i) for (i, descr) in enumerate(self.array_field_descrs)])
  81. #
  82. getlength = cpu.ts.getlength
  83. getarrayitem = cpu.ts.getarrayitem
  84. setarrayitem = cpu.ts.setarrayitem
  85. def read_boxes(cpu, virtualizable):
  86. assert lltype.typeOf(virtualizable) == llmemory.GCREF
  87. virtualizable = cast_gcref_to_vtype(virtualizable)
  88. boxes = []
  89. for _, fieldname in unroll_static_fields:
  90. x = getattr(virtualizable, fieldname)
  91. boxes.append(wrap(cpu, x))
  92. for _, fieldname in unroll_array_fields:
  93. lst = getattr(virtualizable, fieldname)
  94. for i in range(getlength(lst)):
  95. boxes.append(wrap(cpu, getarrayitem(lst, i)))
  96. return boxes
  97. def write_boxes(virtualizable, boxes):
  98. virtualizable = cast_gcref_to_vtype(virtualizable)
  99. i = 0
  100. for FIELDTYPE, fieldname in unroll_static_fields:
  101. x = unwrap(FIELDTYPE, boxes[i])
  102. setattr(virtualizable, fieldname, x)
  103. i = i + 1
  104. for ARRAYITEMTYPE, fieldname in unroll_array_fields:
  105. lst = getattr(virtualizable, fieldname)
  106. for j in range(getlength(lst)):
  107. x = unwrap(ARRAYITEMTYPE, boxes[i])
  108. setarrayitem(lst, j, x)
  109. i = i + 1
  110. assert len(boxes) == i + 1
  111. def get_total_size(virtualizable):
  112. virtualizable = cast_gcref_to_vtype(virtualizable)
  113. size = 0
  114. for _, fieldname in unroll_array_fields:
  115. lst = getattr(virtualizable, fieldname)
  116. size += getlength(lst)
  117. for _, fieldname in unroll_static_fields:
  118. size += 1
  119. return size
  120. def write_from_resume_data_partial(virtualizable, reader, index, numb):
  121. virtualizable = cast_gcref_to_vtype(virtualizable)
  122. # Load values from the reader (see resume.py) described by
  123. # the list of numbers 'nums', and write them in their proper
  124. # place in the 'virtualizable'.
  125. for FIELDTYPE, fieldname in unroll_static_fields:
  126. item, index = numb_next_item(numb, index)
  127. x = reader.load_value_of_type(FIELDTYPE, item)
  128. setattr(virtualizable, fieldname, x)
  129. for ARRAYITEMTYPE, fieldname in unroll_array_fields:
  130. lst = getattr(virtualizable, fieldname)
  131. for j in range(getlength(lst)):
  132. item, index = numb_next_item(numb, index)
  133. x = reader.load_value_of_type(ARRAYITEMTYPE, item)
  134. setarrayitem(lst, j, x)
  135. return index
  136. def load_list_of_boxes(virtualizable, reader, vable_box, numb, index):
  137. virtualizable = cast_gcref_to_vtype(virtualizable)
  138. # Uses 'virtualizable' only to know the length of the arrays;
  139. # does not write anything into it. The returned list is in
  140. # the format expected of virtualizable_boxes, so it ends in
  141. # the virtualizable itself.
  142. boxes = []
  143. for FIELDTYPE, fieldname in unroll_static_fields:
  144. item, index = numb_next_item(numb, index)
  145. box = reader.decode_box_of_type(FIELDTYPE, item)
  146. boxes.append(box)
  147. for ARRAYITEMTYPE, fieldname in unroll_array_fields:
  148. lst = getattr(virtualizable, fieldname)
  149. for j in range(getlength(lst)):
  150. item, index = numb_next_item(numb, index)
  151. box = reader.decode_box_of_type(ARRAYITEMTYPE, item)
  152. boxes.append(box)
  153. boxes.append(vable_box)
  154. return boxes, index
  155. def check_boxes(virtualizable, boxes):
  156. virtualizable = cast_gcref_to_vtype(virtualizable)
  157. # for debugging
  158. i = 0
  159. for FIELDTYPE, fieldname in unroll_static_fields:
  160. x = unwrap(FIELDTYPE, boxes[i])
  161. assert getattr(virtualizable, fieldname) == x
  162. i = i + 1
  163. for ARRAYITEMTYPE, fieldname in unroll_array_fields:
  164. lst = getattr(virtualizable, fieldname)
  165. for j in range(getlength(lst)):
  166. x = unwrap(ARRAYITEMTYPE, boxes[i])
  167. assert getarrayitem(lst, j) == x
  168. i = i + 1
  169. assert len(boxes) == i + 1
  170. def get_index_in_array(virtualizable, arrayindex, index):
  171. virtualizable = cast_gcref_to_vtype(virtualizable)
  172. index += self.num_static_extra_boxes
  173. j = 0
  174. for _, fieldname in unroll_array_fields:
  175. if arrayindex == j:
  176. return index
  177. lst = getattr(virtualizable, fieldname)
  178. index += getlength(lst)
  179. j = j + 1
  180. assert False, "invalid arrayindex"
  181. def get_array_length(virtualizable, arrayindex):
  182. virtualizable = cast_gcref_to_vtype(virtualizable)
  183. j = 0
  184. for _, fieldname in unroll_array_fields:
  185. if arrayindex == j:
  186. lst = getattr(virtualizable, fieldname)
  187. return getlength(lst)
  188. j += 1
  189. assert False, "invalid arrayindex"
  190. unroll_static_fields = unrolling_iterable(zip(FIELDTYPES,
  191. static_fields))
  192. unroll_array_fields = unrolling_iterable(zip(ARRAYITEMTYPES,
  193. array_fields))
  194. unroll_static_fields_rev = unrolling_iterable(
  195. reversed(list(unroll_static_fields)))
  196. unroll_array_fields_rev = unrolling_iterable(
  197. reversed(list(unroll_array_fields)))
  198. self.read_boxes = read_boxes
  199. self.write_boxes = write_boxes
  200. self.write_from_resume_data_partial = write_from_resume_data_partial
  201. self.load_list_of_boxes = load_list_of_boxes
  202. self.check_boxes = check_boxes
  203. self.get_index_in_array = get_index_in_array
  204. self.get_array_length = get_array_length
  205. self.get_total_size = get_total_size
  206. def cast_to_vtype(virtualizable):
  207. return self.cpu.ts.cast_to_instance_maybe(VTYPEPTR, virtualizable)
  208. self.cast_to_vtype = cast_to_vtype
  209. def cast_gcref_to_vtype(virtualizable):
  210. assert lltype.typeOf(virtualizable) == llmemory.GCREF
  211. return lltype.cast_opaque_ptr(VTYPEPTR, virtualizable)
  212. self.cast_gcref_to_vtype = cast_gcref_to_vtype
  213. def clear_vable_token(virtualizable):
  214. virtualizable = cast_gcref_to_vtype(virtualizable)
  215. if virtualizable.vable_token:
  216. force_now(virtualizable)
  217. assert not virtualizable.vable_token
  218. self.clear_vable_token = clear_vable_token
  219. def tracing_before_residual_call(virtualizable):
  220. virtualizable = cast_gcref_to_vtype(virtualizable)
  221. assert not virtualizable.vable_token
  222. virtualizable.vable_token = TOKEN_TRACING_RESCALL
  223. self.tracing_before_residual_call = tracing_before_residual_call
  224. def tracing_after_residual_call(virtualizable):
  225. """
  226. Returns whether or not the virtualizable was forced during a
  227. CALL_MAY_FORCE.
  228. """
  229. virtualizable = cast_gcref_to_vtype(virtualizable)
  230. if virtualizable.vable_token:
  231. # not modified by the residual call; assert that it is still
  232. # set to TOKEN_TRACING_RESCALL and clear it.
  233. assert virtualizable.vable_token == TOKEN_TRACING_RESCALL
  234. virtualizable.vable_token = TOKEN_NONE
  235. return False
  236. else:
  237. # marker "modified during residual call" set.
  238. return True
  239. self.tracing_after_residual_call = tracing_after_residual_call
  240. def force_now(virtualizable):
  241. token = virtualizable.vable_token
  242. if token == TOKEN_TRACING_RESCALL:
  243. # The values in the virtualizable are always correct during
  244. # tracing. We only need to reset vable_token to TOKEN_NONE
  245. # as a marker for the tracing, to tell it that this
  246. # virtualizable escapes.
  247. virtualizable.vable_token = TOKEN_NONE
  248. else:
  249. from rpython.jit.metainterp.compile import ResumeGuardForcedDescr
  250. ResumeGuardForcedDescr.force_now(cpu, token)
  251. assert virtualizable.vable_token == TOKEN_NONE
  252. force_now._dont_inline_ = True
  253. self.force_now = force_now
  254. def is_token_nonnull_gcref(virtualizable):
  255. virtualizable = cast_gcref_to_vtype(virtualizable)
  256. return bool(virtualizable.vable_token)
  257. self.is_token_nonnull_gcref = is_token_nonnull_gcref
  258. def reset_token_gcref(virtualizable):
  259. virtualizable = cast_gcref_to_vtype(virtualizable)
  260. virtualizable.vable_token = TOKEN_NONE
  261. self.reset_token_gcref = reset_token_gcref
  262. def reset_vable_token(virtualizable):
  263. virtualizable.vable_token = TOKEN_NONE
  264. self.reset_vable_token = reset_vable_token
  265. def _freeze_(self):
  266. return True
  267. def finish(self):
  268. #
  269. def force_virtualizable_if_necessary(virtualizable):
  270. if virtualizable.vable_token:
  271. self.force_now(virtualizable)
  272. force_virtualizable_if_necessary._always_inline_ = True
  273. #
  274. all_graphs = self.warmrunnerdesc.translator.graphs
  275. ts = self.warmrunnerdesc.cpu.ts
  276. (_, FUNCPTR) = ts.get_FuncType([self.VTYPEPTR], lltype.Void)
  277. funcptr = self.warmrunnerdesc.helper_func(
  278. FUNCPTR, force_virtualizable_if_necessary)
  279. rvirtualizable.replace_force_virtualizable_with_call(
  280. all_graphs, self.VTYPEPTR, funcptr)
  281. (_, FUNCPTR) = ts.get_FuncType([llmemory.GCREF], lltype.Void)
  282. self.clear_vable_ptr = self.warmrunnerdesc.helper_func(
  283. FUNCPTR, self.clear_vable_token)
  284. FUNC = FUNCPTR.TO
  285. ei = EffectInfo([], [], [], [], [], [], EffectInfo.EF_CANNOT_RAISE,
  286. can_invalidate=False,
  287. oopspecindex=EffectInfo.OS_JIT_FORCE_VIRTUALIZABLE)
  288. self.clear_vable_descr = self.cpu.calldescrof(FUNC, FUNC.ARGS,
  289. FUNC.RESULT, ei)
  290. def unwrap_virtualizable_box(self, virtualizable_box):
  291. return virtualizable_box.getref(llmemory.GCREF)
  292. def is_vtypeptr(self, TYPE):
  293. return TYPE == self.VTYPEPTR
  294. # ____________________________________________________________
  295. #
  296. # The 'vable_token' field of a virtualizable is either NULL, points
  297. # to the JITFRAME object for the current assembler frame, or is
  298. # the special value TOKEN_TRACING_RESCALL. It is:
  299. #
  300. # 1. NULL (TOKEN_NONE) if not in the JIT at all, except as described below.
  301. #
  302. # 2. NULL when tracing is in progress; except:
  303. #
  304. # 3. equal to TOKEN_TRACING_RESCALL during tracing when we do a
  305. # residual call, calling random unknown other parts of the interpreter;
  306. # it is reset to NULL as soon as something occurs to the virtualizable.
  307. #
  308. # 4. when running the machine code with a virtualizable, it is set
  309. # to the JITFRAME, as obtained with the FORCE_TOKEN operation.
  310. _DUMMY = lltype.GcStruct('JITFRAME_DUMMY')
  311. _dummy = lltype.malloc(_DUMMY)
  312. TOKEN_NONE = lltype.nullptr(llmemory.GCREF.TO)
  313. TOKEN_TRACING_RESCALL = lltype.cast_opaque_ptr(llmemory.GCREF, _dummy)