PageRenderTime 89ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/rpython/jit/backend/test/runner_test.py

https://bitbucket.org/pypy/pypy/
Python | 5311 lines | 5281 code | 25 blank | 5 comment | 40 complexity | be4bdc666e6f3b8a49057bca93d098c0 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import py, sys, random, os, struct, operator
  2. from rpython.jit.metainterp.history import (AbstractFailDescr,
  3. AbstractDescr,
  4. BasicFailDescr,
  5. BasicFinalDescr,
  6. JitCellToken, TargetToken,
  7. ConstInt, ConstPtr,
  8. ConstFloat, Const)
  9. from rpython.jit.metainterp.resoperation import ResOperation, rop, InputArgInt,\
  10. InputArgFloat, opname, InputArgRef
  11. from rpython.jit.metainterp.typesystem import deref
  12. from rpython.jit.metainterp.executor import wrap_constant
  13. from rpython.jit.codewriter.effectinfo import EffectInfo
  14. from rpython.jit.tool.oparser import parse
  15. from rpython.rtyper.lltypesystem import lltype, llmemory, rstr, rffi
  16. from rpython.rtyper import rclass
  17. from rpython.rtyper.annlowlevel import llhelper
  18. from rpython.rtyper.llinterp import LLException
  19. from rpython.jit.codewriter import heaptracker, longlong
  20. from rpython.rlib import longlong2float
  21. from rpython.rlib.rarithmetic import intmask, is_valid_int
  22. from rpython.jit.backend.detect_cpu import autodetect
  23. from rpython.jit.backend.llsupport import jitframe
  24. from rpython.jit.backend.llsupport.llmodel import AbstractLLCPU
  25. from rpython.jit.backend.llsupport.llmodel import MissingLatestDescrError
  26. from rpython.jit.backend.llsupport.rewrite import GcRewriterAssembler
  27. IS_32_BIT = sys.maxint < 2**32
  28. IS_64_BIT = sys.maxint > 2**32
  29. boxfloat = InputArgFloat.fromfloat
  30. constfloat = ConstFloat.fromfloat
  31. def clone(op):
  32. if op.type == 'i':
  33. return InputArgInt(op.getint())
  34. elif op.type == 'r':
  35. return InputArgRef(op.getref_base())
  36. return InputArgFloat(op.getfloatstorage())
  37. def boxlonglong(ll):
  38. if longlong.is_64_bit:
  39. return InputArgInt(ll)
  40. else:
  41. return InputArgFloat(ll)
  42. STUFF = lltype.GcStruct('STUFF')
  43. random_gcref = lltype.cast_opaque_ptr(llmemory.GCREF,
  44. lltype.malloc(STUFF, immortal=True))
  45. class Runner(object):
  46. add_loop_instructions = ['overload for a specific cpu']
  47. bridge_loop_instructions = ['overload for a specific cpu']
  48. def execute_operation(self, opname, valueboxes, result_type, descr=None):
  49. inputargs, operations = self._get_single_operation_list(opname,
  50. result_type,
  51. valueboxes,
  52. descr)
  53. return self.execute_operations(inputargs, operations, result_type)
  54. def execute_operations(self, inputargs, operations, result_type):
  55. looptoken = JitCellToken()
  56. self.cpu.compile_loop(inputargs, operations, looptoken)
  57. args = []
  58. for box in inputargs:
  59. if box.type == 'i':
  60. args.append(box.getint())
  61. elif box.type == 'r':
  62. args.append(box.getref_base())
  63. elif box.type == 'f':
  64. args.append(box.getfloatstorage())
  65. else:
  66. raise NotImplementedError(box)
  67. deadframe = self.cpu.execute_token(looptoken, *args)
  68. if self.cpu.get_latest_descr(deadframe) is operations[-1].getdescr():
  69. self.guard_failed = False
  70. else:
  71. self.guard_failed = True
  72. if result_type == 'int':
  73. return self.cpu.get_int_value(deadframe, 0)
  74. elif result_type == 'ref':
  75. return self.cpu.get_ref_value(deadframe, 0)
  76. elif result_type == 'float':
  77. return self.cpu.get_float_value(deadframe, 0)
  78. elif result_type == 'void':
  79. return None
  80. else:
  81. assert False
  82. def _get_operation_list(self, operations, result_type):
  83. inputargs = []
  84. blacklist = set()
  85. for op in operations:
  86. for arg in op.getarglist():
  87. if not isinstance(arg, Const) and arg not in inputargs and \
  88. arg not in blacklist:
  89. inputargs.append(arg)
  90. if op.type != 'v':
  91. blacklist.add(op)
  92. if result_type == 'void':
  93. op1 = ResOperation(rop.FINISH, [], descr=BasicFinalDescr(0))
  94. else:
  95. op1 = ResOperation(rop.FINISH, [operations[-1]], descr=BasicFinalDescr(0))
  96. operations.append(op1)
  97. return inputargs, operations
  98. def _get_single_operation_list(self, opnum, result_type, valueboxes,
  99. descr):
  100. op0 = ResOperation(opnum, valueboxes)
  101. if result_type == 'void':
  102. op1 = ResOperation(rop.FINISH, [], descr=BasicFinalDescr(0))
  103. else:
  104. op1 = ResOperation(rop.FINISH, [op0], descr=BasicFinalDescr(0))
  105. operations = [op0, op1]
  106. if operations[0].is_guard():
  107. operations[0].setfailargs([])
  108. if not descr:
  109. descr = BasicFailDescr(1)
  110. if descr is not None:
  111. operations[0].setdescr(descr)
  112. inputargs = []
  113. for box in valueboxes:
  114. if not isinstance(box, Const) and box not in inputargs:
  115. inputargs.append(box)
  116. return inputargs, operations
  117. class BaseBackendTest(Runner):
  118. avoid_instances = False
  119. def setup_method(self, _):
  120. self.cpu = self.get_cpu()
  121. self.cpu.done_with_this_frame_descr_int = None
  122. self.cpu.done_with_this_frame_descr_ref = None
  123. self.cpu.done_with_this_frame_descr_float = None
  124. self.cpu.done_with_this_frame_descr_void = None
  125. def test_compile_linear_loop(self):
  126. loop = parse("""
  127. [i0]
  128. i1 = int_add(i0, 1)
  129. finish(i1, descr=faildescr)
  130. """, namespace={"faildescr": BasicFinalDescr(1)})
  131. looptoken = JitCellToken()
  132. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  133. deadframe = self.cpu.execute_token(looptoken, 2)
  134. fail = self.cpu.get_latest_descr(deadframe)
  135. res = self.cpu.get_int_value(deadframe, 0)
  136. assert res == 3
  137. assert fail.identifier == 1
  138. def test_compile_linear_float_loop(self):
  139. if not self.cpu.supports_floats:
  140. py.test.skip("requires floats")
  141. loop = parse("""
  142. [f0]
  143. f1 = float_add(f0, 2.3)
  144. finish(f1, descr=fdescr)
  145. """, namespace={'fdescr': BasicFinalDescr(1)})
  146. looptoken = JitCellToken()
  147. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  148. deadframe = self.cpu.execute_token(looptoken,
  149. longlong.getfloatstorage(2.8))
  150. fail = self.cpu.get_latest_descr(deadframe)
  151. res = self.cpu.get_float_value(deadframe, 0)
  152. assert longlong.getrealfloat(res) == 5.1
  153. fail = self.cpu.get_latest_descr(deadframe)
  154. assert fail.identifier == 1
  155. def test_compile_loop(self):
  156. looptoken = JitCellToken()
  157. targettoken = TargetToken()
  158. loop = parse("""
  159. [i0]
  160. label(i0, descr=targettoken)
  161. i1 = int_add(i0, 1)
  162. i2 = int_le(i1, 9)
  163. guard_true(i2, descr=fdescr) [i1]
  164. jump(i1, descr=targettoken)
  165. """, namespace={'targettoken': targettoken,
  166. 'fdescr': BasicFailDescr(2)})
  167. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  168. deadframe = self.cpu.execute_token(looptoken, 2)
  169. fail = self.cpu.get_latest_descr(deadframe)
  170. assert fail.identifier == 2
  171. res = self.cpu.get_int_value(deadframe, 0)
  172. assert res == 10
  173. def test_compile_with_holes_in_fail_args(self):
  174. targettoken = TargetToken()
  175. loop = parse("""
  176. [i3]
  177. i0 = int_sub(i3, 42)
  178. label(i0, descr=targettoken)
  179. i1 = int_add(i0, 1)
  180. i2 = int_le(i1, 9)
  181. guard_true(i2, descr=fdescr) []
  182. jump(i1, descr=targettoken)
  183. """, namespace={'targettoken': targettoken,
  184. 'fdescr': BasicFailDescr(2)})
  185. looptoken = JitCellToken()
  186. loop.operations[4].setfailargs([None, None, loop.operations[2], None])
  187. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  188. deadframe = self.cpu.execute_token(looptoken, 44)
  189. fail = self.cpu.get_latest_descr(deadframe)
  190. assert fail.identifier == 2
  191. res = self.cpu.get_int_value(deadframe, 2)
  192. assert res == 10
  193. def test_backends_dont_keep_loops_alive(self):
  194. import weakref, gc
  195. self.cpu.dont_keepalive_stuff = True
  196. targettoken = TargetToken()
  197. loop = parse("""
  198. [i0]
  199. label(i0, descr=targettoken)
  200. i1 = int_add(i0, 1)
  201. i2 = int_le(i1, 9)
  202. guard_true(i2, descr=fdescr) [i1]
  203. jump(i1, descr=targettoken)
  204. """, namespace={'targettoken': targettoken, 'fdescr': BasicFailDescr()})
  205. looptoken = JitCellToken()
  206. wr_i1 = weakref.ref(loop.operations[1])
  207. wr_guard = weakref.ref(loop.operations[3])
  208. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  209. if hasattr(looptoken, '_x86_ops_offset'):
  210. del looptoken._x86_ops_offset # else it's kept alive
  211. if hasattr(looptoken, '_ppc_ops_offset'):
  212. del looptoken._ppc_ops_offset # else it's kept alive
  213. if hasattr(looptoken, '_zarch_ops_offset'):
  214. del looptoken._zarch_ops_offset # else it's kept alive
  215. del loop
  216. gc.collect()
  217. assert not wr_i1() and not wr_guard()
  218. def test_compile_bridge(self):
  219. self.cpu.tracker.total_compiled_loops = 0
  220. self.cpu.tracker.total_compiled_bridges = 0
  221. targettoken = TargetToken()
  222. faildescr1 = BasicFailDescr(1)
  223. faildescr2 = BasicFailDescr(2)
  224. loop = parse("""
  225. [i0]
  226. label(i0, descr=targettoken)
  227. i1 = int_add(i0, 1)
  228. i2 = int_le(i1, 9)
  229. guard_true(i2, descr=faildescr1) [i1]
  230. jump(i1, descr=targettoken)
  231. """, namespace={'targettoken': targettoken,
  232. 'faildescr1': faildescr1})
  233. looptoken = JitCellToken()
  234. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  235. bridge = parse("""
  236. [i1]
  237. i3 = int_le(i1, 19)
  238. guard_true(i3, descr=faildescr2) [i1]
  239. jump(i1, descr=targettoken)
  240. """, namespace={"targettoken": targettoken,
  241. 'faildescr2': faildescr2})
  242. self.cpu.compile_bridge(faildescr1, bridge.inputargs,
  243. bridge.operations, looptoken)
  244. deadframe = self.cpu.execute_token(looptoken, 2)
  245. fail = self.cpu.get_latest_descr(deadframe)
  246. assert fail.identifier == 2
  247. res = self.cpu.get_int_value(deadframe, 0)
  248. assert res == 20
  249. assert self.cpu.tracker.total_compiled_loops == 1
  250. assert self.cpu.tracker.total_compiled_bridges == 1
  251. return looptoken
  252. def test_compile_bridge_with_holes(self):
  253. faildescr1 = BasicFailDescr(1)
  254. faildescr2 = BasicFailDescr(2)
  255. looptoken = JitCellToken()
  256. targettoken = TargetToken()
  257. loop = parse("""
  258. [i3]
  259. i0 = int_sub(i3, 42)
  260. label(i0, descr=targettoken)
  261. i1 = int_add(i0, 1)
  262. i2 = int_le(i1, 9)
  263. guard_true(i2, descr=faildescr1) []
  264. jump(i1, descr=targettoken)
  265. """, namespace={'targettoken': targettoken,
  266. 'faildescr1': faildescr1})
  267. loop.operations[-2].setfailargs([None, loop.operations[2], None])
  268. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  269. bridge = parse("""
  270. [i1]
  271. i3 = int_le(i1, 19)
  272. guard_true(i3, descr=faildescr2) [i1]
  273. jump(i1, descr=targettoken)
  274. """, namespace={'targettoken': targettoken,
  275. 'faildescr2': faildescr2})
  276. self.cpu.compile_bridge(faildescr1, bridge.inputargs,
  277. bridge.operations, looptoken)
  278. deadframe = self.cpu.execute_token(looptoken, 2)
  279. fail = self.cpu.get_latest_descr(deadframe)
  280. assert fail.identifier == 2
  281. res = self.cpu.get_int_value(deadframe, 0)
  282. assert res == 20
  283. def test_compile_big_bridge_out_of_small_loop(self):
  284. faildescr1 = BasicFailDescr(1)
  285. loop = parse("""
  286. [i0]
  287. guard_false(i0, descr=faildescr1) [i0]
  288. finish(descr=finaldescr)
  289. """, namespace={'faildescr1': faildescr1,
  290. 'finaldescr': BasicFinalDescr(2)})
  291. looptoken = JitCellToken()
  292. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  293. bridge = []
  294. i0 = InputArgInt()
  295. iprev = i0
  296. for i in range(150):
  297. iprev = ResOperation(rop.INT_ADD, [iprev, ConstInt(1)])
  298. bridge.append(iprev)
  299. bridge.append(ResOperation(rop.GUARD_FALSE, [i0],
  300. descr=BasicFailDescr(3)))
  301. bridge.append(ResOperation(rop.FINISH, [],
  302. descr=BasicFinalDescr(4)))
  303. bridge[-2].setfailargs(bridge[:-2])
  304. self.cpu.compile_bridge(faildescr1, [i0], bridge, looptoken)
  305. deadframe = self.cpu.execute_token(looptoken, 1)
  306. fail = self.cpu.get_latest_descr(deadframe)
  307. assert fail.identifier == 3
  308. for i in range(150):
  309. res = self.cpu.get_int_value(deadframe, i)
  310. assert res == 2 + i
  311. def test_finish(self):
  312. from rpython.jit.backend.llsupport.llmodel import final_descr_rd_locs
  313. class UntouchableFailDescr(AbstractFailDescr):
  314. final_descr = True
  315. rd_locs = final_descr_rd_locs
  316. def __setattr__(self, name, value):
  317. if (name == 'index' or name == '_carry_around_for_tests'
  318. or name == '_TYPE' or name == '_cpu'):
  319. return AbstractFailDescr.__setattr__(self, name, value)
  320. py.test.fail("finish descrs should not be touched")
  321. faildescr = UntouchableFailDescr() # to check that is not touched
  322. looptoken = JitCellToken()
  323. loop = parse("""
  324. [i0]
  325. finish(i0, descr=faildescr)
  326. """, namespace={'faildescr': faildescr})
  327. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  328. deadframe = self.cpu.execute_token(looptoken, 99)
  329. fail = self.cpu.get_latest_descr(deadframe)
  330. assert fail is faildescr
  331. res = self.cpu.get_int_value(deadframe, 0)
  332. assert res == 99
  333. looptoken = JitCellToken()
  334. operations = [
  335. ResOperation(rop.FINISH, [ConstInt(42)], descr=faildescr)
  336. ]
  337. self.cpu.compile_loop([], operations, looptoken)
  338. deadframe = self.cpu.execute_token(looptoken)
  339. fail = self.cpu.get_latest_descr(deadframe)
  340. assert fail is faildescr
  341. res = self.cpu.get_int_value(deadframe, 0)
  342. assert res == 42
  343. looptoken = JitCellToken()
  344. operations = [
  345. ResOperation(rop.FINISH, [], descr=faildescr)
  346. ]
  347. self.cpu.compile_loop([], operations, looptoken)
  348. deadframe = self.cpu.execute_token(looptoken)
  349. fail = self.cpu.get_latest_descr(deadframe)
  350. assert fail is faildescr
  351. if self.cpu.supports_floats:
  352. looptoken = JitCellToken()
  353. f0 = InputArgFloat()
  354. operations = [
  355. ResOperation(rop.FINISH, [f0], descr=faildescr)
  356. ]
  357. self.cpu.compile_loop([f0], operations, looptoken)
  358. value = longlong.getfloatstorage(-61.25)
  359. deadframe = self.cpu.execute_token(looptoken, value)
  360. fail = self.cpu.get_latest_descr(deadframe)
  361. assert fail is faildescr
  362. res = self.cpu.get_float_value(deadframe, 0)
  363. assert longlong.getrealfloat(res) == -61.25
  364. looptoken = JitCellToken()
  365. operations = [
  366. ResOperation(rop.FINISH, [constfloat(42.5)], descr=faildescr)
  367. ]
  368. self.cpu.compile_loop([], operations, looptoken)
  369. deadframe = self.cpu.execute_token(looptoken)
  370. fail = self.cpu.get_latest_descr(deadframe)
  371. assert fail is faildescr
  372. res = self.cpu.get_float_value(deadframe, 0)
  373. assert longlong.getrealfloat(res) == 42.5
  374. def test_execute_operations_in_env(self):
  375. cpu = self.cpu
  376. targettoken = TargetToken()
  377. loop = parse("""
  378. [i1, i0]
  379. label(i0, i1, descr=targettoken)
  380. i2 = int_add(i1, i0)
  381. i3 = int_sub(i0, 1)
  382. i4 = int_eq(i3, 0)
  383. guard_false(i4, descr=fdescr) [i3, i2]
  384. jump(i3, i2, descr=targettoken)
  385. """, namespace={'targettoken': targettoken,
  386. 'fdescr': BasicFailDescr()})
  387. looptoken = JitCellToken()
  388. cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  389. deadframe = self.cpu.execute_token(looptoken, 0, 10)
  390. assert self.cpu.get_int_value(deadframe, 0) == 0
  391. assert self.cpu.get_int_value(deadframe, 1) == 55
  392. def test_int_operations(self):
  393. from rpython.jit.metainterp.test.test_executor import get_int_tests
  394. for opnum, boxargs, retvalue in get_int_tests():
  395. print opnum
  396. res = self.execute_operation(opnum, boxargs, 'int')
  397. assert res == retvalue
  398. def test_float_operations(self):
  399. from rpython.jit.metainterp.test.test_executor import get_float_tests
  400. from rpython.jit.metainterp.resoperation import opname
  401. for opnum, boxargs, rettype, retvalue in get_float_tests(self.cpu):
  402. print("testing", opname[opnum])
  403. res = self.execute_operation(opnum, boxargs, rettype)
  404. if rettype == 'float':
  405. res = longlong.getrealfloat(res)
  406. assert res == retvalue
  407. def test_ovf_operations(self, reversed=False):
  408. minint = -sys.maxint-1
  409. boom = 'boom'
  410. for opnum, testcases in [
  411. (rop.INT_ADD_OVF, [(10, -2, 8),
  412. (-1, minint, boom),
  413. (sys.maxint//2, sys.maxint//2+2, boom)]),
  414. (rop.INT_SUB_OVF, [(-20, -23, 3),
  415. (-2, sys.maxint, boom),
  416. (sys.maxint//2, -(sys.maxint//2+2), boom)]),
  417. (rop.INT_MUL_OVF, [(minint/2, 2, minint),
  418. (-2, -(minint/2), minint),
  419. (minint/2, -2, boom)]),
  420. ]:
  421. v1 = InputArgInt(testcases[0][0])
  422. v2 = InputArgInt(testcases[0][1])
  423. #
  424. if not reversed:
  425. op0 = ResOperation(opnum, [v1, v2])
  426. op1 = ResOperation(rop.GUARD_NO_OVERFLOW, [],
  427. descr=BasicFailDescr(1))
  428. op2 = ResOperation(rop.FINISH, [op0], descr=BasicFinalDescr(2))
  429. ops = [op0, op1, op2]
  430. op1.setfailargs([])
  431. else:
  432. op0 = ResOperation(opnum, [v1, v2])
  433. op1 = ResOperation(rop.GUARD_OVERFLOW, [],
  434. descr=BasicFailDescr(1))
  435. op2 = ResOperation(rop.FINISH, [], descr=BasicFinalDescr(2))
  436. ops = [op0, op1, op2]
  437. op1.setfailargs([op0])
  438. #
  439. looptoken = JitCellToken()
  440. self.cpu.compile_loop([v1, v2], ops, looptoken)
  441. for x, y, z in testcases:
  442. deadframe = self.cpu.execute_token(looptoken, x, y)
  443. fail = self.cpu.get_latest_descr(deadframe)
  444. if (z == boom) ^ reversed:
  445. assert fail.identifier == 1
  446. else:
  447. assert fail.identifier == 2
  448. if z != boom:
  449. assert self.cpu.get_int_value(deadframe, 0) == z
  450. excvalue = self.cpu.grab_exc_value(deadframe)
  451. assert not excvalue
  452. def test_ovf_operations_reversed(self):
  453. self.test_ovf_operations(reversed=True)
  454. def test_bh_call(self):
  455. cpu = self.cpu
  456. #
  457. def func(c):
  458. return chr(ord(c) + 1)
  459. FPTR = self.Ptr(self.FuncType([lltype.Char], lltype.Char))
  460. func_ptr = llhelper(FPTR, func)
  461. calldescr = cpu.calldescrof(deref(FPTR), (lltype.Char,), lltype.Char,
  462. EffectInfo.MOST_GENERAL)
  463. x = cpu.bh_call_i(self.get_funcbox(cpu, func_ptr).value,
  464. [ord('A')], None, None, calldescr)
  465. assert x == ord('B')
  466. if cpu.supports_floats:
  467. def func(f, i):
  468. assert isinstance(f, float)
  469. assert is_valid_int(i)
  470. return f - float(i)
  471. FPTR = self.Ptr(self.FuncType([lltype.Float, lltype.Signed],
  472. lltype.Float))
  473. func_ptr = llhelper(FPTR, func)
  474. FTP = deref(FPTR)
  475. calldescr = cpu.calldescrof(FTP, FTP.ARGS, FTP.RESULT,
  476. EffectInfo.MOST_GENERAL)
  477. x = cpu.bh_call_f(self.get_funcbox(cpu, func_ptr).value,
  478. [42], None, [longlong.getfloatstorage(3.5)],
  479. calldescr)
  480. assert longlong.getrealfloat(x) == 3.5 - 42
  481. def test_call(self):
  482. from rpython.rlib.jit_libffi import types
  483. def func_int(a, b):
  484. return a + b
  485. def func_char(c, c1):
  486. return chr(ord(c) + ord(c1))
  487. functions = [
  488. (func_int, lltype.Signed, types.sint, 655360, 655360),
  489. (func_int, lltype.Signed, types.sint, 655360, -293999429),
  490. (func_int, rffi.SHORT, types.sint16, 1213, 1213),
  491. (func_int, rffi.SHORT, types.sint16, 1213, -12020),
  492. (func_char, lltype.Char, types.uchar, 12, 12),
  493. ]
  494. cpu = self.cpu
  495. for func, TP, ffi_type, num, num1 in functions:
  496. #
  497. FPTR = self.Ptr(self.FuncType([TP, TP], TP))
  498. func_ptr = llhelper(FPTR, func)
  499. FUNC = deref(FPTR)
  500. funcbox = self.get_funcbox(cpu, func_ptr)
  501. # first, try it with the "normal" calldescr
  502. calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  503. EffectInfo.MOST_GENERAL)
  504. res = self.execute_operation(rop.CALL_I,
  505. [funcbox, InputArgInt(num),
  506. InputArgInt(num1)],
  507. 'int', descr=calldescr)
  508. assert res == num + num1
  509. # then, try it with the dynamic calldescr
  510. dyn_calldescr = cpu._calldescr_dynamic_for_tests(
  511. [ffi_type, ffi_type], ffi_type)
  512. res = self.execute_operation(rop.CALL_I,
  513. [funcbox, InputArgInt(num),
  514. InputArgInt(num1)],
  515. 'int', descr=dyn_calldescr)
  516. assert res == num + num1
  517. # last, try it with one constant argument
  518. calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL)
  519. res = self.execute_operation(rop.CALL_I,
  520. [funcbox, ConstInt(num),
  521. InputArgInt(num1)],
  522. 'int', descr=calldescr)
  523. assert res == num + num1
  524. if cpu.supports_floats:
  525. def func(f0, f1, f2, f3, f4, f5, f6, i0, f7, i1, f8, f9):
  526. seen.append((f0, f1, f2, f3, f4, f5, f6, i0, f7, i1, f8, f9))
  527. return f0 + f1 + f2 + f3 + f4 + f5 + f6 + float(i0 + i1) + f7 + f8 + f9
  528. seen = []
  529. F = lltype.Float
  530. I = lltype.Signed
  531. FUNC = self.FuncType([F] * 7 + [I] + [F] + [I] + [F]* 2, F)
  532. FPTR = self.Ptr(FUNC)
  533. func_ptr = llhelper(FPTR, func)
  534. calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  535. EffectInfo.MOST_GENERAL)
  536. funcbox = self.get_funcbox(cpu, func_ptr)
  537. args = ([boxfloat(.0), boxfloat(.1), boxfloat(.2), boxfloat(.3),
  538. boxfloat(.4), boxfloat(.5), boxfloat(.6),
  539. InputArgInt(1), boxfloat(.7), InputArgInt(2), boxfloat(.8),
  540. boxfloat(.9)])
  541. res = self.execute_operation(rop.CALL_F,
  542. [funcbox] + args,
  543. 'float', descr=calldescr)
  544. assert seen == [(.0, .1, .2, .3, .4, .5, .6, 1, .7, 2, .8, .9)]
  545. assert abs(longlong.getrealfloat(res) - 7.5) < 0.0001
  546. def test_call_many_arguments(self):
  547. # Test calling a function with a large number of arguments (more than
  548. # 6, which will force passing some arguments on the stack on 64-bit)
  549. def func(*args):
  550. assert len(args) == 16
  551. # Try to sum up args in a way that would probably detect a
  552. # transposed argument
  553. return sum(arg * (2**i) for i, arg in enumerate(args))
  554. FUNC = self.FuncType([lltype.Signed]*16, lltype.Signed)
  555. FPTR = self.Ptr(FUNC)
  556. calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  557. EffectInfo.MOST_GENERAL)
  558. func_ptr = llhelper(FPTR, func)
  559. args = range(16)
  560. funcbox = self.get_funcbox(self.cpu, func_ptr)
  561. res = self.execute_operation(rop.CALL_I, [funcbox] + map(InputArgInt, args), 'int', descr=calldescr)
  562. assert res == func(*args)
  563. def test_call_box_func(self):
  564. def a(a1, a2):
  565. return a1 + a2
  566. def b(b1, b2):
  567. return b1 * b2
  568. arg1 = 40
  569. arg2 = 2
  570. for f in [a, b]:
  571. TP = lltype.Signed
  572. FPTR = self.Ptr(self.FuncType([TP, TP], TP))
  573. func_ptr = llhelper(FPTR, f)
  574. FUNC = deref(FPTR)
  575. funcconst = self.get_funcbox(self.cpu, func_ptr)
  576. funcbox = InputArgInt(funcconst.getint())
  577. calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  578. EffectInfo.MOST_GENERAL)
  579. res = self.execute_operation(rop.CALL_I,
  580. [funcbox, InputArgInt(arg1),
  581. InputArgInt(arg2)],
  582. 'int', descr=calldescr)
  583. assert res == f(arg1, arg2)
  584. def test_call_stack_alignment(self):
  585. # test stack alignment issues, notably for Mac OS/X.
  586. # also test the ordering of the arguments.
  587. def func_ints(*ints):
  588. s = str(ints) + '\n'
  589. os.write(1, s) # don't remove -- crash if the stack is misaligned
  590. return sum([(10+i)*(5+j) for i, j in enumerate(ints)])
  591. for nb_args in range(0, 35):
  592. cpu = self.cpu
  593. TP = lltype.Signed
  594. #
  595. FPTR = self.Ptr(self.FuncType([TP] * nb_args, TP))
  596. func_ptr = llhelper(FPTR, func_ints)
  597. FUNC = deref(FPTR)
  598. calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  599. EffectInfo.MOST_GENERAL)
  600. funcbox = self.get_funcbox(cpu, func_ptr)
  601. args = [280-24*i for i in range(nb_args)]
  602. res = self.execute_operation(rop.CALL_I,
  603. [funcbox] + map(InputArgInt, args),
  604. 'int', descr=calldescr)
  605. assert res == func_ints(*args)
  606. def test_call_with_const_floats(self):
  607. if not self.cpu.supports_floats:
  608. py.test.skip("requires floats")
  609. def func(f1, f2):
  610. return f1 + f2
  611. FUNC = self.FuncType([lltype.Float, lltype.Float], lltype.Float)
  612. FPTR = self.Ptr(FUNC)
  613. calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  614. EffectInfo.MOST_GENERAL)
  615. func_ptr = llhelper(FPTR, func)
  616. funcbox = self.get_funcbox(self.cpu, func_ptr)
  617. res = self.execute_operation(rop.CALL_F, [funcbox, constfloat(1.5),
  618. constfloat(2.5)], 'float',
  619. descr=calldescr)
  620. assert longlong.getrealfloat(res) == 4.0
  621. def test_field_basic(self):
  622. t_box, T_box, d = self.alloc_instance(self.T)
  623. fielddescr = self.cpu.fielddescrof(self.S, 'value')
  624. assert not fielddescr.is_pointer_field()
  625. #
  626. res = self.execute_operation(rop.SETFIELD_GC, [t_box, InputArgInt(39082)],
  627. 'void', descr=fielddescr)
  628. assert res is None
  629. res = self.execute_operation(rop.GETFIELD_GC_I, [t_box],
  630. 'int', descr=fielddescr)
  631. assert res == 39082
  632. #
  633. fielddescr1 = self.cpu.fielddescrof(self.S, 'chr1')
  634. fielddescr2 = self.cpu.fielddescrof(self.S, 'chr2')
  635. shortdescr = self.cpu.fielddescrof(self.S, 'short')
  636. self.execute_operation(rop.SETFIELD_GC, [t_box, InputArgInt(250)],
  637. 'void', descr=fielddescr2)
  638. self.execute_operation(rop.SETFIELD_GC, [t_box, InputArgInt(133)],
  639. 'void', descr=fielddescr1)
  640. self.execute_operation(rop.SETFIELD_GC, [t_box, InputArgInt(1331)],
  641. 'void', descr=shortdescr)
  642. res = self.execute_operation(rop.GETFIELD_GC_I, [t_box],
  643. 'int', descr=fielddescr2)
  644. assert res == 250
  645. res = self.execute_operation(rop.GETFIELD_GC_I, [t_box],
  646. 'int', descr=fielddescr1)
  647. assert res == 133
  648. res = self.execute_operation(rop.GETFIELD_GC_I, [t_box],
  649. 'int', descr=shortdescr)
  650. assert res == 1331
  651. #
  652. u_box, U_box, d = self.alloc_instance(self.U)
  653. fielddescr2 = self.cpu.fielddescrof(self.S, 'next')
  654. assert fielddescr2.is_pointer_field()
  655. res = self.execute_operation(rop.SETFIELD_GC, [t_box, u_box],
  656. 'void', descr=fielddescr2)
  657. assert res is None
  658. res = self.execute_operation(rop.GETFIELD_GC_R, [t_box],
  659. 'ref', descr=fielddescr2)
  660. assert res == u_box.getref_base()
  661. #
  662. null_const = wrap_constant(self.null_instance().getref_base())
  663. res = self.execute_operation(rop.SETFIELD_GC, [t_box, null_const],
  664. 'void', descr=fielddescr2)
  665. assert res is None
  666. res = self.execute_operation(rop.GETFIELD_GC_R, [t_box],
  667. 'ref', descr=fielddescr2)
  668. assert not res
  669. if self.cpu.supports_floats:
  670. floatdescr = self.cpu.fielddescrof(self.S, 'float')
  671. self.execute_operation(rop.SETFIELD_GC, [t_box, boxfloat(3.4)],
  672. 'void', descr=floatdescr)
  673. res = self.execute_operation(rop.GETFIELD_GC_F, [t_box],
  674. 'float', descr=floatdescr)
  675. assert longlong.getrealfloat(res) == 3.4
  676. #
  677. self.execute_operation(rop.SETFIELD_GC, [t_box, constfloat(-3.6)],
  678. 'void', descr=floatdescr)
  679. res = self.execute_operation(rop.GETFIELD_GC_F, [t_box],
  680. 'float', descr=floatdescr)
  681. assert longlong.getrealfloat(res) == -3.6
  682. def test_passing_guards(self):
  683. t_box, T_box, d = self.alloc_instance(self.T)
  684. nullbox = self.null_instance()
  685. all = [(rop.GUARD_TRUE, [InputArgInt(1)]),
  686. (rop.GUARD_FALSE, [InputArgInt(0)]),
  687. (rop.GUARD_VALUE, [InputArgInt(42), ConstInt(42)]),
  688. ]
  689. if not self.avoid_instances:
  690. all.extend([
  691. (rop.GUARD_NONNULL, [t_box]),
  692. (rop.GUARD_ISNULL, [nullbox])
  693. ])
  694. if self.cpu.supports_floats:
  695. all.append((rop.GUARD_VALUE, [boxfloat(3.5), constfloat(3.5)]))
  696. for (opname, args) in all:
  697. assert self.execute_operation(opname, args, 'void') == None
  698. assert not self.guard_failed
  699. def test_passing_guard_class(self):
  700. t_box, T_box, d = self.alloc_instance(self.T)
  701. #null_box = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.nullptr(T)))
  702. self.execute_operation(rop.GUARD_CLASS, [t_box, T_box], 'void')
  703. assert not self.guard_failed
  704. self.execute_operation(rop.GUARD_NONNULL_CLASS, [t_box, T_box], 'void')
  705. assert not self.guard_failed
  706. def test_failing_guards(self):
  707. t_box, T_box, d = self.alloc_instance(self.T)
  708. nullbox = self.null_instance()
  709. all = [(rop.GUARD_TRUE, [InputArgInt(0)]),
  710. (rop.GUARD_FALSE, [InputArgInt(1)]),
  711. (rop.GUARD_VALUE, [InputArgInt(42), ConstInt(41)]),
  712. ]
  713. if not self.avoid_instances:
  714. all.extend([
  715. (rop.GUARD_NONNULL, [nullbox]),
  716. (rop.GUARD_ISNULL, [t_box])])
  717. if self.cpu.supports_floats:
  718. all.append((rop.GUARD_VALUE, [boxfloat(-1.0), constfloat(1.0)]))
  719. for opname, args in all:
  720. assert self.execute_operation(opname, args, 'void') == None
  721. assert self.guard_failed
  722. def test_failing_guard_class(self):
  723. t_box, T_box, _ = self.alloc_instance(self.T)
  724. u_box, U_box, _ = self.alloc_instance(self.U)
  725. null_box = self.null_instance()
  726. for opname, args in [(rop.GUARD_CLASS, [t_box, U_box]),
  727. (rop.GUARD_CLASS, [u_box, T_box]),
  728. (rop.GUARD_NONNULL_CLASS, [t_box, U_box]),
  729. (rop.GUARD_NONNULL_CLASS, [u_box, T_box]),
  730. (rop.GUARD_NONNULL_CLASS, [null_box, T_box]),
  731. ]:
  732. assert self.execute_operation(opname, args, 'void') == None
  733. assert self.guard_failed
  734. def test_ooops(self):
  735. u1_box, U_box, _ = self.alloc_instance(self.U)
  736. u2_box, U_box, _ = self.alloc_instance(self.U)
  737. r = self.execute_operation(rop.PTR_EQ, [u1_box,
  738. clone(u1_box)], 'int')
  739. assert r == 1
  740. r = self.execute_operation(rop.PTR_NE, [u2_box,
  741. clone(u2_box)], 'int')
  742. assert r == 0
  743. r = self.execute_operation(rop.PTR_EQ, [u1_box, u2_box], 'int')
  744. assert r == 0
  745. r = self.execute_operation(rop.PTR_NE, [u2_box, u1_box], 'int')
  746. assert r == 1
  747. #
  748. null_box = self.null_instance()
  749. r = self.execute_operation(rop.PTR_EQ, [null_box,
  750. clone(null_box)], 'int')
  751. assert r == 1
  752. r = self.execute_operation(rop.PTR_EQ, [u1_box, null_box], 'int')
  753. assert r == 0
  754. r = self.execute_operation(rop.PTR_EQ, [null_box, u2_box], 'int')
  755. assert r == 0
  756. r = self.execute_operation(rop.PTR_NE, [null_box,
  757. clone(null_box)], 'int')
  758. assert r == 0
  759. r = self.execute_operation(rop.PTR_NE, [u2_box, null_box], 'int')
  760. assert r == 1
  761. r = self.execute_operation(rop.PTR_NE, [null_box, u1_box], 'int')
  762. assert r == 1
  763. # These operations are supposed to be the same as PTR_EQ/PTR_NE
  764. # just checking that the operations are defined in the backend.
  765. r = self.execute_operation(rop.INSTANCE_PTR_EQ, [u1_box, u2_box], 'int')
  766. assert r == 0
  767. r = self.execute_operation(rop.INSTANCE_PTR_NE, [u2_box, u1_box], 'int')
  768. assert r == 1
  769. def test_array_basic(self):
  770. a_box, A = self.alloc_array_of(rffi.SHORT, 342)
  771. arraydescr = self.cpu.arraydescrof(A)
  772. assert not arraydescr.is_array_of_pointers()
  773. #
  774. r = self.execute_operation(rop.ARRAYLEN_GC, [a_box],
  775. 'int', descr=arraydescr)
  776. assert r == 342
  777. r = self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(310),
  778. InputArgInt(744)],
  779. 'void', descr=arraydescr)
  780. assert r is None
  781. r = self.execute_operation(rop.GETARRAYITEM_GC_I, [a_box, InputArgInt(310)],
  782. 'int', descr=arraydescr)
  783. assert r == 744
  784. a_box, A = self.alloc_array_of(lltype.Signed, 342)
  785. arraydescr = self.cpu.arraydescrof(A)
  786. assert not arraydescr.is_array_of_pointers()
  787. #
  788. r = self.execute_operation(rop.ARRAYLEN_GC, [a_box],
  789. 'int', descr=arraydescr)
  790. assert r == 342
  791. r = self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(310),
  792. InputArgInt(7441)],
  793. 'void', descr=arraydescr)
  794. assert r is None
  795. r = self.execute_operation(rop.GETARRAYITEM_GC_I, [a_box, InputArgInt(310)],
  796. 'int', descr=arraydescr)
  797. assert r == 7441
  798. #
  799. a_box, A = self.alloc_array_of(lltype.Char, 11)
  800. arraydescr = self.cpu.arraydescrof(A)
  801. assert not arraydescr.is_array_of_pointers()
  802. r = self.execute_operation(rop.ARRAYLEN_GC, [a_box],
  803. 'int', descr=arraydescr)
  804. assert r == 11
  805. r = self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(4),
  806. InputArgInt(150)],
  807. 'void', descr=arraydescr)
  808. assert r is None
  809. r = self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(3),
  810. InputArgInt(160)],
  811. 'void', descr=arraydescr)
  812. assert r is None
  813. r = self.execute_operation(rop.GETARRAYITEM_GC_I, [a_box, InputArgInt(4)],
  814. 'int', descr=arraydescr)
  815. assert r == 150
  816. r = self.execute_operation(rop.GETARRAYITEM_GC_I, [a_box, InputArgInt(3)],
  817. 'int', descr=arraydescr)
  818. assert r == 160
  819. #
  820. if isinstance(A, lltype.GcArray):
  821. A = lltype.Ptr(A)
  822. b_box, B = self.alloc_array_of(A, 3)
  823. arraydescr = self.cpu.arraydescrof(B)
  824. assert arraydescr.is_array_of_pointers()
  825. r = self.execute_operation(rop.ARRAYLEN_GC, [b_box],
  826. 'int', descr=arraydescr)
  827. assert r == 3
  828. r = self.execute_operation(rop.SETARRAYITEM_GC, [b_box, InputArgInt(1),
  829. a_box],
  830. 'void', descr=arraydescr)
  831. assert r is None
  832. r = self.execute_operation(rop.GETARRAYITEM_GC_R, [b_box, InputArgInt(1)],
  833. 'ref', descr=arraydescr)
  834. assert r == a_box.getvalue()
  835. #
  836. # Unsigned should work the same as Signed
  837. a_box, A = self.alloc_array_of(lltype.Unsigned, 342)
  838. arraydescr = self.cpu.arraydescrof(A)
  839. assert not arraydescr.is_array_of_pointers()
  840. r = self.execute_operation(rop.ARRAYLEN_GC, [a_box],
  841. 'int', descr=arraydescr)
  842. assert r == 342
  843. r = self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(310),
  844. InputArgInt(7441)],
  845. 'void', descr=arraydescr)
  846. assert r is None
  847. r = self.execute_operation(rop.GETARRAYITEM_GC_I, [a_box, InputArgInt(310)],
  848. 'int', descr=arraydescr)
  849. assert r == 7441
  850. #
  851. # Bool should work the same as Char
  852. a_box, A = self.alloc_array_of(lltype.Bool, 311)
  853. arraydescr = self.cpu.arraydescrof(A)
  854. assert not arraydescr.is_array_of_pointers()
  855. r = self.execute_operation(rop.ARRAYLEN_GC, [a_box],
  856. 'int', descr=arraydescr)
  857. assert r == 311
  858. r = self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(304),
  859. InputArgInt(1)],
  860. 'void', descr=arraydescr)
  861. assert r is None
  862. r = self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(303),
  863. InputArgInt(0)],
  864. 'void', descr=arraydescr)
  865. assert r is None
  866. r = self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(302),
  867. InputArgInt(1)],
  868. 'void', descr=arraydescr)
  869. assert r is None
  870. r = self.execute_operation(rop.GETARRAYITEM_GC_I, [a_box, InputArgInt(304)],
  871. 'int', descr=arraydescr)
  872. assert r == 1
  873. r = self.execute_operation(rop.GETARRAYITEM_GC_I, [a_box, InputArgInt(303)],
  874. 'int', descr=arraydescr)
  875. assert r == 0
  876. r = self.execute_operation(rop.GETARRAYITEM_GC_I, [a_box, InputArgInt(302)],
  877. 'int', descr=arraydescr)
  878. assert r == 1
  879. if self.cpu.supports_floats:
  880. a_box, A = self.alloc_array_of(lltype.Float, 31)
  881. arraydescr = self.cpu.arraydescrof(A)
  882. self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(1),
  883. boxfloat(3.5)],
  884. 'void', descr=arraydescr)
  885. self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(2),
  886. constfloat(4.5)],
  887. 'void', descr=arraydescr)
  888. r = self.execute_operation(rop.GETARRAYITEM_GC_F, [a_box, InputArgInt(1)],
  889. 'float', descr=arraydescr)
  890. assert longlong.getrealfloat(r) == 3.5
  891. r = self.execute_operation(rop.GETARRAYITEM_GC_F, [a_box, InputArgInt(2)],
  892. 'float', descr=arraydescr)
  893. assert longlong.getrealfloat(r) == 4.5
  894. # For platforms where sizeof(INT) != sizeof(Signed) (ie, x86-64)
  895. a_box, A = self.alloc_array_of(rffi.INT, 342)
  896. arraydescr = self.cpu.arraydescrof(A)
  897. assert not arraydescr.is_array_of_pointers()
  898. r = self.execute_operation(rop.ARRAYLEN_GC, [a_box],
  899. 'int', descr=arraydescr)
  900. assert r == 342
  901. r = self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(310),
  902. InputArgInt(7441)],
  903. 'void', descr=arraydescr)
  904. assert r is None
  905. r = self.execute_operation(rop.GETARRAYITEM_GC_I, [a_box, InputArgInt(310)],
  906. 'int', descr=arraydescr)
  907. assert r == 7441
  908. def test_array_of_structs(self):
  909. TP = lltype.GcStruct('x')
  910. ITEM = lltype.Struct('x',
  911. ('vs', lltype.Signed),
  912. ('vu', lltype.Unsigned),
  913. ('vsc', rffi.SIGNEDCHAR),
  914. ('vuc', rffi.UCHAR),
  915. ('vss', rffi.SHORT),
  916. ('vus', rffi.USHORT),
  917. ('vsi', rffi.INT),
  918. ('vui', rffi.UINT),
  919. ('k', lltype.Float),
  920. ('p', lltype.Ptr(TP)))
  921. a_box, A = self.alloc_array_of(ITEM, 15)
  922. s_box, S, _ = self.alloc_instance(TP)
  923. vsdescr = self.cpu.interiorfielddescrof(A, 'vs')
  924. kdescr = self.cpu.interiorfielddescrof(A, 'k')
  925. pdescr = self.cpu.interiorfielddescrof(A, 'p')
  926. self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, InputArgInt(3),
  927. boxfloat(1.5)],
  928. 'void', descr=kdescr)
  929. f = self.cpu.bh_getinteriorfield_gc_f(a_box.getref_base(), 3, kdescr)
  930. assert longlong.getrealfloat(f) == 1.5
  931. self.cpu.bh_setinteriorfield_gc_f(a_box.getref_base(), 3, longlong.getfloatstorage(2.5), kdescr)
  932. r = self.execute_operation(rop.GETINTERIORFIELD_GC_F, [a_box, InputArgInt(3)],
  933. 'float', descr=kdescr)
  934. assert longlong.getrealfloat(r) == 2.5
  935. #
  936. NUMBER_FIELDS = [('vs', lltype.Signed),
  937. ('vu', lltype.Unsigned),
  938. ('vsc', rffi.SIGNEDCHAR),
  939. ('vuc', rffi.UCHAR),
  940. ('vss', rffi.SHORT),
  941. ('vus', rffi.USHORT),
  942. ('vsi', rffi.INT),
  943. ('vui', rffi.UINT)]
  944. for name, TYPE in NUMBER_FIELDS[::-1]:
  945. vdescr = self.cpu.interiorfielddescrof(A, name)
  946. self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, InputArgInt(3),
  947. InputArgInt(-15)],
  948. 'void', descr=vdescr)
  949. for name, TYPE in NUMBER_FIELDS:
  950. vdescr = self.cpu.interiorfielddescrof(A, name)
  951. i = self.cpu.bh_getinteriorfield_gc_i(a_box.getref_base(), 3,
  952. vdescr)
  953. assert i == rffi.cast(lltype.Signed, rffi.cast(TYPE, -15))
  954. for name, TYPE in NUMBER_FIELDS[::-1]:
  955. vdescr = self.cpu.interiorfielddescrof(A, name)
  956. self.cpu.bh_setinteriorfield_gc_i(a_box.getref_base(), 3,
  957. -25, vdescr)
  958. for name, TYPE in NUMBER_FIELDS:
  959. vdescr = self.cpu.interiorfielddescrof(A, name)
  960. r = self.execute_operation(rop.GETINTERIORFIELD_GC_I,
  961. [a_box, InputArgInt(3)],
  962. 'int', descr=vdescr)
  963. assert r == rffi.cast(lltype.Signed, rffi.cast(TYPE, -25))
  964. #
  965. self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, InputArgInt(4),
  966. s_box],
  967. 'void', descr=pdescr)
  968. r = self.cpu.bh_getinteriorfield_gc_r(a_box.getref_base(), 4, pdescr)
  969. assert r == s_box.getref_base()
  970. self.cpu.bh_setinteriorfield_gc_r(a_box.getref_base(), 3,
  971. s_box.getref_base(), pdescr)
  972. r = self.execute_operation(rop.GETINTERIORFIELD_GC_R, [a_box, InputArgInt(3)],
  973. 'ref', descr=pdescr)
  974. assert r == s_box.getref_base()
  975. #
  976. # test a corner case that used to fail on x86
  977. i4 = InputArgInt(4)
  978. self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, i4, i4],
  979. 'void', descr=vsdescr)
  980. r = self.cpu.bh_getinteriorfield_gc_i(a_box.getref_base(), 4, vsdescr)
  981. assert r == 4
  982. def test_array_of_structs_all_sizes(self):
  983. # x86 has special support that can be used for sizes
  984. # 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 16, 18, 20, 24, 32, 36, 40, 64, 72
  985. for length in range(1, 75):
  986. ITEM = lltype.FixedSizeArray(lltype.Char, length)
  987. a_box, A = self.alloc_array_of(ITEM, 5)
  988. a = lltype.cast_opaque_ptr(lltype.Ptr(A), a_box.getref_base())
  989. middle = length // 2
  990. a[3][middle] = chr(65 + length)
  991. fdescr = self.cpu.interiorfielddescrof(A, 'item%d' % middle)
  992. r = self.execute_operation(rop.GETINTERIORFIELD_GC_I,
  993. [a_box, InputArgInt(3)],
  994. 'int', descr=fdescr)
  995. assert r == 65 + length
  996. self.execute_operation(rop.SETINTERIORFIELD_GC,
  997. [a_box, InputArgInt(2), InputArgInt(r + 1)],
  998. 'void', descr=fdescr)
  999. r1 = self.cpu.bh_getinteriorfield_gc_i(a_box.getref_base(), 2,
  1000. fdescr)
  1001. assert r1 == r + 1
  1002. def test_string_basic(self):
  1003. s_box = self.alloc_string("hello\xfe")
  1004. r = self.execute_operation(rop.STRLEN, [s_box], 'int')
  1005. assert r == 6
  1006. r = self.execute_operation(rop.STRGETITEM, [s_box, InputArgInt(5)], 'int')
  1007. assert r == 254
  1008. r = self.execute_operation(rop.STRSETITEM, [s_box, InputArgInt(4),
  1009. InputArgInt(153)], 'void')
  1010. assert r is None
  1011. r = self.execute_operation(rop.STRGETITEM, [s_box, InputArgInt(5)], 'int')
  1012. assert r == 254
  1013. r = self.execute_operation(rop.STRGETITEM, [s_box, InputArgInt(4)], 'int')
  1014. assert r == 153
  1015. def test_copystrcontent(self):
  1016. s_box = self.alloc_string("abcdef")
  1017. for s_box in [s_box, wrap_constant(s_box.getref_base())]:
  1018. for srcstart_box in [InputArgInt(2), ConstInt(2)]:
  1019. for dststart_box in [InputArgInt(3), ConstInt(3)]:
  1020. for length_box in [InputArgInt(4), ConstInt(4)]:
  1021. for r_box_is_const in [False, True]:
  1022. r_box = self.alloc_string("!???????!")
  1023. if r_box_is_const:
  1024. r_box = wrap_constant(r_box.getref_base())
  1025. self.execute_operation(rop.COPYSTRCONTENT,
  1026. [s_box, r_box,
  1027. srcstart_box,
  1028. dststart_box,
  1029. length_box], 'void')
  1030. assert self.look_string(r_box) == "!??cdef?!"
  1031. def test_copyunicodecontent(self):
  1032. s_box = self.alloc_unicode(u"abcdef")
  1033. for s_box in [s_box, wrap_constant(s_box.getref_base())]:
  1034. for srcstart_box in [InputArgInt(2), ConstInt(2)]:
  1035. for dststart_box in [InputArgInt(3), ConstInt(3)]:
  1036. for length_box in [InputArgInt(4), ConstInt(4)]:
  1037. for r_box_is_const in [False, True]:
  1038. r_box = self.alloc_unicode(u"!???????!")
  1039. if r_box_is_const:
  1040. r_box = wrap_constant(r_box.getref_base())
  1041. self.execute_operation(rop.COPYUNICODECONTENT,
  1042. [s_box, r_box,
  1043. srcstart_box,
  1044. dststart_box,
  1045. length_box], 'void')
  1046. assert self.look_unicode(r_box) == u"!??cdef?!"
  1047. def test_do_unicode_basic(self):
  1048. u = self.cpu.bh_newunicode(5)
  1049. self.cpu.bh_unicodesetitem(u, 4, 123)
  1050. r = self.cpu.bh_unicodegetitem(u, 4)
  1051. assert r == 123
  1052. def test_unicode_basic(self):
  1053. u_box = self.alloc_unicode(u"hello\u1234")
  1054. r = self.execute_operation(rop.UNICODELEN, [u_box], 'int')
  1055. assert r == 6
  1056. r = self.execute_operation(rop.UNICODEGETITEM, [u_box, InputArgInt(5)],
  1057. 'int')
  1058. assert r == 0x1234
  1059. r = self.execute_operation(rop.UNICODESETITEM, [u_box, InputArgInt(4),
  1060. InputArgInt(31313)], 'void')
  1061. assert r is None
  1062. r = self.execute_operation(rop.UNICODEGETITEM, [u_box, InputArgInt(5)],
  1063. 'int')
  1064. assert r == 0x1234
  1065. r = self.execute_operation(rop.UNICODEGETITEM, [u_box, InputArgInt(4)],
  1066. 'int')
  1067. assert r == 31313
  1068. def test_same_as(self):
  1069. r = self.execute_operation(rop.SAME_AS_I, [ConstInt(5)], 'int')
  1070. assert r == 5
  1071. r = self.execute_operation(rop.SAME_AS_I, [InputArgInt(5)], 'int')
  1072. assert r == 5
  1073. u_box = self.alloc_unicode(u"hello\u1234")
  1074. r = self.execute_operation(rop.SAME_AS_R, [wrap_constant(u_box.getref_base())], 'ref')
  1075. assert r == u_box.getref_base()
  1076. r = self.execute_operation(rop.SAME_AS_R, [u_box], 'ref')
  1077. assert r == u_box.getref_base()
  1078. if self.cpu.supports_floats:
  1079. r = self.execute_operation(rop.SAME_AS_F, [constfloat(5.5)], 'float')
  1080. assert longlong.getrealfloat(r) == 5.5
  1081. r = self.execute_operation(rop.SAME_AS_F, [boxfloat(5.5)], 'float')
  1082. assert longlong.getrealfloat(r) == 5.5
  1083. def test_virtual_ref(self):
  1084. pass # VIRTUAL_REF must not reach the backend nowadays
  1085. def test_virtual_ref_finish(self):
  1086. pass # VIRTUAL_REF_FINISH must not reach the backend nowadays
  1087. def test_arguments_to_execute_token(self):
  1088. # this test checks that execute_token() can be called with any
  1089. # variant of ints and floats as arguments
  1090. if self.cpu.supports_floats:
  1091. numkinds = 2
  1092. else:
  1093. numkinds = 1
  1094. seed = random.randrange(0, 10000)
  1095. print 'Seed is', seed # or choose it by changing the previous line
  1096. r = random.Random()
  1097. r.seed(seed)
  1098. for nb_args in range(50):
  1099. print 'Passing %d arguments to execute_token...' % nb_args
  1100. #
  1101. inputargs = []
  1102. values = []
  1103. for k in range(nb_args):
  1104. kind = r.randrange(0, numkinds)
  1105. if kind == 0:
  1106. inputargs.append(InputArgInt())
  1107. values.append(r.randrange(-100000, 100000))
  1108. else:
  1109. inputargs.append(InputArgFloat())
  1110. values.append(longlong.getfloatstorage(r.random()))
  1111. #
  1112. looptoken = JitCellToken()
  1113. guarddescr = BasicFailDescr(42)
  1114. faildescr = BasicFinalDescr(43)
  1115. operations = []
  1116. retboxes = []
  1117. retvalues = []
  1118. #
  1119. ks = range(nb_args)
  1120. random.shuffle(ks)
  1121. for k in ks:
  1122. if isinstance(inputargs[k], InputArgInt):
  1123. x = r.randrange(-100000, 100000)
  1124. operations.append(
  1125. ResOperation(rop.INT_ADD, [inputargs[k],
  1126. ConstInt(x)])
  1127. )
  1128. y = values[k] + x
  1129. else:
  1130. x = r.random()
  1131. operations.append(
  1132. ResOperation(rop.FLOAT_ADD, [inputargs[k],
  1133. constfloat(x)])
  1134. )
  1135. y = longlong.getrealfloat(values[k]) + x
  1136. y = longlong.getfloatstorage(y)
  1137. kk = r.randrange(0, len(retboxes)+1)
  1138. retboxes.insert(kk, operations[-1])
  1139. retvalues.insert(kk, y)
  1140. #
  1141. op0 = ResOperation(rop.SAME_AS_I, [ConstInt(0)])
  1142. op1 = ResOperation(rop.GUARD_TRUE, [op0], descr=guarddescr)
  1143. op2 = ResOperation(rop.FINISH, [], descr=faildescr)
  1144. operations += [op0, op1, op2]
  1145. operations[-2].setfailargs(retboxes)
  1146. print inputargs
  1147. for op in operations:
  1148. print op
  1149. self.cpu.compile_loop(inputargs, operations, looptoken)
  1150. #
  1151. deadframe = self.cpu.execute_token(looptoken, *values)
  1152. fail = self.cpu.get_latest_descr(deadframe)
  1153. assert fail.identifier == 42
  1154. #
  1155. for k in range(len(retvalues)):
  1156. if retboxes[k].type == 'i':
  1157. got = self.cpu.get_int_value(deadframe, k)
  1158. else:
  1159. got = self.cpu.get_float_value(deadframe, k)
  1160. assert got == retvalues[k]
  1161. def test_jump(self):
  1162. # this test generates small loops where the JUMP passes many
  1163. # arguments of various types, shuffling them around.
  1164. if self.cpu.supports_floats:
  1165. numkinds = 3
  1166. else:
  1167. numkinds = 2
  1168. seed = random.randrange(0, 10000)
  1169. print 'Seed is', seed # or choose it by changing the previous line
  1170. r = random.Random()
  1171. r.seed(seed)
  1172. for nb_args in range(50):
  1173. print 'Passing %d arguments around...' % nb_args
  1174. #
  1175. inputargs = []
  1176. for k in range(nb_args):
  1177. kind = r.randrange(0, numkinds)
  1178. if kind == 0:
  1179. inputargs.append(InputArgInt())
  1180. elif kind == 1:
  1181. inputargs.append(InputArgRef())
  1182. else:
  1183. inputargs.append(InputArgFloat())
  1184. jumpargs = []
  1185. remixing = []
  1186. for srcbox in inputargs:
  1187. n = r.randrange(0, len(inputargs))
  1188. otherbox = inputargs[n]
  1189. if otherbox.type == srcbox.type:
  1190. remixing.append((srcbox, otherbox))
  1191. else:
  1192. otherbox = srcbox
  1193. jumpargs.append(otherbox)
  1194. #
  1195. index_counter = r.randrange(0, len(inputargs)+1)
  1196. i0 = InputArgInt()
  1197. inputargs.insert(index_counter, i0)
  1198. #
  1199. looptoken = JitCellToken()
  1200. targettoken = TargetToken()
  1201. faildescr = BasicFailDescr(15)
  1202. op0 = ResOperation(rop.LABEL, inputargs, descr=targettoken)
  1203. op1 = ResOperation(rop.INT_SUB, [i0, ConstInt(1)])
  1204. op2 = ResOperation(rop.INT_GE, [op1, ConstInt(0)])
  1205. op3 = ResOperation(rop.GUARD_TRUE, [op2])
  1206. jumpargs.insert(index_counter, op1)
  1207. op4 = ResOperation(rop.JUMP, jumpargs, descr=targettoken)
  1208. operations = [op0, op1, op2, op3, op4]
  1209. operations[3].setfailargs(inputargs[:])
  1210. operations[3].setdescr(faildescr)
  1211. #
  1212. self.cpu.compile_loop(inputargs, operations, looptoken)
  1213. #
  1214. values = []
  1215. S = lltype.GcStruct('S')
  1216. for box in inputargs:
  1217. if box.type == 'i':
  1218. values.append(r.randrange(-10000, 10000))
  1219. elif box.type == 'r':
  1220. p = lltype.malloc(S)
  1221. values.append(lltype.cast_opaque_ptr(llmemory.GCREF, p))
  1222. elif box.type == 'f':
  1223. values.append(longlong.getfloatstorage(r.random()))
  1224. else:
  1225. assert 0
  1226. values[index_counter] = 11
  1227. #
  1228. deadframe = self.cpu.execute_token(looptoken, *values)
  1229. fail = self.cpu.get_latest_descr(deadframe)
  1230. assert fail.identifier == 15
  1231. #
  1232. dstvalues = values[:]
  1233. for _ in range(11):
  1234. expected = dstvalues[:]
  1235. for tgtbox, srcbox in remixing:
  1236. v = dstvalues[inputargs.index(srcbox)]
  1237. expected[inputargs.index(tgtbox)] = v
  1238. dstvalues = expected
  1239. #
  1240. assert dstvalues[index_counter] == 11
  1241. dstvalues[index_counter] = 0
  1242. for i, (box, val) in enumerate(zip(inputargs, dstvalues)):
  1243. if box.type == 'i':
  1244. got = self.cpu.get_int_value(deadframe, i)
  1245. elif box.type == 'r':
  1246. got = self.cpu.get_ref_value(deadframe, i)
  1247. elif box.type == 'f':
  1248. got = self.cpu.get_float_value(deadframe, i)
  1249. else:
  1250. assert 0
  1251. assert type(got) == type(val)
  1252. assert got == val
  1253. def test_compile_bridge_float(self):
  1254. if not self.cpu.supports_floats:
  1255. py.test.skip("requires floats")
  1256. targettoken = TargetToken()
  1257. faildescr1 = BasicFailDescr(1)
  1258. faildescr2 = BasicFailDescr(2)
  1259. faildescr3 = BasicFinalDescr(3)
  1260. loop = parse("""
  1261. [f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11]
  1262. label(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, descr=targettoken)
  1263. i2 = float_le(f0, 9.2)
  1264. guard_true(i2, descr=faildescr1) [f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11]
  1265. guard_false(i2, descr=faildescr2) [f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11]
  1266. finish(descr=faildescr3)
  1267. """, namespace=locals())
  1268. looptoken = JitCellToken()
  1269. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  1270. bridge = parse("""
  1271. [f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11]
  1272. f15 = float_sub(f0, 1.0)
  1273. jump(f15, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, descr=targettoken)
  1274. """, namespace=locals())
  1275. self.cpu.compile_bridge(faildescr1, bridge.inputargs,
  1276. bridge.operations, looptoken)
  1277. args = []
  1278. for i in range(len(loop.inputargs)):
  1279. x = 13.5 + 6.73 * i
  1280. args.append(longlong.getfloatstorage(x))
  1281. deadframe = self.cpu.execute_token(looptoken, *args)
  1282. fail = self.cpu.get_latest_descr(deadframe)
  1283. assert fail.identifier == 2
  1284. res = self.cpu.get_float_value(deadframe, 0)
  1285. assert longlong.getrealfloat(res) == 8.5
  1286. for i in range(1, len(loop.inputargs)):
  1287. got = longlong.getrealfloat(self.cpu.get_float_value(
  1288. deadframe, i))
  1289. assert got == 13.5 + 6.73 * i
  1290. def test_compile_bridge_spilled_float(self):
  1291. if not self.cpu.supports_floats:
  1292. py.test.skip("requires floats")
  1293. faildescr1 = BasicFailDescr(100)
  1294. faildescr2 = BasicFinalDescr(102)
  1295. loopops = """
  1296. [i0,f1, f2]
  1297. f3 = float_add(f1, f2)
  1298. force_spill(f3)
  1299. force_spill(f1)
  1300. force_spill(f2)
  1301. guard_false(i0) [f1, f2, f3]
  1302. finish()"""
  1303. loop = parse(loopops)
  1304. looptoken = JitCellToken()
  1305. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  1306. args = [1]
  1307. args.append(longlong.getfloatstorage(132.25))
  1308. args.append(longlong.getfloatstorage(0.75))
  1309. deadframe = self.cpu.execute_token(looptoken, *args) #xxx check
  1310. fail = self.cpu.get_latest_descr(deadframe)
  1311. assert loop.operations[-2].getdescr() == fail
  1312. f1 = self.cpu.get_float_value(deadframe, 0)
  1313. f2 = self.cpu.get_float_value(deadframe, 1)
  1314. f3 = self.cpu.get_float_value(deadframe, 2)
  1315. assert longlong.getrealfloat(f1) == 132.25
  1316. assert longlong.getrealfloat(f2) == 0.75
  1317. assert longlong.getrealfloat(f3) == 133.0
  1318. bridge = parse("""
  1319. [f1, f2, f3]
  1320. i0 = same_as_i(0)
  1321. guard_true(i0, descr=faildescr1) [f1, f2, f3]
  1322. finish(descr=faildescr2)
  1323. """, namespace=locals())
  1324. self.cpu.compile_bridge(loop.operations[-2].getdescr(),
  1325. bridge.inputargs, bridge.operations,
  1326. looptoken)
  1327. args = [1,
  1328. longlong.getfloatstorage(132.25),
  1329. longlong.getfloatstorage(0.75)]
  1330. deadframe = self.cpu.execute_token(looptoken, *args)
  1331. fail = self.cpu.get_latest_descr(deadframe)
  1332. assert fail.identifier == 100
  1333. f1 = self.cpu.get_float_value(deadframe, 0)
  1334. f2 = self.cpu.get_float_value(deadframe, 1)
  1335. f3 = self.cpu.get_float_value(deadframe, 2)
  1336. assert longlong.getrealfloat(f1) == 132.25
  1337. assert longlong.getrealfloat(f2) == 0.75
  1338. assert longlong.getrealfloat(f3) == 133.0
  1339. def test_integers_and_guards2(self, extra_op=False):
  1340. for opname, compare in [
  1341. (rop.INT_IS_TRUE, lambda x: bool(x)),
  1342. (rop.INT_IS_ZERO, lambda x: not bool(x))]:
  1343. for opguard, guard_case in [
  1344. (rop.GUARD_FALSE, False),
  1345. (rop.GUARD_TRUE, True),
  1346. ]:
  1347. box = InputArgInt()
  1348. faildescr1 = BasicFailDescr(1)
  1349. faildescr2 = BasicFinalDescr(2)
  1350. inputargs = [box]
  1351. op0 = ResOperation(opname, [box])
  1352. op1 = ResOperation(opguard, [op0], descr=faildescr1)
  1353. op2 = ResOperation(rop.FINISH, [], descr=faildescr2)
  1354. operations = [op0, op1, op2]
  1355. if extra_op:
  1356. operations.insert(1, ResOperation(rop.SAME_AS_I,
  1357. [ConstInt(42)]))
  1358. op1.setfailargs([])
  1359. looptoken = JitCellToken()
  1360. self.cpu.compile_loop(inputargs, operations, looptoken)
  1361. #
  1362. for value in [-42, 0, 1, 10]:
  1363. deadframe = self.cpu.execute_token(looptoken, value)
  1364. fail = self.cpu.get_latest_descr(deadframe)
  1365. #
  1366. expected = compare(value)
  1367. expected ^= guard_case
  1368. assert fail.identifier == 2 - expected
  1369. def test_integers_and_guards2_x(self):
  1370. self.test_integers_and_guards2(extra_op=True)
  1371. def test_integers_and_guards(self, extra_op=False):
  1372. for opname, compare in [
  1373. (rop.INT_LT, lambda x, y: x < y),
  1374. (rop.INT_LE, lambda x, y: x <= y),
  1375. (rop.INT_EQ, lambda x, y: x == y),
  1376. (rop.INT_NE, lambda x, y: x != y),
  1377. (rop.INT_GT, lambda x, y: x > y),
  1378. (rop.INT_GE, lambda x, y: x >= y),
  1379. ]:
  1380. for opguard, guard_case in [
  1381. (rop.GUARD_FALSE, False),
  1382. (rop.GUARD_TRUE, True),
  1383. ]:
  1384. for combinaison in ["bb", "bc", "cb"]:
  1385. #
  1386. if combinaison[0] == 'b':
  1387. ibox1 = InputArgInt()
  1388. else:
  1389. ibox1 = ConstInt(-42)
  1390. if combinaison[1] == 'b':
  1391. ibox2 = InputArgInt()
  1392. else:
  1393. ibox2 = ConstInt(-42)
  1394. faildescr1 = BasicFailDescr(1)
  1395. faildescr2 = BasicFinalDescr(2)
  1396. inputargs = [ib for ib in [ibox1, ibox2]
  1397. if isinstance(ib, InputArgInt)]
  1398. op0 = ResOperation(opname, [ibox1, ibox2])
  1399. op1 = ResOperation(opguard, [op0], descr=faildescr1)
  1400. op2 = ResOperation(rop.FINISH, [], descr=faildescr2)
  1401. operations = [op0, op1, op2]
  1402. if extra_op:
  1403. operations.insert(1, ResOperation(rop.SAME_AS_I,
  1404. [ConstInt(42)]))
  1405. operations[-2].setfailargs([])
  1406. looptoken = JitCellToken()
  1407. self.cpu.compile_loop(inputargs, operations, looptoken)
  1408. #
  1409. for test1 in [-65, -42, -11, 0, 1, 10]:
  1410. if test1 == -42 or combinaison[0] == 'b':
  1411. for test2 in [-65, -42, -11, 0, 1, 10]:
  1412. if test2 == -42 or combinaison[1] == 'b':
  1413. args = []
  1414. if combinaison[0] == 'b':
  1415. args.append(test1)
  1416. if combinaison[1] == 'b':
  1417. args.append(test2)
  1418. deadframe = self.cpu.execute_token(
  1419. looptoken, *args)
  1420. fail = self.cpu.get_latest_descr(deadframe)
  1421. #
  1422. expected = compare(test1, test2)
  1423. expected ^= guard_case
  1424. assert fail.identifier == 2 - expected
  1425. def test_integers_and_guards_x(self):
  1426. self.test_integers_and_guards(extra_op=True)
  1427. def test_integers_and_guards_uint(self, extra_op=False):
  1428. for opname, compare in [
  1429. (rop.UINT_LE, lambda x, y: (x) <= (y)),
  1430. (rop.UINT_GT, lambda x, y: (x) > (y)),
  1431. (rop.UINT_LT, lambda x, y: (x) < (y)),
  1432. (rop.UINT_GE, lambda x, y: (x) >= (y)),
  1433. ]:
  1434. for opguard, guard_case in [
  1435. (rop.GUARD_FALSE, False),
  1436. (rop.GUARD_TRUE, True),
  1437. ]:
  1438. for combinaison in ["bb", "bc", "cb"]:
  1439. #
  1440. if combinaison[0] == 'b':
  1441. ibox1 = InputArgInt()
  1442. else:
  1443. ibox1 = ConstInt(42)
  1444. if combinaison[1] == 'b':
  1445. ibox2 = InputArgInt()
  1446. else:
  1447. ibox2 = ConstInt(42)
  1448. faildescr1 = BasicFailDescr(1)
  1449. faildescr2 = BasicFinalDescr(2)
  1450. inputargs = [ib for ib in [ibox1, ibox2]
  1451. if isinstance(ib, InputArgInt)]
  1452. op0 = ResOperation(opname, [ibox1, ibox2])
  1453. op1 = ResOperation(opguard, [op0], descr=faildescr1)
  1454. op2 = ResOperation(rop.FINISH, [], descr=faildescr2)
  1455. operations = [op0, op1, op2]
  1456. if extra_op:
  1457. operations.insert(1, ResOperation(rop.SAME_AS_I,
  1458. [ConstInt(42)]))
  1459. operations[-2].setfailargs([])
  1460. looptoken = JitCellToken()
  1461. self.cpu.compile_loop(inputargs, operations, looptoken)
  1462. #
  1463. for test1 in [65, 42, 11, 0, 1]:
  1464. if test1 == 42 or combinaison[0] == 'b':
  1465. for test2 in [65, 42, 11, 0, 1]:
  1466. if test2 == 42 or combinaison[1] == 'b':
  1467. args = []
  1468. if combinaison[0] == 'b':
  1469. args.append(test1)
  1470. if combinaison[1] == 'b':
  1471. args.append(test2)
  1472. deadframe = self.cpu.execute_token(
  1473. looptoken, *args)
  1474. fail = self.cpu.get_latest_descr(deadframe)
  1475. #
  1476. expected = compare(test1, test2)
  1477. expected ^= guard_case
  1478. assert fail.identifier == 2 - expected
  1479. def test_integers_and_guards_uint_x(self):
  1480. self.test_integers_and_guards_uint(extra_op=True)
  1481. def test_floats_and_guards(self, extra_op=False):
  1482. if not self.cpu.supports_floats:
  1483. py.test.skip("requires floats")
  1484. for opname, compare in [
  1485. (rop.FLOAT_LT, lambda x, y: x < y),
  1486. (rop.FLOAT_LE, lambda x, y: x <= y),
  1487. (rop.FLOAT_EQ, lambda x, y: x == y),
  1488. (rop.FLOAT_NE, lambda x, y: x != y),
  1489. (rop.FLOAT_GT, lambda x, y: x > y),
  1490. (rop.FLOAT_GE, lambda x, y: x >= y),
  1491. ]:
  1492. for opguard, guard_case in [
  1493. (rop.GUARD_FALSE, False),
  1494. (rop.GUARD_TRUE, True),
  1495. ]:
  1496. for combinaison in ["bb", "bc", "cb"]:
  1497. #
  1498. if combinaison[0] == 'b':
  1499. fbox1 = InputArgFloat()
  1500. else:
  1501. fbox1 = constfloat(-4.5)
  1502. if combinaison[1] == 'b':
  1503. fbox2 = InputArgFloat()
  1504. else:
  1505. fbox2 = constfloat(-4.5)
  1506. faildescr1 = BasicFailDescr(1)
  1507. faildescr2 = BasicFinalDescr(2)
  1508. inputargs = [fb for fb in [fbox1, fbox2]
  1509. if not isinstance(fb, Const)]
  1510. op0 = ResOperation(opname, [fbox1, fbox2])
  1511. op1 = ResOperation(opguard, [op0], descr=faildescr1)
  1512. op2 = ResOperation(rop.FINISH, [], descr=faildescr2)
  1513. operations = [op0, op1, op2]
  1514. if extra_op:
  1515. operations.insert(1, ResOperation(rop.SAME_AS_I,
  1516. [ConstInt(42)]))
  1517. operations[-2].setfailargs([])
  1518. looptoken = JitCellToken()
  1519. self.cpu.compile_loop(inputargs, operations, looptoken)
  1520. #
  1521. nan = 1e200 * 1e200
  1522. nan /= nan
  1523. for test1 in [-6.5, -4.5, -2.5, nan]:
  1524. if test1 == -4.5 or combinaison[0] == 'b':
  1525. for test2 in [-6.5, -4.5, -2.5, nan]:
  1526. if test2 == -4.5 or combinaison[1] == 'b':
  1527. args = []
  1528. if combinaison[0] == 'b':
  1529. args.append(
  1530. longlong.getfloatstorage(test1))
  1531. if combinaison[1] == 'b':
  1532. args.append(
  1533. longlong.getfloatstorage(test2))
  1534. deadframe = self.cpu.execute_token(
  1535. looptoken, *args)
  1536. fail = self.cpu.get_latest_descr(deadframe)
  1537. #
  1538. expected = compare(test1, test2)
  1539. expected ^= guard_case
  1540. assert fail.identifier == 2 - expected
  1541. def test_floats_and_guards_x(self):
  1542. self.test_floats_and_guards(extra_op=True)
  1543. def test_unused_result_int(self):
  1544. # test pure operations on integers whose result is not used
  1545. from rpython.jit.metainterp.test.test_executor import get_int_tests
  1546. int_tests = list(get_int_tests())
  1547. int_tests = [(opnum, boxargs, 'int', retvalue)
  1548. for opnum, boxargs, retvalue in int_tests]
  1549. self._test_unused_result(int_tests)
  1550. def test_unused_result_float(self):
  1551. # same as test_unused_result_int, for float operations
  1552. from rpython.jit.metainterp.test.test_executor import get_float_tests
  1553. float_tests = list(get_float_tests(self.cpu))
  1554. self._test_unused_result(float_tests)
  1555. def _test_unused_result(self, tests):
  1556. while len(tests) > 50: # only up to 50 tests at once
  1557. self._test_unused_result(tests[:50])
  1558. tests = tests[50:]
  1559. inputargs = []
  1560. operations = []
  1561. for opnum, boxargs, rettype, retvalue in tests:
  1562. inputargs += [box for box in boxargs if not isinstance(box, Const)]
  1563. operations.append(ResOperation(opnum, boxargs))
  1564. # Unique-ify inputargs
  1565. inputargs = list(set(inputargs))
  1566. faildescr = BasicFinalDescr(1)
  1567. operations.append(ResOperation(rop.FINISH, [], descr=faildescr))
  1568. looptoken = JitCellToken()
  1569. #
  1570. self.cpu.compile_loop(inputargs, operations, looptoken)
  1571. #
  1572. args = []
  1573. for box in inputargs:
  1574. if isinstance(box, InputArgInt):
  1575. args.append(box.getint())
  1576. elif isinstance(box, InputArgFloat):
  1577. args.append(box.getfloatstorage())
  1578. else:
  1579. assert 0
  1580. #
  1581. deadframe = self.cpu.execute_token(looptoken, *args)
  1582. fail = self.cpu.get_latest_descr(deadframe)
  1583. assert fail.identifier == 1
  1584. def test_nan_and_infinity(self):
  1585. if not self.cpu.supports_floats:
  1586. py.test.skip("requires floats")
  1587. from rpython.rlib.rfloat import INFINITY, NAN, isinf, isnan
  1588. from rpython.jit.metainterp.resoperation import opname
  1589. fzer = 0.0
  1590. fone = 1.0
  1591. fmqr = -0.25
  1592. finf = INFINITY
  1593. fmnf = -INFINITY
  1594. fnan = NAN
  1595. all_cases_unary = [(a,) for a in [fzer,fone,fmqr,finf,fmnf,fnan]]
  1596. all_cases_binary = [(a, b) for a in [fzer,fone,fmqr,finf,fmnf,fnan]
  1597. for b in [fzer,fone,fmqr,finf,fmnf,fnan]]
  1598. no_zero_divison = [(a, b) for a in [fzer,fone,fmqr,finf,fmnf,fnan]
  1599. for b in [ fone,fmqr,finf,fmnf,fnan]]
  1600. def nan_and_infinity(opnum, realoperation, testcases):
  1601. for testcase in testcases:
  1602. expected = realoperation(*testcase)
  1603. inputargs = [boxfloat(x) for x in testcase]
  1604. if isinstance(expected, float):
  1605. expectedtype = 'float'
  1606. else:
  1607. expectedtype = 'int'
  1608. got = self.execute_operation(opnum, inputargs,
  1609. expectedtype)
  1610. if not isinstance(expected, bool):
  1611. got = longlong.getrealfloat(got)
  1612. if isnan(expected):
  1613. ok = isnan(got)
  1614. elif isinf(expected):
  1615. ok = isinf(got)
  1616. else:
  1617. ok = got == expected
  1618. if not ok:
  1619. raise AssertionError("%s(%s): got %r, expected %r" % (
  1620. opname[opnum], ', '.join(map(repr, testcase)),
  1621. got, expected))
  1622. # if we expect a boolean, also check the combination with
  1623. # a GUARD_TRUE or GUARD_FALSE
  1624. if isinstance(expected, bool):
  1625. for extra_op in (False, True):
  1626. for guard_opnum, expected_id in [(rop.GUARD_TRUE, 1),
  1627. (rop.GUARD_FALSE, 0)]:
  1628. op0 = ResOperation(opnum, inputargs)
  1629. op1 = ResOperation(guard_opnum, [op0],
  1630. descr=BasicFailDescr(4))
  1631. op2 = ResOperation(rop.FINISH, [],
  1632. descr=BasicFinalDescr(5))
  1633. operations = [op0, op1, op2]
  1634. if extra_op:
  1635. operations.insert(1, ResOperation(rop.SAME_AS_I,
  1636. [ConstInt(42)]))
  1637. operations[-2].setfailargs([])
  1638. looptoken = JitCellToken()
  1639. # Use "set" to unique-ify inputargs
  1640. unique_testcase_list = list(set(inputargs))
  1641. self.cpu.compile_loop(unique_testcase_list, operations,
  1642. looptoken)
  1643. args = [box.getfloatstorage() for box in
  1644. unique_testcase_list]
  1645. deadframe = self.cpu.execute_token(looptoken, *args)
  1646. fail = self.cpu.get_latest_descr(deadframe)
  1647. if fail.identifier != 5 - (expected_id^expected):
  1648. if fail.identifier == 4:
  1649. msg = "was taken"
  1650. else:
  1651. msg = "was not taken"
  1652. raise AssertionError(
  1653. "%s(%s)/%s took the wrong path: "
  1654. "the failure path of the guard %s" % (
  1655. opname[opnum],
  1656. ', '.join(map(repr, testcase)),
  1657. opname[guard_opnum], msg))
  1658. yield nan_and_infinity, rop.FLOAT_ADD, operator.add, all_cases_binary
  1659. yield nan_and_infinity, rop.FLOAT_SUB, operator.sub, all_cases_binary
  1660. yield nan_and_infinity, rop.FLOAT_MUL, operator.mul, all_cases_binary
  1661. yield nan_and_infinity, rop.FLOAT_TRUEDIV, \
  1662. operator.truediv, no_zero_divison
  1663. yield nan_and_infinity, rop.FLOAT_NEG, operator.neg, all_cases_unary
  1664. yield nan_and_infinity, rop.FLOAT_ABS, abs, all_cases_unary
  1665. yield nan_and_infinity, rop.FLOAT_LT, operator.lt, all_cases_binary
  1666. yield nan_and_infinity, rop.FLOAT_LE, operator.le, all_cases_binary
  1667. yield nan_and_infinity, rop.FLOAT_EQ, operator.eq, all_cases_binary
  1668. yield nan_and_infinity, rop.FLOAT_NE, operator.ne, all_cases_binary
  1669. yield nan_and_infinity, rop.FLOAT_GT, operator.gt, all_cases_binary
  1670. yield nan_and_infinity, rop.FLOAT_GE, operator.ge, all_cases_binary
  1671. def test_noops(self):
  1672. c_box = wrap_constant(self.alloc_string("hi there").getref_base())
  1673. c_nest = ConstInt(0)
  1674. c_id = ConstInt(0)
  1675. self.execute_operation(rop.DEBUG_MERGE_POINT, [c_box, c_nest, c_id, c_nest], 'void')
  1676. self.execute_operation(rop.JIT_DEBUG, [c_box, c_nest, c_nest,
  1677. c_nest, c_nest], 'void')
  1678. def test_read_timestamp(self):
  1679. if IS_32_BIT and not self.cpu.supports_longlong:
  1680. py.test.skip("read_timestamp returns a longlong")
  1681. if sys.platform == 'win32':
  1682. # windows quite often is very inexact (like the old Intel 8259 PIC),
  1683. # so we stretch the time a little bit.
  1684. # On my virtual Parallels machine in a 2GHz Core i7 Mac Mini,
  1685. # the test starts working at delay == 21670 and stops at 20600000.
  1686. # We take the geometric mean value.
  1687. from math import log, exp
  1688. delay_min = 21670
  1689. delay_max = 20600000
  1690. delay = int(exp((log(delay_min)+log(delay_max))/2))
  1691. def wait_a_bit():
  1692. for i in xrange(delay): pass
  1693. else:
  1694. def wait_a_bit():
  1695. pass
  1696. from rpython.jit.codewriter.effectinfo import EffectInfo
  1697. from rpython.rlib import rtimer
  1698. effectinfo = EffectInfo([], [], [], [], [], [],
  1699. EffectInfo.EF_CANNOT_RAISE,
  1700. EffectInfo.OS_MATH_READ_TIMESTAMP)
  1701. FPTR = self.Ptr(self.FuncType([], lltype.SignedLongLong))
  1702. func_ptr = llhelper(FPTR, rtimer.read_timestamp)
  1703. FUNC = deref(FPTR)
  1704. funcbox = self.get_funcbox(self.cpu, func_ptr)
  1705. calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, effectinfo)
  1706. if longlong.is_64_bit:
  1707. res1 = self.execute_operation(rop.CALL_I, [funcbox], 'int', calldescr)
  1708. wait_a_bit()
  1709. res2 = self.execute_operation(rop.CALL_I, [funcbox], 'int', calldescr)
  1710. else:
  1711. res1 = self.execute_operation(rop.CALL_F, [funcbox],'float',calldescr)
  1712. wait_a_bit()
  1713. res2 = self.execute_operation(rop.CALL_F, [funcbox],'float',calldescr)
  1714. assert res1 < res2 < res1 + 2**32
  1715. class LLtypeBackendTest(BaseBackendTest):
  1716. Ptr = lltype.Ptr
  1717. FuncType = lltype.FuncType
  1718. malloc = staticmethod(lltype.malloc)
  1719. nullptr = staticmethod(lltype.nullptr)
  1720. @classmethod
  1721. def get_funcbox(cls, cpu, func_ptr):
  1722. addr = llmemory.cast_ptr_to_adr(func_ptr)
  1723. return ConstInt(heaptracker.adr2int(addr))
  1724. MY_VTABLE = rclass.OBJECT_VTABLE # for tests only
  1725. S = lltype.GcForwardReference()
  1726. S.become(lltype.GcStruct('S', ('parent', rclass.OBJECT),
  1727. ('value', lltype.Signed),
  1728. ('chr1', lltype.Char),
  1729. ('chr2', lltype.Char),
  1730. ('short', rffi.SHORT),
  1731. ('next', lltype.Ptr(S)),
  1732. ('float', lltype.Float)))
  1733. T = lltype.GcStruct('T', ('parent', S),
  1734. ('next', lltype.Ptr(S)))
  1735. U = lltype.GcStruct('U', ('parent', T),
  1736. ('next', lltype.Ptr(S)))
  1737. def alloc_instance(self, T):
  1738. if hasattr(T, 'parent'):
  1739. vtable_for_T = lltype.malloc(self.MY_VTABLE, immortal=True)
  1740. vtable_for_T_addr = llmemory.cast_ptr_to_adr(vtable_for_T)
  1741. else:
  1742. vtable_for_T = lltype.nullptr(rclass.OBJECT_VTABLE)
  1743. cpu = self.cpu
  1744. class FakeGCCache(object):
  1745. pass
  1746. if hasattr(cpu, 'gc_ll_descr'):
  1747. if not hasattr(cpu.gc_ll_descr, '_cache_gcstruct2vtable'):
  1748. cpu.gc_ll_descr._cache_gcstruct2vtable = {}
  1749. cpu.gc_ll_descr._cache_gcstruct2vtable.update({T: vtable_for_T})
  1750. p = T
  1751. while hasattr(p, 'parent'):
  1752. vtable_for_parent = lltype.malloc(self.MY_VTABLE, immortal=True)
  1753. cpu.gc_ll_descr._cache_gcstruct2vtable[p.parent] = vtable_for_parent
  1754. p = p.parent
  1755. else:
  1756. descr = cpu.sizeof(T, vtable_for_T)
  1757. t = lltype.malloc(T)
  1758. if T == self.T:
  1759. t.parent.parent.typeptr = vtable_for_T
  1760. elif T == self.U:
  1761. t.parent.parent.parent.typeptr = vtable_for_T
  1762. t_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, t))
  1763. if not hasattr(T, 'parent'):
  1764. vtable = lltype.nullptr(rclass.OBJECT_VTABLE)
  1765. T_box = None
  1766. else:
  1767. vtable = vtable_for_T
  1768. T_box = ConstInt(heaptracker.adr2int(vtable_for_T_addr))
  1769. descr = cpu.sizeof(T, vtable)
  1770. return t_box, T_box, descr
  1771. def null_instance(self):
  1772. return InputArgRef(lltype.nullptr(llmemory.GCREF.TO))
  1773. def alloc_array_of(self, ITEM, length):
  1774. A = lltype.GcArray(ITEM)
  1775. a = lltype.malloc(A, length)
  1776. a_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, a))
  1777. return a_box, A
  1778. def alloc_string(self, string):
  1779. s = rstr.mallocstr(len(string))
  1780. for i in range(len(string)):
  1781. s.chars[i] = string[i]
  1782. s_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, s))
  1783. return s_box
  1784. def look_string(self, string_box):
  1785. s = string_box.getref(lltype.Ptr(rstr.STR))
  1786. return ''.join(s.chars)
  1787. def alloc_unicode(self, unicode):
  1788. u = rstr.mallocunicode(len(unicode))
  1789. for i in range(len(unicode)):
  1790. u.chars[i] = unicode[i]
  1791. u_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, u))
  1792. return u_box
  1793. def look_unicode(self, unicode_box):
  1794. u = unicode_box.getref(lltype.Ptr(rstr.UNICODE))
  1795. return u''.join(u.chars)
  1796. def test_cast_int_to_ptr(self):
  1797. res = self.execute_operation(rop.CAST_INT_TO_PTR,
  1798. [InputArgInt(-17)], 'ref')
  1799. assert lltype.cast_ptr_to_int(res) == -17
  1800. def test_cast_ptr_to_int(self):
  1801. x = lltype.cast_int_to_ptr(llmemory.GCREF, -19)
  1802. res = self.execute_operation(rop.CAST_PTR_TO_INT,
  1803. [InputArgRef(x)], 'int')
  1804. assert res == -19
  1805. def test_cast_int_to_float(self):
  1806. if not self.cpu.supports_floats:
  1807. py.test.skip("requires floats")
  1808. for x in [-10, -1, 0, 3, 42, sys.maxint-1]:
  1809. res = self.execute_operation(rop.CAST_INT_TO_FLOAT,
  1810. [InputArgInt(x)], 'float')
  1811. assert longlong.getrealfloat(res) == float(x)
  1812. # --- the front-end never generates CAST_INT_TO_FLOAT(Const)
  1813. #res = self.execute_operation(rop.CAST_INT_TO_FLOAT,
  1814. # [ConstInt(x)], 'float').value
  1815. #assert longlong.getrealfloat(res) == float(x)
  1816. def test_cast_float_to_int(self):
  1817. if not self.cpu.supports_floats:
  1818. py.test.skip("requires floats")
  1819. for x in [-24.23, -5.3, 0.0, 3.1234, 11.1, 0.1]:
  1820. v = longlong.getfloatstorage(x)
  1821. res = self.execute_operation(rop.CAST_FLOAT_TO_INT,
  1822. [InputArgFloat(v)], 'int')
  1823. assert res == int(x)
  1824. # --- the front-end never generates CAST_FLOAT_TO_INT(Const)
  1825. #res = self.execute_operation(rop.CAST_FLOAT_TO_INT,
  1826. # [ConstFloat(v)], 'int').value
  1827. #assert res == int(x)
  1828. def test_convert_float_bytes(self):
  1829. if not self.cpu.supports_floats:
  1830. py.test.skip("requires floats")
  1831. if IS_32_BIT and not self.cpu.supports_longlong:
  1832. py.test.skip("longlong test")
  1833. t = 'int' if longlong.is_64_bit else 'float'
  1834. res = self.execute_operation(rop.CONVERT_FLOAT_BYTES_TO_LONGLONG,
  1835. [boxfloat(2.5)], t)
  1836. assert res == longlong2float.float2longlong(2.5)
  1837. bytes = longlong2float.float2longlong(2.5)
  1838. res = self.execute_operation(rop.CONVERT_LONGLONG_BYTES_TO_FLOAT,
  1839. [boxlonglong(bytes)], 'float')
  1840. assert longlong.getrealfloat(res) == 2.5
  1841. def test_ooops_non_gc(self):
  1842. x = lltype.malloc(lltype.Struct('x'), flavor='raw')
  1843. v = heaptracker.adr2int(llmemory.cast_ptr_to_adr(x))
  1844. r = self.execute_operation(rop.PTR_EQ, [InputArgInt(v), InputArgInt(v)], 'int')
  1845. assert r == 1
  1846. r = self.execute_operation(rop.PTR_NE, [InputArgInt(v), InputArgInt(v)], 'int')
  1847. assert r == 0
  1848. lltype.free(x, flavor='raw')
  1849. def test_new_plain_struct(self):
  1850. cpu = self.cpu
  1851. S = lltype.GcStruct('S', ('x', lltype.Char), ('y', lltype.Char))
  1852. sizedescr = cpu.sizeof(S)
  1853. r1 = self.execute_operation(rop.NEW, [], 'ref', descr=sizedescr)
  1854. r2 = self.execute_operation(rop.NEW, [], 'ref', descr=sizedescr)
  1855. assert r1 != r2
  1856. xdescr = cpu.fielddescrof(S, 'x')
  1857. ydescr = cpu.fielddescrof(S, 'y')
  1858. self.execute_operation(rop.SETFIELD_GC, [InputArgRef(r1),
  1859. InputArgInt(150)],
  1860. 'void', descr=ydescr)
  1861. self.execute_operation(rop.SETFIELD_GC, [InputArgRef(r1),
  1862. InputArgInt(190)],
  1863. 'void', descr=xdescr)
  1864. s = lltype.cast_opaque_ptr(lltype.Ptr(S), r1)
  1865. assert s.x == chr(190)
  1866. assert s.y == chr(150)
  1867. def test_new_with_vtable(self):
  1868. cpu = self.cpu
  1869. t_box, T_box, descr = self.alloc_instance(self.T)
  1870. vtable = llmemory.cast_adr_to_ptr(
  1871. llmemory.cast_int_to_adr(T_box.getint()), rclass.CLASSTYPE)
  1872. r1 = self.execute_operation(rop.NEW_WITH_VTABLE, [], 'ref', descr)
  1873. r2 = self.execute_operation(rop.NEW_WITH_VTABLE, [], 'ref', descr)
  1874. assert r1 != r2
  1875. descr1 = cpu.fielddescrof(self.S, 'chr1')
  1876. descr2 = cpu.fielddescrof(self.S, 'chr2')
  1877. descrshort = cpu.fielddescrof(self.S, 'short')
  1878. descrshort.parent_descr.vtable = vtable
  1879. self.execute_operation(rop.SETFIELD_GC, [InputArgRef(r1),
  1880. InputArgInt(150)],
  1881. 'void', descr=descr2)
  1882. self.execute_operation(rop.SETFIELD_GC, [InputArgRef(r1),
  1883. InputArgInt(190)],
  1884. 'void', descr=descr1)
  1885. self.execute_operation(rop.SETFIELD_GC, [InputArgRef(r1),
  1886. InputArgInt(1313)],
  1887. 'void', descr=descrshort)
  1888. s = lltype.cast_opaque_ptr(lltype.Ptr(self.T), r1)
  1889. assert s.parent.chr1 == chr(190)
  1890. assert s.parent.chr2 == chr(150)
  1891. r = self.cpu.bh_getfield_gc_i(r1, descrshort)
  1892. assert r == 1313
  1893. self.cpu.bh_setfield_gc_i(r1, 1333, descrshort)
  1894. r = self.cpu.bh_getfield_gc_i(r1, descrshort)
  1895. assert r == 1333
  1896. r = self.execute_operation(rop.GETFIELD_GC_I, [InputArgRef(r1)], 'int',
  1897. descr=descrshort)
  1898. assert r == 1333
  1899. t = lltype.cast_opaque_ptr(lltype.Ptr(self.T), t_box.getref_base())
  1900. assert s.parent.parent.typeptr == t.parent.parent.typeptr
  1901. def test_new_array(self):
  1902. A = lltype.GcArray(lltype.Signed)
  1903. arraydescr = self.cpu.arraydescrof(A)
  1904. r1 = self.execute_operation(rop.NEW_ARRAY, [InputArgInt(342)],
  1905. 'ref', descr=arraydescr)
  1906. r2 = self.execute_operation(rop.NEW_ARRAY, [InputArgInt(342)],
  1907. 'ref', descr=arraydescr)
  1908. assert r1 != r2
  1909. a = lltype.cast_opaque_ptr(lltype.Ptr(A), r1)
  1910. assert len(a) == 342
  1911. def test_new_array_clear(self):
  1912. A = lltype.GcArray(lltype.Signed)
  1913. arraydescr = self.cpu.arraydescrof(A)
  1914. r1 = self.execute_operation(rop.NEW_ARRAY_CLEAR, [InputArgInt(342)],
  1915. 'ref', descr=arraydescr)
  1916. a = lltype.cast_opaque_ptr(lltype.Ptr(A), r1)
  1917. assert a[0] == 0
  1918. assert len(a) == 342
  1919. def test_new_string(self):
  1920. r1 = self.execute_operation(rop.NEWSTR, [InputArgInt(342)], 'ref')
  1921. r2 = self.execute_operation(rop.NEWSTR, [InputArgInt(342)], 'ref')
  1922. assert r1 != r2
  1923. a = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), r1)
  1924. assert len(a.chars) == 342
  1925. def test_new_unicode(self):
  1926. r1 = self.execute_operation(rop.NEWUNICODE, [InputArgInt(342)], 'ref')
  1927. r2 = self.execute_operation(rop.NEWUNICODE, [InputArgInt(342)], 'ref')
  1928. assert r1 != r2
  1929. a = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), r1)
  1930. assert len(a.chars) == 342
  1931. def test_exceptions(self):
  1932. exc_tp = None
  1933. exc_ptr = None
  1934. def func(i):
  1935. if i:
  1936. raise LLException(exc_tp, exc_ptr)
  1937. ops = '''
  1938. [i0]
  1939. i1 = same_as_i(1)
  1940. call_n(ConstClass(fptr), i0, descr=calldescr)
  1941. p0 = guard_exception(ConstClass(xtp)) [i1]
  1942. finish(p0)
  1943. '''
  1944. FPTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void))
  1945. fptr = llhelper(FPTR, func)
  1946. calldescr = self.cpu.calldescrof(FPTR.TO, FPTR.TO.ARGS, FPTR.TO.RESULT,
  1947. EffectInfo.MOST_GENERAL)
  1948. xtp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
  1949. xtp.subclassrange_min = 1
  1950. xtp.subclassrange_max = 3
  1951. X = lltype.GcStruct('X', ('parent', rclass.OBJECT),
  1952. hints={'vtable': xtp._obj})
  1953. xptr = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(X))
  1954. exc_tp = xtp
  1955. exc_ptr = xptr
  1956. loop = parse(ops, self.cpu, namespace=locals())
  1957. looptoken = JitCellToken()
  1958. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  1959. deadframe = self.cpu.execute_token(looptoken, 1)
  1960. assert self.cpu.get_ref_value(deadframe, 0) == xptr
  1961. excvalue = self.cpu.grab_exc_value(deadframe)
  1962. assert not excvalue
  1963. deadframe = self.cpu.execute_token(looptoken, 0)
  1964. assert self.cpu.get_int_value(deadframe, 0) == 1
  1965. excvalue = self.cpu.grab_exc_value(deadframe)
  1966. assert not excvalue
  1967. ytp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
  1968. ytp.subclassrange_min = 2
  1969. ytp.subclassrange_max = 2
  1970. assert rclass.ll_issubclass(ytp, xtp)
  1971. Y = lltype.GcStruct('Y', ('parent', rclass.OBJECT),
  1972. hints={'vtable': ytp._obj})
  1973. yptr = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(Y))
  1974. # guard_exception uses an exact match
  1975. exc_tp = ytp
  1976. exc_ptr = yptr
  1977. loop = parse(ops, self.cpu, namespace=locals())
  1978. looptoken = JitCellToken()
  1979. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  1980. deadframe = self.cpu.execute_token(looptoken, 1)
  1981. assert self.cpu.get_int_value(deadframe, 0) == 1
  1982. excvalue = self.cpu.grab_exc_value(deadframe)
  1983. assert excvalue == yptr
  1984. exc_tp = xtp
  1985. exc_ptr = xptr
  1986. ops = '''
  1987. [i0]
  1988. i1 = same_as_i(1)
  1989. call_n(ConstClass(fptr), i0, descr=calldescr)
  1990. guard_no_exception() [i1]
  1991. finish(0)
  1992. '''
  1993. loop = parse(ops, self.cpu, namespace=locals())
  1994. looptoken = JitCellToken()
  1995. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  1996. deadframe = self.cpu.execute_token(looptoken, 1)
  1997. assert self.cpu.get_int_value(deadframe, 0) == 1
  1998. excvalue = self.cpu.grab_exc_value(deadframe)
  1999. assert excvalue == xptr
  2000. deadframe = self.cpu.execute_token(looptoken, 0)
  2001. assert self.cpu.get_int_value(deadframe, 0) == 0
  2002. excvalue = self.cpu.grab_exc_value(deadframe)
  2003. assert not excvalue
  2004. def test_save_restore_exceptions(self):
  2005. exc_tp = None
  2006. exc_ptr = None
  2007. def func(i):
  2008. if hasattr(self.cpu, '_exception_emulator'):
  2009. assert not self.cpu._exception_emulator[0]
  2010. assert not self.cpu._exception_emulator[1]
  2011. called.append(i)
  2012. if i:
  2013. raise LLException(exc_tp, exc_ptr)
  2014. ops = '''
  2015. [i0]
  2016. i1 = same_as_i(1)
  2017. call_n(ConstClass(fptr), i0, descr=calldescr)
  2018. i2 = save_exc_class()
  2019. p2 = save_exception()
  2020. call_n(ConstClass(fptr), 0, descr=calldescr)
  2021. restore_exception(i2, p2)
  2022. p0 = guard_exception(ConstClass(xtp)) [i1]
  2023. finish(p0)
  2024. '''
  2025. FPTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void))
  2026. fptr = llhelper(FPTR, func)
  2027. calldescr = self.cpu.calldescrof(FPTR.TO, FPTR.TO.ARGS, FPTR.TO.RESULT,
  2028. EffectInfo.MOST_GENERAL)
  2029. xtp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
  2030. xtp.subclassrange_min = 1
  2031. xtp.subclassrange_max = 3
  2032. X = lltype.GcStruct('X', ('parent', rclass.OBJECT),
  2033. hints={'vtable': xtp._obj})
  2034. xx = lltype.malloc(X)
  2035. xx.parent.typeptr = xtp
  2036. xptr = lltype.cast_opaque_ptr(llmemory.GCREF, xx)
  2037. exc_tp = xtp
  2038. exc_ptr = xptr
  2039. loop = parse(ops, self.cpu, namespace=locals())
  2040. looptoken = JitCellToken()
  2041. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  2042. called = []
  2043. deadframe = self.cpu.execute_token(looptoken, 5)
  2044. assert called == [5, 0]
  2045. assert self.cpu.get_ref_value(deadframe, 0) == xptr
  2046. excvalue = self.cpu.grab_exc_value(deadframe)
  2047. assert not excvalue
  2048. called = []
  2049. deadframe = self.cpu.execute_token(looptoken, 0)
  2050. assert called == [0, 0]
  2051. assert self.cpu.get_int_value(deadframe, 0) == 1
  2052. excvalue = self.cpu.grab_exc_value(deadframe)
  2053. assert not excvalue
  2054. def test_cond_call_gc_wb(self):
  2055. def func_void(a):
  2056. record.append(rffi.cast(lltype.Signed, a))
  2057. record = []
  2058. #
  2059. S = lltype.GcStruct('S', ('tid', lltype.Signed))
  2060. FUNC = self.FuncType([lltype.Ptr(S)], lltype.Void)
  2061. func_ptr = llhelper(lltype.Ptr(FUNC), func_void)
  2062. funcbox = self.get_funcbox(self.cpu, func_ptr)
  2063. class WriteBarrierDescr(AbstractDescr):
  2064. jit_wb_if_flag = 4096
  2065. jit_wb_if_flag_byteofs = struct.pack("l", 4096).index('\x10')
  2066. jit_wb_if_flag_singlebyte = 0x10
  2067. def get_write_barrier_fn(self, cpu):
  2068. return funcbox.getint()
  2069. #
  2070. for cond in [False, True]:
  2071. value = random.randrange(-sys.maxint, sys.maxint)
  2072. if cond:
  2073. value |= 4096
  2074. else:
  2075. value &= ~4096
  2076. s = lltype.malloc(S)
  2077. s.tid = value
  2078. sgcref = lltype.cast_opaque_ptr(llmemory.GCREF, s)
  2079. del record[:]
  2080. self.execute_operation(rop.COND_CALL_GC_WB,
  2081. [InputArgRef(sgcref)],
  2082. 'void', descr=WriteBarrierDescr())
  2083. if cond:
  2084. assert record == [rffi.cast(lltype.Signed, sgcref)]
  2085. else:
  2086. assert record == []
  2087. def test_cond_call_gc_wb_array(self):
  2088. def func_void(a):
  2089. record.append(rffi.cast(lltype.Signed, a))
  2090. record = []
  2091. #
  2092. S = lltype.GcStruct('S', ('tid', lltype.Signed))
  2093. FUNC = self.FuncType([lltype.Ptr(S)], lltype.Void)
  2094. func_ptr = llhelper(lltype.Ptr(FUNC), func_void)
  2095. funcbox = self.get_funcbox(self.cpu, func_ptr)
  2096. class WriteBarrierDescr(AbstractDescr):
  2097. jit_wb_if_flag = 4096
  2098. jit_wb_if_flag_byteofs = struct.pack("l", 4096).index('\x10')
  2099. jit_wb_if_flag_singlebyte = 0x10
  2100. jit_wb_cards_set = 0 # <= without card marking
  2101. def get_write_barrier_fn(self, cpu):
  2102. return funcbox.getint()
  2103. #
  2104. for cond in [False, True]:
  2105. value = random.randrange(-sys.maxint, sys.maxint)
  2106. if cond:
  2107. value |= 4096
  2108. else:
  2109. value &= ~4096
  2110. s = lltype.malloc(S)
  2111. s.tid = value
  2112. sgcref = lltype.cast_opaque_ptr(llmemory.GCREF, s)
  2113. del record[:]
  2114. self.execute_operation(rop.COND_CALL_GC_WB_ARRAY,
  2115. [InputArgRef(sgcref), ConstInt(123)],
  2116. 'void', descr=WriteBarrierDescr())
  2117. if cond:
  2118. assert record == [rffi.cast(lltype.Signed, sgcref)]
  2119. else:
  2120. assert record == []
  2121. def test_cond_call_gc_wb_array_card_marking_fast_path(self):
  2122. def func_void(a):
  2123. record.append(rffi.cast(lltype.Signed, a))
  2124. if cond == 1: # the write barrier sets the flag
  2125. s.data.tid |= 32768
  2126. record = []
  2127. #
  2128. S = lltype.Struct('S', ('tid', lltype.Signed))
  2129. S_WITH_CARDS = lltype.Struct('S_WITH_CARDS',
  2130. ('card0', lltype.Char),
  2131. ('card1', lltype.Char),
  2132. ('card2', lltype.Char),
  2133. ('card3', lltype.Char),
  2134. ('card4', lltype.Char),
  2135. ('card5', lltype.Char),
  2136. ('card6', lltype.Char),
  2137. ('card7', lltype.Char),
  2138. ('data', S))
  2139. FUNC = self.FuncType([lltype.Ptr(S)], lltype.Void)
  2140. func_ptr = llhelper(lltype.Ptr(FUNC), func_void)
  2141. funcbox = self.get_funcbox(self.cpu, func_ptr)
  2142. class WriteBarrierDescr(AbstractDescr):
  2143. jit_wb_if_flag = 4096
  2144. jit_wb_if_flag_byteofs = struct.pack("l", 4096).index('\x10')
  2145. jit_wb_if_flag_singlebyte = 0x10
  2146. jit_wb_cards_set = 32768
  2147. jit_wb_cards_set_byteofs = struct.pack("l", 32768).index('\x80')
  2148. jit_wb_cards_set_singlebyte = -0x80
  2149. jit_wb_card_page_shift = 7
  2150. def get_write_barrier_from_array_fn(self, cpu):
  2151. return funcbox.getint()
  2152. #
  2153. for BoxIndexCls in [InputArgInt, ConstInt]*3:
  2154. for cond in [-1, 0, 1, 2]:
  2155. # cond=-1:GCFLAG_TRACK_YOUNG_PTRS, GCFLAG_CARDS_SET are not set
  2156. # cond=0: GCFLAG_CARDS_SET is never set
  2157. # cond=1: GCFLAG_CARDS_SET is not set, but the wb sets it
  2158. # cond=2: GCFLAG_CARDS_SET is already set
  2159. print
  2160. print '_'*79
  2161. print 'BoxIndexCls =', BoxIndexCls
  2162. print 'testing cond =', cond
  2163. print
  2164. value = random.randrange(-sys.maxint, sys.maxint)
  2165. if cond >= 0:
  2166. value |= 4096
  2167. else:
  2168. value &= ~4096
  2169. if cond == 2:
  2170. value |= 32768
  2171. else:
  2172. value &= ~32768
  2173. s = lltype.malloc(S_WITH_CARDS, immortal=True, zero=True)
  2174. s.data.tid = value
  2175. sgcref = rffi.cast(llmemory.GCREF, s.data)
  2176. del record[:]
  2177. box_index = BoxIndexCls((9<<7) + 17)
  2178. self.execute_operation(rop.COND_CALL_GC_WB_ARRAY,
  2179. [InputArgRef(sgcref), box_index],
  2180. 'void', descr=WriteBarrierDescr())
  2181. if cond in [0, 1]:
  2182. assert record == [rffi.cast(lltype.Signed, s.data)]
  2183. else:
  2184. assert record == []
  2185. if cond in [1, 2]:
  2186. assert s.card6 == '\x02'
  2187. else:
  2188. assert s.card6 == '\x00'
  2189. assert s.card0 == '\x00'
  2190. assert s.card1 == '\x00'
  2191. assert s.card2 == '\x00'
  2192. assert s.card3 == '\x00'
  2193. assert s.card4 == '\x00'
  2194. assert s.card5 == '\x00'
  2195. assert s.card7 == '\x00'
  2196. if cond == 1:
  2197. value |= 32768
  2198. assert s.data.tid == value
  2199. def test_cond_call_1(self):
  2200. def func_void(*args):
  2201. called.append(args)
  2202. for i in range(5):
  2203. called = []
  2204. FUNC = self.FuncType([lltype.Signed] * i, lltype.Void)
  2205. func_ptr = llhelper(lltype.Ptr(FUNC), func_void)
  2206. calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  2207. EffectInfo.MOST_GENERAL)
  2208. ops = '''
  2209. [i0, i1, i2, i3, i4, i5, i6, f0, f1]
  2210. cond_call(i1, ConstClass(func_ptr), %s)
  2211. guard_false(i0, descr=faildescr) [i1, i2, i3, i4, i5, i6, f0, f1]
  2212. ''' % ', '.join(['i%d' % (j + 2) for j in range(i)] + ["descr=calldescr"])
  2213. loop = parse(ops, namespace={'faildescr': BasicFailDescr(),
  2214. 'func_ptr': func_ptr,
  2215. 'calldescr': calldescr})
  2216. looptoken = JitCellToken()
  2217. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  2218. f1 = longlong.getfloatstorage(1.2)
  2219. f2 = longlong.getfloatstorage(3.4)
  2220. frame = self.cpu.execute_token(looptoken, 1, 0, 1, 2, 3, 4, 5, f1, f2)
  2221. assert not called
  2222. for j in range(5):
  2223. assert self.cpu.get_int_value(frame, j) == j
  2224. assert longlong.getrealfloat(self.cpu.get_float_value(frame, 6)) == 1.2
  2225. assert longlong.getrealfloat(self.cpu.get_float_value(frame, 7)) == 3.4
  2226. frame = self.cpu.execute_token(looptoken, 1, 1, 1, 2, 3, 4, 5, f1, f2)
  2227. assert called == [tuple(range(1, i + 1))]
  2228. for j in range(4):
  2229. assert self.cpu.get_int_value(frame, j + 1) == j + 1
  2230. assert longlong.getrealfloat(self.cpu.get_float_value(frame, 6)) == 1.2
  2231. assert longlong.getrealfloat(self.cpu.get_float_value(frame, 7)) == 3.4
  2232. def test_cond_call_2(self):
  2233. def func_void(*args):
  2234. called.append(args)
  2235. FUNC = self.FuncType([lltype.Signed, lltype.Signed], lltype.Void)
  2236. func_ptr = llhelper(lltype.Ptr(FUNC), func_void)
  2237. calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  2238. EffectInfo.MOST_GENERAL)
  2239. gfs = longlong.getfloatstorage
  2240. for (operation, arg1, arg2_if_true, arg2_if_false) in [
  2241. ('int_lt', -5, 2, -5),
  2242. ('int_le', 5, 5, -6),
  2243. ('int_eq', 11, 11, 12),
  2244. ('int_ne', 11, 12, 11),
  2245. ('int_gt', 8, -1, 8),
  2246. ('int_xor', 7, 3, 7), # test without a comparison at all
  2247. ('int_is_true', 4242, 1, 0),
  2248. ('int_is_zero', 4242, 0, 1),
  2249. ('float_lt', gfs(-0.5), gfs(0.2), gfs(-0.5)),
  2250. ('float_eq', gfs(1.1), gfs(1.1), gfs(1.2)),
  2251. ]:
  2252. called = []
  2253. ops = '''
  2254. [%s, %s, i3, i4]
  2255. i2 = %s(%s)
  2256. cond_call(i2, ConstClass(func_ptr), i3, i4, descr=calldescr)
  2257. guard_no_exception(descr=faildescr) []
  2258. finish()
  2259. ''' % ("i0" if operation.startswith('int') else "f0",
  2260. "i1" if operation.startswith('int') else "f1",
  2261. operation,
  2262. ("i1" if operation.startswith('int_is_') else
  2263. "i0, i1" if operation.startswith('int') else
  2264. "f0, f1"))
  2265. loop = parse(ops, namespace={'func_ptr': func_ptr,
  2266. 'calldescr': calldescr,
  2267. 'faildescr': BasicFailDescr()})
  2268. looptoken = JitCellToken()
  2269. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  2270. frame = self.cpu.execute_token(looptoken, arg1, arg2_if_false, 0, 0)
  2271. assert called == []
  2272. frame = self.cpu.execute_token(looptoken, arg1, arg2_if_true,
  2273. 67, 89)
  2274. assert called == [(67, 89)]
  2275. def test_force_operations_returning_void(self):
  2276. values = []
  2277. def maybe_force(token, flag):
  2278. if flag:
  2279. deadframe = self.cpu.force(token)
  2280. values.append(self.cpu.get_latest_descr(deadframe))
  2281. values.append(self.cpu.get_int_value(deadframe, 0))
  2282. values.append(self.cpu.get_int_value(deadframe, 1))
  2283. self.cpu.set_savedata_ref(deadframe, random_gcref)
  2284. FUNC = self.FuncType([llmemory.GCREF, lltype.Signed], lltype.Void)
  2285. func_ptr = llhelper(lltype.Ptr(FUNC), maybe_force)
  2286. calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  2287. EffectInfo.MOST_GENERAL)
  2288. cpu = self.cpu
  2289. faildescr = BasicFailDescr(1)
  2290. finaldescr = BasicFinalDescr(0)
  2291. loop = parse("""
  2292. [i0, i1]
  2293. p2 = force_token()
  2294. call_may_force_n(ConstClass(func_ptr), p2, i1, descr=calldescr)
  2295. guard_not_forced(descr=faildescr) [i1, i0]
  2296. finish(i0, descr=finaldescr)
  2297. """, namespace=locals())
  2298. looptoken = JitCellToken()
  2299. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  2300. deadframe = self.cpu.execute_token(looptoken, 20, 0)
  2301. fail = self.cpu.get_latest_descr(deadframe)
  2302. assert fail.identifier == 0
  2303. assert self.cpu.get_int_value(deadframe, 0) == 20
  2304. assert values == []
  2305. deadframe = self.cpu.execute_token(looptoken, 10, 1)
  2306. fail = self.cpu.get_latest_descr(deadframe)
  2307. assert fail.identifier == 1
  2308. assert self.cpu.get_int_value(deadframe, 0) == 1
  2309. assert self.cpu.get_int_value(deadframe, 1) == 10
  2310. assert values == [faildescr, 1, 10]
  2311. assert self.cpu.get_savedata_ref(deadframe) # not NULL
  2312. assert self.cpu.get_savedata_ref(deadframe) == random_gcref
  2313. def test_force_operations_returning_int(self):
  2314. values = []
  2315. def maybe_force(token, flag):
  2316. if flag:
  2317. deadframe = self.cpu.force(token)
  2318. values.append(self.cpu.get_int_value(deadframe, 0))
  2319. values.append(self.cpu.get_int_value(deadframe, 2))
  2320. self.cpu.set_savedata_ref(deadframe, random_gcref)
  2321. return 42
  2322. FUNC = self.FuncType([llmemory.GCREF, lltype.Signed], lltype.Signed)
  2323. func_ptr = llhelper(lltype.Ptr(FUNC), maybe_force)
  2324. calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  2325. EffectInfo.MOST_GENERAL)
  2326. cpu = self.cpu
  2327. faildescr = BasicFailDescr(1)
  2328. finaldescr = BasicFinalDescr(0)
  2329. loop = parse("""
  2330. [i0, i1]
  2331. p3 = force_token()
  2332. i2 = call_may_force_i(ConstClass(func_ptr), p3, i1, descr=calldescr)
  2333. guard_not_forced(descr=faildescr) [i1, i2, i0]
  2334. finish(i2, descr=finaldescr)
  2335. """, namespace=locals())
  2336. looptoken = JitCellToken()
  2337. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  2338. deadframe = self.cpu.execute_token(looptoken, 20, 0)
  2339. fail = self.cpu.get_latest_descr(deadframe)
  2340. assert fail.identifier == 0
  2341. assert self.cpu.get_int_value(deadframe, 0) == 42
  2342. assert values == []
  2343. deadframe = self.cpu.execute_token(looptoken, 10, 1)
  2344. fail = self.cpu.get_latest_descr(deadframe)
  2345. assert fail.identifier == 1
  2346. assert self.cpu.get_int_value(deadframe, 0) == 1
  2347. assert self.cpu.get_int_value(deadframe, 1) == 42
  2348. assert self.cpu.get_int_value(deadframe, 2) == 10
  2349. assert values == [1, 10]
  2350. assert self.cpu.get_savedata_ref(deadframe) == random_gcref
  2351. def test_force_operations_returning_float(self):
  2352. if not self.cpu.supports_floats:
  2353. py.test.skip("requires floats")
  2354. values = []
  2355. def maybe_force(token, flag):
  2356. if flag:
  2357. deadframe = self.cpu.force(token)
  2358. values.append(self.cpu.get_int_value(deadframe, 0))
  2359. values.append(self.cpu.get_int_value(deadframe, 2))
  2360. self.cpu.set_savedata_ref(deadframe, random_gcref)
  2361. return 42.5
  2362. FUNC = self.FuncType([llmemory.GCREF, lltype.Signed], lltype.Float)
  2363. func_ptr = llhelper(lltype.Ptr(FUNC), maybe_force)
  2364. funcbox = self.get_funcbox(self.cpu, func_ptr).constbox()
  2365. calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  2366. EffectInfo.MOST_GENERAL)
  2367. cpu = self.cpu
  2368. faildescr = BasicFailDescr(1)
  2369. finaldescr = BasicFinalDescr(0)
  2370. loop = parse("""
  2371. [i0, i1]
  2372. p3 = force_token()
  2373. f2 = call_may_force_f(ConstClass(func_ptr), p3, i1, descr=calldescr)
  2374. guard_not_forced(descr=faildescr) [i1, f2, i0]
  2375. finish(f2, descr=finaldescr)
  2376. """, namespace=locals())
  2377. looptoken = JitCellToken()
  2378. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  2379. deadframe = self.cpu.execute_token(looptoken, 20, 0)
  2380. fail = self.cpu.get_latest_descr(deadframe)
  2381. assert fail.identifier == 0
  2382. x = self.cpu.get_float_value(deadframe, 0)
  2383. assert longlong.getrealfloat(x) == 42.5
  2384. assert values == []
  2385. deadframe = self.cpu.execute_token(looptoken, 10, 1)
  2386. fail = self.cpu.get_latest_descr(deadframe)
  2387. assert fail.identifier == 1
  2388. assert self.cpu.get_int_value(deadframe, 0) == 1
  2389. x = self.cpu.get_float_value(deadframe, 1)
  2390. assert longlong.getrealfloat(x) == 42.5
  2391. assert self.cpu.get_int_value(deadframe, 2) == 10
  2392. assert values == [1, 10]
  2393. assert self.cpu.get_savedata_ref(deadframe) == random_gcref
  2394. def test_guard_not_forced_2(self):
  2395. cpu = self.cpu
  2396. faildescr = BasicFailDescr(1)
  2397. finaldescr = BasicFinalDescr(0)
  2398. loop = parse("""
  2399. [i0]
  2400. i1 = int_add(i0, 10)
  2401. p2 = force_token()
  2402. guard_not_forced_2(descr=faildescr) [i1]
  2403. finish(p2, descr=finaldescr)
  2404. """, namespace=locals())
  2405. looptoken = JitCellToken()
  2406. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  2407. deadframe = self.cpu.execute_token(looptoken, 20)
  2408. fail = self.cpu.get_latest_descr(deadframe)
  2409. assert fail.identifier == 0
  2410. frame = self.cpu.get_ref_value(deadframe, 0)
  2411. # actually, we should get the same pointer in 'frame' and 'deadframe'
  2412. # but it is not the case on LLGraph
  2413. if not getattr(self.cpu, 'is_llgraph', False):
  2414. assert frame == deadframe
  2415. deadframe2 = self.cpu.force(frame)
  2416. assert self.cpu.get_int_value(deadframe2, 0) == 30
  2417. def test_call_to_c_function(self):
  2418. from rpython.rlib.libffi import CDLL, types, ArgChain, FUNCFLAG_CDECL
  2419. from rpython.rtyper.lltypesystem.ll2ctypes import libc_name
  2420. libc = CDLL(libc_name)
  2421. c_tolower = libc.getpointer('tolower', [types.uchar], types.sint)
  2422. argchain = ArgChain().arg(ord('A'))
  2423. assert c_tolower.call(argchain, rffi.INT) == ord('a')
  2424. cpu = self.cpu
  2425. func_adr = c_tolower.funcsym
  2426. calldescr = cpu._calldescr_dynamic_for_tests([types.uchar], types.sint)
  2427. faildescr = BasicFailDescr(1)
  2428. finaldescr = BasicFinalDescr(0)
  2429. loop = parse("""
  2430. [i1]
  2431. i2 = call_release_gil_i(0, ConstClass(func_adr), i1, descr=calldescr)
  2432. guard_not_forced(descr=faildescr) [i1, i2]
  2433. finish(i2, descr=finaldescr)
  2434. """, namespace=locals())
  2435. looptoken = JitCellToken()
  2436. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  2437. deadframe = self.cpu.execute_token(looptoken, ord('G'))
  2438. fail = self.cpu.get_latest_descr(deadframe)
  2439. assert fail.identifier == 0
  2440. assert self.cpu.get_int_value(deadframe, 0) == ord('g')
  2441. def test_call_to_c_function_with_callback(self):
  2442. from rpython.rlib.libffi import CDLL, types, ArgChain, clibffi
  2443. from rpython.rtyper.lltypesystem.ll2ctypes import libc_name
  2444. libc = CDLL(libc_name)
  2445. types_size_t = clibffi.cast_type_to_ffitype(rffi.SIZE_T)
  2446. c_qsort = libc.getpointer('qsort', [types.pointer, types_size_t,
  2447. types_size_t, types.pointer],
  2448. types.void)
  2449. class Glob(object):
  2450. pass
  2451. glob = Glob()
  2452. class X(object):
  2453. pass
  2454. #
  2455. def callback(p1, p2):
  2456. glob.lst.append(X())
  2457. return rffi.cast(rffi.INT, 1)
  2458. CALLBACK = lltype.Ptr(lltype.FuncType([lltype.Signed,
  2459. lltype.Signed], rffi.INT))
  2460. fn = llhelper(CALLBACK, callback)
  2461. S = lltype.Struct('S', ('x', rffi.INT), ('y', rffi.INT))
  2462. raw = lltype.malloc(S, flavor='raw')
  2463. argchain = ArgChain()
  2464. argchain = argchain.arg(rffi.cast(lltype.Signed, raw))
  2465. argchain = argchain.arg(rffi.cast(rffi.SIZE_T, 2))
  2466. argchain = argchain.arg(rffi.cast(rffi.SIZE_T, 4))
  2467. argchain = argchain.arg(rffi.cast(lltype.Signed, fn))
  2468. glob.lst = []
  2469. c_qsort.call(argchain, lltype.Void)
  2470. assert len(glob.lst) > 0
  2471. del glob.lst[:]
  2472. cpu = self.cpu
  2473. func_adr = c_qsort.funcsym
  2474. calldescr = cpu._calldescr_dynamic_for_tests(
  2475. [types.pointer, types_size_t, types_size_t, types.pointer],
  2476. types.void)
  2477. faildescr = BasicFailDescr(1)
  2478. finaldescr = BasicFinalDescr(0)
  2479. loop = parse("""
  2480. [i0, i1, i2, i3]
  2481. call_release_gil_n(0, ConstClass(func_adr), i0, i1, i2, i3, descr=calldescr)
  2482. guard_not_forced(descr=faildescr) []
  2483. finish(descr=finaldescr)
  2484. """, namespace=locals())
  2485. looptoken = JitCellToken()
  2486. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  2487. args = [rffi.cast(lltype.Signed, raw),
  2488. 2,
  2489. 4,
  2490. rffi.cast(lltype.Signed, fn)]
  2491. assert glob.lst == []
  2492. deadframe = self.cpu.execute_token(looptoken, *args)
  2493. fail = self.cpu.get_latest_descr(deadframe)
  2494. assert fail.identifier == 0
  2495. assert len(glob.lst) > 0
  2496. lltype.free(raw, flavor='raw')
  2497. def test_call_to_winapi_function(self):
  2498. from rpython.rlib.clibffi import _WIN32
  2499. if not _WIN32:
  2500. py.test.skip("Windows test only")
  2501. from rpython.rlib.libffi import WinDLL, types, ArgChain
  2502. from rpython.rlib.rwin32 import DWORD
  2503. libc = WinDLL('KERNEL32')
  2504. c_GetCurrentDir = libc.getpointer('GetCurrentDirectoryA',
  2505. [types.ulong, types.pointer],
  2506. types.ulong)
  2507. cwd = os.getcwd()
  2508. buflen = len(cwd) + 10
  2509. buffer = lltype.malloc(rffi.CCHARP.TO, buflen, flavor='raw')
  2510. argchain = ArgChain().arg(rffi.cast(DWORD, buflen)).arg(buffer)
  2511. res = c_GetCurrentDir.call(argchain, DWORD)
  2512. assert rffi.cast(lltype.Signed, res) == len(cwd)
  2513. assert rffi.charp2strn(buffer, buflen) == cwd
  2514. lltype.free(buffer, flavor='raw')
  2515. cpu = self.cpu
  2516. func_adr = llmemory.cast_ptr_to_adr(c_GetCurrentDir.funcsym)
  2517. funcbox = ConstInt(heaptracker.adr2int(func_adr))
  2518. calldescr = cpu._calldescr_dynamic_for_tests(
  2519. [types.ulong, types.pointer],
  2520. types.ulong,
  2521. abiname='FFI_STDCALL')
  2522. i1 = InputArgInt()
  2523. i2 = InputArgInt()
  2524. faildescr = BasicFailDescr(1)
  2525. # if the stdcall convention is ignored, then ESP is wrong after the
  2526. # call: 8 bytes too much. If we repeat the call often enough, crash.
  2527. ops = []
  2528. for i in range(50):
  2529. ops += [
  2530. ResOperation(rop.CALL_RELEASE_GIL_I,
  2531. [ConstInt(0), funcbox, i1, i2],
  2532. descr=calldescr),
  2533. ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr),
  2534. ]
  2535. i3 = ops[-2]
  2536. ops[-1].setfailargs([])
  2537. ops += [
  2538. ResOperation(rop.FINISH, [i3], descr=BasicFinalDescr(0))
  2539. ]
  2540. looptoken = JitCellToken()
  2541. self.cpu.compile_loop([i1, i2], ops, looptoken)
  2542. buffer = lltype.malloc(rffi.CCHARP.TO, buflen, flavor='raw')
  2543. args = [buflen, rffi.cast(lltype.Signed, buffer)]
  2544. deadframe = self.cpu.execute_token(looptoken, *args)
  2545. fail = self.cpu.get_latest_descr(deadframe)
  2546. assert fail.identifier == 0
  2547. assert self.cpu.get_int_value(deadframe, 0) == len(cwd)
  2548. assert rffi.charp2strn(buffer, buflen) == cwd
  2549. lltype.free(buffer, flavor='raw')
  2550. def test_call_release_gil_return_types(self):
  2551. from rpython.rlib.libffi import types
  2552. from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong
  2553. from rpython.rlib.rarithmetic import r_singlefloat
  2554. cpu = self.cpu
  2555. for ffitype, result, TP in [
  2556. (types.ulong, r_uint(sys.maxint + 10), lltype.Unsigned),
  2557. (types.slong, -4321, lltype.Signed),
  2558. (types.uint8, 200, rffi.UCHAR),
  2559. (types.sint8, -42, rffi.SIGNEDCHAR),
  2560. (types.uint16, 50000, rffi.USHORT),
  2561. (types.sint16, -20000, rffi.SHORT),
  2562. (types.uint32, r_uint(3000000000), rffi.UINT),
  2563. (types.sint32, -2000000000, rffi.INT),
  2564. (types.uint64, r_ulonglong(9999999999999999999),
  2565. lltype.UnsignedLongLong),
  2566. (types.sint64, r_longlong(-999999999999999999),
  2567. lltype.SignedLongLong),
  2568. (types.double, 12.3475226, rffi.DOUBLE),
  2569. (types.float, r_singlefloat(-592.75), rffi.FLOAT),
  2570. ]:
  2571. if IS_32_BIT and TP in (lltype.SignedLongLong,
  2572. lltype.UnsignedLongLong):
  2573. if not cpu.supports_longlong:
  2574. continue
  2575. if TP == rffi.DOUBLE:
  2576. if not cpu.supports_floats:
  2577. continue
  2578. if TP == rffi.FLOAT:
  2579. if not cpu.supports_singlefloats:
  2580. continue
  2581. #
  2582. result = rffi.cast(TP, result)
  2583. #
  2584. def pseudo_c_function():
  2585. return result
  2586. #
  2587. FPTR = self.Ptr(self.FuncType([], TP))
  2588. func_ptr = llhelper(FPTR, pseudo_c_function)
  2589. funcbox = self.get_funcbox(cpu, func_ptr)
  2590. calldescr = cpu._calldescr_dynamic_for_tests([], ffitype)
  2591. faildescr = BasicFailDescr(1)
  2592. kind = types.getkind(ffitype)
  2593. if kind in 'uis':
  2594. opnum = rop.CALL_RELEASE_GIL_I
  2595. elif kind in 'fUI':
  2596. opnum = rop.CALL_RELEASE_GIL_F
  2597. else:
  2598. assert 0, kind
  2599. #
  2600. op0 = ResOperation(opnum, [ConstInt(0), funcbox], descr=calldescr)
  2601. op1 = ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr)
  2602. op2 = ResOperation(rop.FINISH, [op0], BasicFinalDescr(0))
  2603. ops = [op0, op1, op2]
  2604. ops[1].setfailargs([])
  2605. looptoken = JitCellToken()
  2606. self.cpu.compile_loop([], ops, looptoken)
  2607. deadframe = self.cpu.execute_token(looptoken)
  2608. fail = self.cpu.get_latest_descr(deadframe)
  2609. assert fail.identifier == 0
  2610. if kind in 'uis':
  2611. r = self.cpu.get_int_value(deadframe, 0)
  2612. if isinstance(result, r_singlefloat):
  2613. assert -sys.maxint-1 <= r <= 0xFFFFFFFF
  2614. r, = struct.unpack("f", struct.pack("I", r & 0xFFFFFFFF))
  2615. result = float(result)
  2616. else:
  2617. r = rffi.cast(TP, r)
  2618. assert r == result
  2619. elif kind in 'fUI':
  2620. r = self.cpu.get_float_value(deadframe, 0)
  2621. if isinstance(result, float):
  2622. r = longlong.getrealfloat(r)
  2623. else:
  2624. r = rffi.cast(TP, r)
  2625. assert r == result
  2626. def test_call_release_gil_variable_function_and_arguments(self):
  2627. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  2628. from rpython.rlib.libffi import types
  2629. from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong
  2630. from rpython.rlib.rarithmetic import r_singlefloat
  2631. from rpython.translator.c import primitive
  2632. def same_as_for_box(b):
  2633. if b.type == 'i':
  2634. return rop.SAME_AS_I
  2635. elif b.type == 'f':
  2636. return rop.SAME_AS_F
  2637. else:
  2638. assert False
  2639. cpu = self.cpu
  2640. rnd = random.Random(525)
  2641. seed = py.test.config.option.randomseed
  2642. print("random seed %d" % seed)
  2643. ALL_TYPES = [
  2644. (types.ulong, lltype.Unsigned),
  2645. (types.slong, lltype.Signed),
  2646. (types.uint8, rffi.UCHAR),
  2647. (types.sint8, rffi.SIGNEDCHAR),
  2648. (types.uint16, rffi.USHORT),
  2649. (types.sint16, rffi.SHORT),
  2650. (types.uint32, rffi.UINT),
  2651. (types.sint32, rffi.INT),
  2652. ]
  2653. if IS_32_BIT and cpu.supports_longlong:
  2654. ALL_TYPES += [
  2655. (types.uint64, lltype.UnsignedLongLong),
  2656. (types.sint64, lltype.SignedLongLong),
  2657. ] * 2
  2658. if cpu.supports_floats:
  2659. ALL_TYPES += [
  2660. (types.double, rffi.DOUBLE),
  2661. ] * 4
  2662. if cpu.supports_singlefloats:
  2663. ALL_TYPES += [
  2664. (types.float, rffi.FLOAT),
  2665. ] * 4
  2666. NB_TESTS = 100
  2667. c_source = []
  2668. all_tests = []
  2669. def prepare_c_source():
  2670. """Pick a random choice of argument types and length,
  2671. and build a C function with these arguments. The C
  2672. function will simply copy them all into static global
  2673. variables. There are then additional functions to fetch
  2674. them, one per argument, with a signature 'void(ARG *)'.
  2675. """
  2676. POSSIBLE_TYPES = [rnd.choice(ALL_TYPES)
  2677. for i in range(random.randrange(2, 5))]
  2678. load_factor = rnd.random()
  2679. keepalive_factor = rnd.random()
  2680. #
  2681. ffitypes = []
  2682. ARGTYPES = []
  2683. for i in range(rnd.randrange(4, 20)):
  2684. ffitype, TP = rnd.choice(POSSIBLE_TYPES)
  2685. ffitypes.append(ffitype)
  2686. ARGTYPES.append(TP)
  2687. fn_name = 'vartest%d' % k
  2688. all_tests.append((ARGTYPES, ffitypes, fn_name))
  2689. #
  2690. fn_args = []
  2691. for i, ARG in enumerate(ARGTYPES):
  2692. arg_decl = primitive.cdecl(primitive.PrimitiveType[ARG],
  2693. 'x%d' % i)
  2694. fn_args.append(arg_decl)
  2695. var_name = 'argcopy_%s_x%d' % (fn_name, i)
  2696. var_decl = primitive.cdecl(primitive.PrimitiveType[ARG],
  2697. var_name)
  2698. c_source.append('static %s;' % var_decl)
  2699. getter_name = '%s_get%d' % (fn_name, i)
  2700. c_source.append('RPY_EXPORTED void %s(%s) { *p = %s; }' % (
  2701. getter_name,
  2702. primitive.cdecl(primitive.PrimitiveType[ARG], '*p'),
  2703. var_name))
  2704. c_source.append('')
  2705. c_source.append('static void real%s(%s)' % (
  2706. fn_name, ', '.join(fn_args)))
  2707. c_source.append('{')
  2708. for i in range(len(ARGTYPES)):
  2709. c_source.append(' argcopy_%s_x%d = x%d;' % (fn_name, i, i))
  2710. c_source.append('}')
  2711. c_source.append('RPY_EXPORTED void *%s(void)' % fn_name)
  2712. c_source.append('{')
  2713. c_source.append(' return (void *)&real%s;' % fn_name)
  2714. c_source.append('}')
  2715. c_source.append('')
  2716. for k in range(NB_TESTS):
  2717. prepare_c_source()
  2718. eci = ExternalCompilationInfo(
  2719. separate_module_sources=['\n'.join(c_source)])
  2720. for k in range(NB_TESTS):
  2721. ARGTYPES, ffitypes, fn_name = all_tests[k]
  2722. func_getter_ptr = rffi.llexternal(fn_name, [], lltype.Signed,
  2723. compilation_info=eci, _nowrapper=True)
  2724. load_factor = rnd.random()
  2725. keepalive_factor = rnd.random()
  2726. #
  2727. func_raw = func_getter_ptr()
  2728. calldescr = cpu._calldescr_dynamic_for_tests(ffitypes, types.void)
  2729. faildescr = BasicFailDescr(1)
  2730. #
  2731. argboxes = [InputArgInt()] # for the function to call
  2732. codes = ['X']
  2733. for ffitype in ffitypes:
  2734. kind = types.getkind(ffitype)
  2735. codes.append(kind)
  2736. if kind in 'uis':
  2737. b1 = InputArgInt()
  2738. elif kind in 'fUI':
  2739. b1 = InputArgFloat()
  2740. else:
  2741. assert 0, kind
  2742. argboxes.append(b1)
  2743. codes = ''.join(codes) # useful for pdb
  2744. print
  2745. print codes
  2746. #
  2747. argvalues = [func_raw]
  2748. for TP in ARGTYPES:
  2749. r = (rnd.random() - 0.5) * 999999999999.9
  2750. r = rffi.cast(TP, r)
  2751. argvalues.append(r)
  2752. #
  2753. argvalues_normal = argvalues[:1]
  2754. for ffitype, r in zip(ffitypes, argvalues[1:]):
  2755. kind = types.getkind(ffitype)
  2756. if kind in 'ui':
  2757. r = rffi.cast(lltype.Signed, r)
  2758. elif kind in 's':
  2759. r, = struct.unpack("i", struct.pack("f", float(r)))
  2760. elif kind in 'f':
  2761. r = longlong.getfloatstorage(r)
  2762. elif kind in 'UI': # 32-bit only
  2763. r = rffi.cast(lltype.SignedLongLong, r)
  2764. else:
  2765. assert 0
  2766. argvalues_normal.append(r)
  2767. #
  2768. ops = []
  2769. loadcodes = []
  2770. insideboxes = []
  2771. for b1 in argboxes:
  2772. load = rnd.random() < load_factor
  2773. loadcodes.append(' ^'[load])
  2774. if load:
  2775. b2 = ResOperation(same_as_for_box(b1), [b1])
  2776. ops.insert(rnd.randrange(0, len(ops)+1), b2)
  2777. b1 = b2
  2778. insideboxes.append(b1)
  2779. loadcodes = ''.join(loadcodes)
  2780. print loadcodes
  2781. ops += [
  2782. ResOperation(rop.CALL_RELEASE_GIL_N,
  2783. [ConstInt(0)] + insideboxes,
  2784. descr=calldescr),
  2785. ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr),
  2786. ResOperation(rop.FINISH, [], descr=BasicFinalDescr(0))
  2787. ]
  2788. ops[-2].setfailargs([])
  2789. # keep alive a random subset of the insideboxes
  2790. for b1 in insideboxes:
  2791. if rnd.random() < keepalive_factor:
  2792. ops.insert(-1, ResOperation(same_as_for_box(b1), [b1]))
  2793. looptoken = JitCellToken()
  2794. self.cpu.compile_loop(argboxes, ops, looptoken)
  2795. #
  2796. deadframe = self.cpu.execute_token(looptoken, *argvalues_normal)
  2797. fail = self.cpu.get_latest_descr(deadframe)
  2798. assert fail.identifier == 0
  2799. expected = argvalues[1:]
  2800. got = []
  2801. for i, ARG in enumerate(ARGTYPES):
  2802. PARG = rffi.CArrayPtr(ARG)
  2803. getter_name = '%s_get%d' % (fn_name, i)
  2804. getter_ptr = rffi.llexternal(getter_name, [PARG], lltype.Void,
  2805. compilation_info=eci,
  2806. _nowrapper=True)
  2807. my_arg = lltype.malloc(PARG.TO, 1, zero=True, flavor='raw')
  2808. getter_ptr(my_arg)
  2809. got.append(my_arg[0])
  2810. lltype.free(my_arg, flavor='raw')
  2811. different_values = ['x%d: got %r, expected %r' % (i, a, b)
  2812. for i, (a, b) in enumerate(zip(got, expected))
  2813. if a != b]
  2814. assert got == expected, '\n'.join(
  2815. ['bad args, signature %r' % codes[1:]] + different_values)
  2816. def test_call_release_gil_save_errno(self):
  2817. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  2818. from rpython.rlib.libffi import types
  2819. from rpython.jit.backend.llsupport import llerrno
  2820. #
  2821. if not isinstance(self.cpu, AbstractLLCPU):
  2822. py.test.skip("not on LLGraph")
  2823. eci = ExternalCompilationInfo(
  2824. separate_module_sources=['''
  2825. #include <errno.h>
  2826. static long f1(long a, long b, long c, long d,
  2827. long e, long f, long g) {
  2828. errno = 42;
  2829. return (a + 10*b + 100*c + 1000*d +
  2830. 10000*e + 100000*f + 1000000*g);
  2831. }
  2832. RPY_EXPORTED
  2833. long test_call_release_gil_save_errno(void) {
  2834. return (long)&f1;
  2835. }
  2836. '''])
  2837. fn_name = 'test_call_release_gil_save_errno'
  2838. getter_ptr = rffi.llexternal(fn_name, [], lltype.Signed,
  2839. compilation_info=eci, _nowrapper=True)
  2840. func1_adr = getter_ptr()
  2841. calldescr = self.cpu._calldescr_dynamic_for_tests([types.slong]*7,
  2842. types.slong)
  2843. #
  2844. for saveerr in [rffi.RFFI_ERR_NONE,
  2845. rffi.RFFI_SAVE_ERRNO,
  2846. rffi.RFFI_ERR_NONE | rffi.RFFI_ALT_ERRNO,
  2847. rffi.RFFI_SAVE_ERRNO | rffi.RFFI_ALT_ERRNO,
  2848. ]:
  2849. faildescr = BasicFailDescr(1)
  2850. inputargs = [InputArgInt() for i in range(7)]
  2851. op0 = ResOperation(rop.CALL_RELEASE_GIL_I,
  2852. [ConstInt(saveerr), ConstInt(func1_adr)]
  2853. + inputargs,
  2854. descr=calldescr)
  2855. ops = [
  2856. op0,
  2857. ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr),
  2858. ResOperation(rop.FINISH, [op0], descr=BasicFinalDescr(0))
  2859. ]
  2860. ops[-2].setfailargs([])
  2861. looptoken = JitCellToken()
  2862. self.cpu.compile_loop(inputargs, ops, looptoken)
  2863. #
  2864. llerrno.set_debug_saved_errno(self.cpu, 24)
  2865. llerrno.set_debug_saved_alterrno(self.cpu, 25)
  2866. deadframe = self.cpu.execute_token(looptoken, 9, 8, 7, 6, 5, 4, 3)
  2867. original_result = self.cpu.get_int_value(deadframe, 0)
  2868. result = llerrno.get_debug_saved_errno(self.cpu)
  2869. altresult = llerrno.get_debug_saved_alterrno(self.cpu)
  2870. print 'saveerr =', saveerr, ': got result =', result, \
  2871. 'altresult =', altresult
  2872. #
  2873. expected = {
  2874. rffi.RFFI_ERR_NONE: (24, 25),
  2875. rffi.RFFI_SAVE_ERRNO: (42, 25),
  2876. rffi.RFFI_ERR_NONE | rffi.RFFI_ALT_ERRNO: (24, 25),
  2877. rffi.RFFI_SAVE_ERRNO | rffi.RFFI_ALT_ERRNO: (24, 42),
  2878. }
  2879. # expected (24, 25) as originally set, with possibly one
  2880. # of the two changed to 42 by the assembler code
  2881. assert (result, altresult) == expected[saveerr]
  2882. assert original_result == 3456789
  2883. def test_call_release_gil_readsaved_errno(self):
  2884. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  2885. from rpython.rlib.libffi import types
  2886. from rpython.jit.backend.llsupport import llerrno
  2887. #
  2888. if not isinstance(self.cpu, AbstractLLCPU):
  2889. py.test.skip("not on LLGraph")
  2890. eci = ExternalCompilationInfo(
  2891. separate_module_sources=[r'''
  2892. #include <stdio.h>
  2893. #include <errno.h>
  2894. static long f1(long a, long b, long c, long d,
  2895. long e, long f, long g) {
  2896. long r = errno;
  2897. printf("read saved errno: %ld\n", r);
  2898. r += 100 * (a + 10*b + 100*c + 1000*d +
  2899. 10000*e + 100000*f + 1000000*g);
  2900. return r;
  2901. }
  2902. RPY_EXPORTED
  2903. long test_call_release_gil_readsaved_errno(void) {
  2904. return (long)&f1;
  2905. }
  2906. '''])
  2907. fn_name = 'test_call_release_gil_readsaved_errno'
  2908. getter_ptr = rffi.llexternal(fn_name, [], lltype.Signed,
  2909. compilation_info=eci, _nowrapper=True)
  2910. func1_adr = getter_ptr()
  2911. calldescr = self.cpu._calldescr_dynamic_for_tests([types.slong]*7,
  2912. types.slong)
  2913. #
  2914. for saveerr in [rffi.RFFI_READSAVED_ERRNO,
  2915. rffi.RFFI_ZERO_ERRNO_BEFORE,
  2916. rffi.RFFI_READSAVED_ERRNO | rffi.RFFI_ALT_ERRNO,
  2917. rffi.RFFI_ZERO_ERRNO_BEFORE | rffi.RFFI_ALT_ERRNO,
  2918. ]:
  2919. faildescr = BasicFailDescr(1)
  2920. inputargs = [InputArgInt() for i in range(7)]
  2921. op0 = ResOperation(rop.CALL_RELEASE_GIL_I,
  2922. [ConstInt(saveerr), ConstInt(func1_adr)]
  2923. + inputargs,
  2924. descr=calldescr)
  2925. ops = [
  2926. op0,
  2927. ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr),
  2928. ResOperation(rop.FINISH, [op0], descr=BasicFinalDescr(0))
  2929. ]
  2930. ops[-2].setfailargs([])
  2931. looptoken = JitCellToken()
  2932. self.cpu.compile_loop(inputargs, ops, looptoken)
  2933. #
  2934. llerrno.set_debug_saved_errno(self.cpu, 24)
  2935. llerrno.set_debug_saved_alterrno(self.cpu, 25)
  2936. deadframe = self.cpu.execute_token(looptoken, 9, 8, 7, 6, 5, 4, 3)
  2937. result = self.cpu.get_int_value(deadframe, 0)
  2938. assert llerrno.get_debug_saved_errno(self.cpu) == 24
  2939. assert llerrno.get_debug_saved_alterrno(self.cpu) == 25
  2940. #
  2941. if saveerr & rffi.RFFI_READSAVED_ERRNO:
  2942. if saveerr & rffi.RFFI_ALT_ERRNO:
  2943. assert result == 25 + 345678900
  2944. else:
  2945. assert result == 24 + 345678900
  2946. else:
  2947. assert result == 0 + 345678900
  2948. def test_call_release_gil_save_lasterror(self):
  2949. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  2950. from rpython.rlib.libffi import types
  2951. from rpython.jit.backend.llsupport import llerrno
  2952. #
  2953. if not isinstance(self.cpu, AbstractLLCPU):
  2954. py.test.skip("not on LLGraph")
  2955. if sys.platform != 'win32':
  2956. py.test.skip("Windows test only")
  2957. eci = ExternalCompilationInfo(
  2958. separate_module_sources=['''
  2959. #include <windows.h>
  2960. static long f1(long a, long b, long c, long d,
  2961. long e, long f, long g) {
  2962. SetLastError(42);
  2963. return (a + 10*b + 100*c + 1000*d +
  2964. 10000*e + 100000*f + 1000000*g);
  2965. }
  2966. RPY_EXPORTED
  2967. long test_call_release_gil_save_lasterror(void) {
  2968. return (long)&f1;
  2969. }
  2970. '''])
  2971. fn_name = 'test_call_release_gil_save_lasterror'
  2972. getter_ptr = rffi.llexternal(fn_name, [], lltype.Signed,
  2973. compilation_info=eci, _nowrapper=True)
  2974. func1_adr = getter_ptr()
  2975. calldescr = self.cpu._calldescr_dynamic_for_tests([types.slong]*7,
  2976. types.slong)
  2977. #
  2978. for saveerr in [rffi.RFFI_SAVE_ERRNO, # but not _LASTERROR
  2979. rffi.RFFI_SAVE_ERRNO | rffi.RFFI_ALT_ERRNO,
  2980. rffi.RFFI_SAVE_LASTERROR,
  2981. rffi.RFFI_SAVE_LASTERROR | rffi.RFFI_ALT_ERRNO,
  2982. ]:
  2983. faildescr = BasicFailDescr(1)
  2984. inputargs = [InputArgInt() for i in range(7)]
  2985. ops = [
  2986. ResOperation(rop.CALL_RELEASE_GIL_I,
  2987. [ConstInt(saveerr), ConstInt(func1_adr)]
  2988. + inputargs,
  2989. descr=calldescr),
  2990. ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr),
  2991. ]
  2992. i1 = ops[0]
  2993. ops += [ResOperation(rop.FINISH, [i1], descr=BasicFinalDescr(0))]
  2994. ops[-2].setfailargs([])
  2995. looptoken = JitCellToken()
  2996. self.cpu.compile_loop(inputargs, ops, looptoken)
  2997. #
  2998. llerrno.set_debug_saved_lasterror(self.cpu, 24)
  2999. llerrno.set_debug_saved_altlasterror(self.cpu, 25)
  3000. deadframe = self.cpu.execute_token(looptoken, 9, 8, 7, 6, 5, 4, 3)
  3001. original_result = self.cpu.get_int_value(deadframe, 0)
  3002. result = llerrno.get_debug_saved_lasterror(self.cpu)
  3003. altresult = llerrno.get_debug_saved_altlasterror(self.cpu)
  3004. print 'saveerr =', saveerr, ': got result =', result,
  3005. print 'and altresult =', altresult
  3006. #
  3007. if saveerr & rffi.RFFI_SAVE_LASTERROR:
  3008. # one from the C code, the other not touched
  3009. if saveerr & rffi.RFFI_ALT_ERRNO:
  3010. assert (result, altresult) == (24, 42)
  3011. else:
  3012. assert (result, altresult) == (42, 25)
  3013. else:
  3014. assert (result, altresult) == (24, 25) # not touched
  3015. assert original_result == 3456789
  3016. def test_call_release_gil_readsaved_lasterror(self):
  3017. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  3018. from rpython.rlib.libffi import types
  3019. from rpython.jit.backend.llsupport import llerrno
  3020. #
  3021. if not isinstance(self.cpu, AbstractLLCPU):
  3022. py.test.skip("not on LLGraph")
  3023. if sys.platform != 'win32':
  3024. py.test.skip("Windows test only")
  3025. eci = ExternalCompilationInfo(
  3026. separate_module_sources=[r'''
  3027. #include <windows.h>
  3028. static long f1(long a, long b, long c, long d,
  3029. long e, long f, long g) {
  3030. long r = GetLastError();
  3031. printf("GetLastError() result: %ld\n", r);
  3032. printf("%ld %ld %ld %ld %ld %ld %ld\n", a,b,c,d,e,f,g);
  3033. r += 100 * (a + 10*b + 100*c + 1000*d +
  3034. 10000*e + 100000*f + 1000000*g);
  3035. return r;
  3036. }
  3037. RPY_EXPORTED
  3038. long test_call_release_gil_readsaved_lasterror(void) {
  3039. return (long)&f1;
  3040. }
  3041. '''])
  3042. fn_name = 'test_call_release_gil_readsaved_lasterror'
  3043. getter_ptr = rffi.llexternal(fn_name, [], lltype.Signed,
  3044. compilation_info=eci, _nowrapper=True)
  3045. func1_adr = getter_ptr()
  3046. calldescr = self.cpu._calldescr_dynamic_for_tests([types.slong]*7,
  3047. types.slong)
  3048. #
  3049. for saveerr in [rffi.RFFI_READSAVED_LASTERROR,
  3050. rffi.RFFI_READSAVED_LASTERROR | rffi.RFFI_ALT_ERRNO,
  3051. ]:
  3052. faildescr = BasicFailDescr(1)
  3053. inputargs = [InputArgInt() for i in range(7)]
  3054. ops = [
  3055. ResOperation(rop.CALL_RELEASE_GIL_I,
  3056. [ConstInt(saveerr), ConstInt(func1_adr)]
  3057. + inputargs,
  3058. descr=calldescr),
  3059. ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr),
  3060. ]
  3061. i1 = ops[-2]
  3062. ops += [ResOperation(rop.FINISH, [i1], descr=BasicFinalDescr(0))]
  3063. ops[-2].setfailargs([])
  3064. looptoken = JitCellToken()
  3065. self.cpu.compile_loop(inputargs, ops, looptoken)
  3066. #
  3067. llerrno.set_debug_saved_lasterror(self.cpu, 24)
  3068. llerrno.set_debug_saved_altlasterror(self.cpu, 25)
  3069. deadframe = self.cpu.execute_token(looptoken, 9, 8, 7, 6, 5, 4, 3)
  3070. result = self.cpu.get_int_value(deadframe, 0)
  3071. assert llerrno.get_debug_saved_lasterror(self.cpu) == 24
  3072. assert llerrno.get_debug_saved_altlasterror(self.cpu) == 25
  3073. #
  3074. if saveerr & rffi.RFFI_ALT_ERRNO:
  3075. expected_lasterror = 25
  3076. else:
  3077. expected_lasterror = 24
  3078. assert result == expected_lasterror + 345678900
  3079. def test_call_release_gil_err_all(self):
  3080. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  3081. from rpython.rlib.libffi import types
  3082. from rpython.jit.backend.llsupport import llerrno
  3083. #
  3084. if not isinstance(self.cpu, AbstractLLCPU):
  3085. py.test.skip("not on LLGraph")
  3086. if sys.platform != 'win32':
  3087. eci = ExternalCompilationInfo(
  3088. separate_module_sources=[r'''
  3089. #include <errno.h>
  3090. static long f1(long a, long b, long c, long d,
  3091. long e, long f, long g) {
  3092. long r = errno;
  3093. errno = 42;
  3094. r += 100 * (a + 10*b + 100*c + 1000*d +
  3095. 10000*e + 100000*f + 1000000*g);
  3096. return r;
  3097. }
  3098. RPY_EXPORTED
  3099. long test_call_release_gil_err_all(void) {
  3100. return (long)&f1;
  3101. }
  3102. '''])
  3103. else:
  3104. eci = ExternalCompilationInfo(
  3105. separate_module_sources=[r'''
  3106. #include <windows.h>
  3107. #include <errno.h>
  3108. static long f1(long a, long b, long c, long d,
  3109. long e, long f, long g) {
  3110. long r = errno + 10 * GetLastError();
  3111. errno = 42;
  3112. SetLastError(43);
  3113. r += 100 * (a + 10*b + 100*c + 1000*d +
  3114. 10000*e + 100000*f + 1000000*g);
  3115. return r;
  3116. }
  3117. RPY_EXPORTED
  3118. long test_call_release_gil_err_all(void) {
  3119. return (long)&f1;
  3120. }
  3121. '''])
  3122. fn_name = 'test_call_release_gil_err_all'
  3123. getter_ptr = rffi.llexternal(fn_name, [], lltype.Signed,
  3124. compilation_info=eci, _nowrapper=True)
  3125. func1_adr = getter_ptr()
  3126. calldescr = self.cpu._calldescr_dynamic_for_tests([types.slong]*7,
  3127. types.slong)
  3128. #
  3129. for saveerr in [rffi.RFFI_ERR_ALL,
  3130. rffi.RFFI_ERR_ALL | rffi.RFFI_ALT_ERRNO,
  3131. ]:
  3132. faildescr = BasicFailDescr(1)
  3133. inputargs = [InputArgInt() for i in range(7)]
  3134. op0 = ResOperation(rop.CALL_RELEASE_GIL_I,
  3135. [ConstInt(saveerr), ConstInt(func1_adr)]
  3136. + inputargs,
  3137. descr=calldescr)
  3138. ops = [
  3139. op0,
  3140. ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr),
  3141. ResOperation(rop.FINISH, [op0], descr=BasicFinalDescr(0))
  3142. ]
  3143. ops[-2].setfailargs([])
  3144. looptoken = JitCellToken()
  3145. self.cpu.compile_loop(inputargs, ops, looptoken)
  3146. #
  3147. llerrno.set_debug_saved_errno(self.cpu, 8)
  3148. llerrno.set_debug_saved_alterrno(self.cpu, 5)
  3149. llerrno.set_debug_saved_lasterror(self.cpu, 9)
  3150. llerrno.set_debug_saved_altlasterror(self.cpu, 4)
  3151. deadframe = self.cpu.execute_token(looptoken, 1, 2, 3, 4, 5, 6, 7)
  3152. result = self.cpu.get_int_value(deadframe, 0)
  3153. got_errno = llerrno.get_debug_saved_errno(self.cpu)
  3154. got_alter = llerrno.get_debug_saved_alterrno(self.cpu)
  3155. if saveerr & rffi.RFFI_ALT_ERRNO:
  3156. assert (got_errno, got_alter) == (8, 42)
  3157. else:
  3158. assert (got_errno, got_alter) == (42, 5)
  3159. if sys.platform != 'win32':
  3160. if saveerr & rffi.RFFI_ALT_ERRNO:
  3161. assert result == 765432105
  3162. else:
  3163. assert result == 765432108
  3164. else:
  3165. if saveerr & rffi.RFFI_ALT_ERRNO:
  3166. assert result == 765432145
  3167. else:
  3168. assert result == 765432198
  3169. got_lasterror = llerrno.get_debug_saved_lasterror(self.cpu)
  3170. got_altlaster = llerrno.get_debug_saved_altlasterror(self.cpu)
  3171. if saveerr & rffi.RFFI_ALT_ERRNO:
  3172. assert (got_lasterror, got_altlaster) == (9, 43)
  3173. else:
  3174. assert (got_lasterror, got_altlaster) == (43, 4)
  3175. def test_guard_not_invalidated(self):
  3176. cpu = self.cpu
  3177. faildescr = BasicFailDescr(1)
  3178. finaldescr = BasicFinalDescr(0)
  3179. loop = parse("""
  3180. [i0, i1]
  3181. guard_not_invalidated(descr=faildescr) [i1]
  3182. finish(i0, descr=finaldescr)
  3183. """, namespace=locals())
  3184. looptoken = JitCellToken()
  3185. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  3186. deadframe = self.cpu.execute_token(looptoken, -42, 9)
  3187. fail = self.cpu.get_latest_descr(deadframe)
  3188. assert fail.identifier == 0
  3189. assert self.cpu.get_int_value(deadframe, 0) == -42
  3190. print 'step 1 ok'
  3191. print '-'*79
  3192. # mark as failing
  3193. self.cpu.invalidate_loop(looptoken)
  3194. deadframe = self.cpu.execute_token(looptoken, -42, 9)
  3195. fail = self.cpu.get_latest_descr(deadframe)
  3196. assert fail is faildescr
  3197. assert self.cpu.get_int_value(deadframe, 0) == 9
  3198. print 'step 2 ok'
  3199. print '-'*79
  3200. # attach a bridge
  3201. faildescr2 = BasicFailDescr(2)
  3202. finaldescr2 = BasicFinalDescr(3)
  3203. bridge = parse("""
  3204. [i2]
  3205. guard_not_invalidated(descr=faildescr2) []
  3206. finish(i2, descr=finaldescr2)
  3207. """, namespace=locals())
  3208. self.cpu.compile_bridge(faildescr, bridge.inputargs,
  3209. bridge.operations, looptoken)
  3210. deadframe = self.cpu.execute_token(looptoken, -42, 9)
  3211. fail = self.cpu.get_latest_descr(deadframe)
  3212. assert fail.identifier == 3
  3213. assert self.cpu.get_int_value(deadframe, 0) == 9
  3214. print 'step 3 ok'
  3215. print '-'*79
  3216. # mark as failing again
  3217. self.cpu.invalidate_loop(looptoken)
  3218. deadframe = self.cpu.execute_token(looptoken, -42, 9)
  3219. fail = self.cpu.get_latest_descr(deadframe)
  3220. assert fail is faildescr2
  3221. print 'step 4 ok'
  3222. print '-'*79
  3223. def test_guard_not_invalidated_and_label(self):
  3224. # test that the guard_not_invalidated reserves enough room before
  3225. # the label. If it doesn't, then in this example after we invalidate
  3226. # the guard, jumping to the label will hit the invalidation code too
  3227. cpu = self.cpu
  3228. faildescr = BasicFailDescr(1)
  3229. labeldescr = TargetToken()
  3230. finaldescr = BasicFinalDescr(3)
  3231. loop = parse("""
  3232. [i0]
  3233. guard_not_invalidated(descr=faildescr) []
  3234. label(i0, descr=labeldescr)
  3235. finish(i0, descr=finaldescr)
  3236. """, namespace=locals())
  3237. looptoken = JitCellToken()
  3238. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  3239. # mark as failing
  3240. self.cpu.invalidate_loop(looptoken)
  3241. # attach a bridge
  3242. i2 = InputArgInt()
  3243. ops2 = [
  3244. ResOperation(rop.JUMP, [ConstInt(333)], descr=labeldescr),
  3245. ]
  3246. self.cpu.compile_bridge(faildescr, [], ops2, looptoken)
  3247. # run: must not be caught in an infinite loop
  3248. deadframe = self.cpu.execute_token(looptoken, 16)
  3249. fail = self.cpu.get_latest_descr(deadframe)
  3250. assert fail.identifier == 3
  3251. assert self.cpu.get_int_value(deadframe, 0) == 333
  3252. # pure do_ / descr features
  3253. def test_do_operations(self):
  3254. cpu = self.cpu
  3255. #
  3256. A = lltype.GcArray(lltype.Char)
  3257. descr_A = cpu.arraydescrof(A)
  3258. a = lltype.malloc(A, 5)
  3259. x = cpu.bh_arraylen_gc(lltype.cast_opaque_ptr(llmemory.GCREF, a),
  3260. descr_A)
  3261. assert x == 5
  3262. #
  3263. a[2] = 'Y'
  3264. x = cpu.bh_getarrayitem_gc_i(
  3265. lltype.cast_opaque_ptr(llmemory.GCREF, a), 2, descr_A)
  3266. assert x == ord('Y')
  3267. #
  3268. B = lltype.GcArray(lltype.Ptr(A))
  3269. descr_B = cpu.arraydescrof(B)
  3270. b = lltype.malloc(B, 4)
  3271. b[3] = a
  3272. x = cpu.bh_getarrayitem_gc_r(
  3273. lltype.cast_opaque_ptr(llmemory.GCREF, b), 3, descr_B)
  3274. assert lltype.cast_opaque_ptr(lltype.Ptr(A), x) == a
  3275. if self.cpu.supports_floats:
  3276. C = lltype.GcArray(lltype.Float)
  3277. c = lltype.malloc(C, 6)
  3278. c[3] = 3.5
  3279. descr_C = cpu.arraydescrof(C)
  3280. x = cpu.bh_getarrayitem_gc_f(
  3281. lltype.cast_opaque_ptr(llmemory.GCREF, c), 3, descr_C)
  3282. assert longlong.getrealfloat(x) == 3.5
  3283. cpu.bh_setarrayitem_gc_f(
  3284. lltype.cast_opaque_ptr(llmemory.GCREF, c), 4,
  3285. longlong.getfloatstorage(4.5), descr_C)
  3286. assert c[4] == 4.5
  3287. s = rstr.mallocstr(6)
  3288. x = cpu.bh_strlen(lltype.cast_opaque_ptr(llmemory.GCREF, s))
  3289. assert x == 6
  3290. #
  3291. s.chars[3] = 'X'
  3292. x = cpu.bh_strgetitem(lltype.cast_opaque_ptr(llmemory.GCREF, s), 3)
  3293. assert x == ord('X')
  3294. #
  3295. S = lltype.GcStruct('S', ('x', lltype.Char), ('y', lltype.Ptr(A)),
  3296. ('z', lltype.Float))
  3297. descrfld_x = cpu.fielddescrof(S, 'x')
  3298. s = lltype.malloc(S)
  3299. s.x = 'Z'
  3300. x = cpu.bh_getfield_gc_i(lltype.cast_opaque_ptr(llmemory.GCREF, s),
  3301. descrfld_x)
  3302. assert x == ord('Z')
  3303. #
  3304. cpu.bh_setfield_gc_i(lltype.cast_opaque_ptr(llmemory.GCREF, s),
  3305. ord('4'), descrfld_x)
  3306. assert s.x == '4'
  3307. #
  3308. descrfld_y = cpu.fielddescrof(S, 'y')
  3309. s.y = a
  3310. x = cpu.bh_getfield_gc_r(lltype.cast_opaque_ptr(llmemory.GCREF, s),
  3311. descrfld_y)
  3312. assert lltype.cast_opaque_ptr(lltype.Ptr(A), x) == a
  3313. #
  3314. s.y = lltype.nullptr(A)
  3315. cpu.bh_setfield_gc_r(lltype.cast_opaque_ptr(llmemory.GCREF, s),
  3316. x, descrfld_y)
  3317. assert s.y == a
  3318. #
  3319. RS = lltype.Struct('S', ('x', lltype.Char)) #, ('y', lltype.Ptr(A)))
  3320. descrfld_rx = cpu.fielddescrof(RS, 'x')
  3321. rs = lltype.malloc(RS, immortal=True)
  3322. rs.x = '?'
  3323. x = cpu.bh_getfield_raw_i(
  3324. heaptracker.adr2int(llmemory.cast_ptr_to_adr(rs)),
  3325. descrfld_rx)
  3326. assert x == ord('?')
  3327. #
  3328. cpu.bh_setfield_raw_i(
  3329. heaptracker.adr2int(llmemory.cast_ptr_to_adr(rs)),
  3330. ord('!'), descrfld_rx)
  3331. assert rs.x == '!'
  3332. #
  3333. if self.cpu.supports_floats:
  3334. descrfld_z = cpu.fielddescrof(S, 'z')
  3335. cpu.bh_setfield_gc_f(
  3336. lltype.cast_opaque_ptr(llmemory.GCREF, s),
  3337. longlong.getfloatstorage(3.5), descrfld_z)
  3338. assert s.z == 3.5
  3339. s.z = 3.2
  3340. x = cpu.bh_getfield_gc_f(
  3341. lltype.cast_opaque_ptr(llmemory.GCREF, s),
  3342. descrfld_z)
  3343. assert longlong.getrealfloat(x) == 3.2
  3344. ### we don't support in the JIT for now GC pointers
  3345. ### stored inside non-GC structs.
  3346. #descrfld_ry = cpu.fielddescrof(RS, 'y')
  3347. #rs.y = a
  3348. #x = cpu.do_getfield_raw(
  3349. # InputArgInt(cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(rs))),
  3350. # descrfld_ry)
  3351. #assert isinstance(x, BoxPtr)
  3352. #assert x.getref(lltype.Ptr(A)) == a
  3353. #
  3354. #rs.y = lltype.nullptr(A)
  3355. #cpu.do_setfield_raw(
  3356. # InputArgInt(cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(rs))), x,
  3357. # descrfld_ry)
  3358. #assert rs.y == a
  3359. #
  3360. descrsize = cpu.sizeof(S)
  3361. x = cpu.bh_new(descrsize)
  3362. lltype.cast_opaque_ptr(lltype.Ptr(S), x) # type check
  3363. #
  3364. X = lltype.GcStruct('X', ('parent', rclass.OBJECT))
  3365. _, T, descrsize2 = self.alloc_instance(X)
  3366. x = cpu.bh_new_with_vtable(descrsize2)
  3367. lltype.cast_opaque_ptr(lltype.Ptr(rclass.OBJECT), x) # type check
  3368. # well...
  3369. #assert x.getref(rclass.OBJECTPTR).typeptr == vtable2
  3370. #
  3371. arraydescr = cpu.arraydescrof(A)
  3372. x = cpu.bh_new_array(7, arraydescr)
  3373. array = lltype.cast_opaque_ptr(lltype.Ptr(A), x)
  3374. assert len(array) == 7
  3375. #
  3376. cpu.bh_setarrayitem_gc_i(x, 5, ord('*'), descr_A)
  3377. assert array[5] == '*'
  3378. #
  3379. cpu.bh_setarrayitem_gc_r(
  3380. lltype.cast_opaque_ptr(llmemory.GCREF, b), 1, x, descr_B)
  3381. assert b[1] == array
  3382. #
  3383. x = cpu.bh_newstr(5)
  3384. str = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), x)
  3385. assert len(str.chars) == 5
  3386. #
  3387. cpu.bh_strsetitem(x, 4, ord('/'))
  3388. assert str.chars[4] == '/'
  3389. def test_sorting_of_fields(self):
  3390. S = lltype.GcStruct('S', ('parent', rclass.OBJECT),
  3391. ('value', lltype.Signed),
  3392. ('chr1', lltype.Char),
  3393. ('chr2', lltype.Char))
  3394. self.alloc_instance(S)
  3395. chr1 = self.cpu.fielddescrof(S, 'chr1').sort_key()
  3396. value = self.cpu.fielddescrof(S, 'value').sort_key()
  3397. chr2 = self.cpu.fielddescrof(S, 'chr2').sort_key()
  3398. assert len(set([value, chr1, chr2])) == 3
  3399. def test_guards_nongc(self):
  3400. x = lltype.malloc(lltype.Struct('x'), flavor='raw')
  3401. v = heaptracker.adr2int(llmemory.cast_ptr_to_adr(x))
  3402. vbox = InputArgInt(v)
  3403. ops = [
  3404. (rop.GUARD_NONNULL, vbox, False),
  3405. (rop.GUARD_ISNULL, vbox, True),
  3406. (rop.GUARD_NONNULL, InputArgInt(0), True),
  3407. (rop.GUARD_ISNULL, InputArgInt(0), False),
  3408. ]
  3409. for opname, arg, res in ops:
  3410. self.execute_operation(opname, [arg], 'void')
  3411. assert self.guard_failed == res
  3412. lltype.free(x, flavor='raw')
  3413. def test_assembler_call(self):
  3414. called = []
  3415. def assembler_helper(deadframe, virtualizable):
  3416. assert self.cpu.get_int_value(deadframe, 0) == 97
  3417. called.append(self.cpu.get_latest_descr(deadframe))
  3418. return 4 + 9
  3419. FUNCPTR = lltype.Ptr(lltype.FuncType([llmemory.GCREF,
  3420. llmemory.GCREF],
  3421. lltype.Signed))
  3422. class FakeJitDriverSD:
  3423. index_of_virtualizable = -1
  3424. _assembler_helper_ptr = llhelper(FUNCPTR, assembler_helper)
  3425. assembler_helper_adr = llmemory.cast_ptr_to_adr(
  3426. _assembler_helper_ptr)
  3427. ops = '''
  3428. [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9]
  3429. i10 = int_add(i0, i1)
  3430. i11 = int_add(i10, i2)
  3431. i12 = int_add(i11, i3)
  3432. i13 = int_add(i12, i4)
  3433. i14 = int_add(i13, i5)
  3434. i15 = int_add(i14, i6)
  3435. i16 = int_add(i15, i7)
  3436. i17 = int_add(i16, i8)
  3437. i18 = int_add(i17, i9)
  3438. finish(i18)'''
  3439. loop = parse(ops)
  3440. looptoken = JitCellToken()
  3441. looptoken.outermost_jitdriver_sd = FakeJitDriverSD()
  3442. finish_descr = loop.operations[-1].getdescr()
  3443. self.cpu.done_with_this_frame_descr_int = BasicFinalDescr()
  3444. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  3445. ARGS = [lltype.Signed] * 10
  3446. RES = lltype.Signed
  3447. FakeJitDriverSD.portal_calldescr = self.cpu.calldescrof(
  3448. lltype.Ptr(lltype.FuncType(ARGS, RES)), ARGS, RES,
  3449. EffectInfo.MOST_GENERAL)
  3450. args = [i+1 for i in range(10)]
  3451. deadframe = self.cpu.execute_token(looptoken, *args)
  3452. assert self.cpu.get_int_value(deadframe, 0) == 55
  3453. ops = '''
  3454. [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9]
  3455. i10 = int_add(i0, 42)
  3456. i11 = call_assembler_i(i10, i1, i2, i3, i4, i5, i6, i7, i8, i9, descr=looptoken)
  3457. # NOTE: call_assembler_i() is turned into a single-argument version
  3458. # by rewrite.py
  3459. guard_not_forced()[]
  3460. finish(i11)
  3461. '''
  3462. loop = parse(ops, namespace=locals())
  3463. othertoken = JitCellToken()
  3464. self.cpu.compile_loop(loop.inputargs, loop.operations, othertoken)
  3465. args = [i+1 for i in range(10)]
  3466. deadframe = self.cpu.execute_token(othertoken, *args)
  3467. assert self.cpu.get_int_value(deadframe, 0) == 13
  3468. assert called == [finish_descr]
  3469. # test the fast path, which should not call assembler_helper()
  3470. del called[:]
  3471. self.cpu.done_with_this_frame_descr_int = finish_descr
  3472. othertoken = JitCellToken()
  3473. loop = parse(ops, namespace=locals())
  3474. self.cpu.compile_loop(loop.inputargs, loop.operations, othertoken)
  3475. args = [i+1 for i in range(10)]
  3476. deadframe = self.cpu.execute_token(othertoken, *args)
  3477. assert self.cpu.get_int_value(deadframe, 0) == 97
  3478. assert not called
  3479. def test_assembler_call_propagate_exc(self):
  3480. # WARNING: this test depends on test_memoryerror first passing
  3481. if not isinstance(self.cpu, AbstractLLCPU):
  3482. py.test.skip("llgraph can't fake exceptions well enough, give up")
  3483. excdescr = BasicFailDescr(666)
  3484. self.cpu.propagate_exception_descr = excdescr
  3485. self.cpu.setup_once() # xxx redo it, because we added
  3486. # propagate_exception
  3487. def assembler_helper(deadframe, virtualizable):
  3488. assert self.cpu.get_latest_descr(deadframe) is excdescr
  3489. # let's assume we handled that
  3490. return 3
  3491. FUNCPTR = lltype.Ptr(lltype.FuncType([llmemory.GCREF,
  3492. llmemory.GCREF],
  3493. lltype.Signed))
  3494. class FakeJitDriverSD:
  3495. index_of_virtualizable = -1
  3496. _assembler_helper_ptr = llhelper(FUNCPTR, assembler_helper)
  3497. assembler_helper_adr = llmemory.cast_ptr_to_adr(
  3498. _assembler_helper_ptr)
  3499. ops = '''
  3500. [i0]
  3501. p0 = newunicode(i0)
  3502. finish(p0)'''
  3503. loop = parse(ops)
  3504. looptoken = JitCellToken()
  3505. looptoken.outermost_jitdriver_sd = FakeJitDriverSD()
  3506. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  3507. ARGS = [lltype.Signed] * 10
  3508. RES = lltype.Signed
  3509. FakeJitDriverSD.portal_calldescr = self.cpu.calldescrof(
  3510. lltype.Ptr(lltype.FuncType(ARGS, RES)), ARGS, RES,
  3511. EffectInfo.MOST_GENERAL)
  3512. ops = '''
  3513. [i0]
  3514. i11 = call_assembler_i(i0, descr=looptoken)
  3515. guard_not_forced()[]
  3516. finish(i11)
  3517. '''
  3518. loop = parse(ops, namespace=locals())
  3519. othertoken = JitCellToken()
  3520. self.cpu.compile_loop(loop.inputargs, loop.operations, othertoken)
  3521. deadframe = self.cpu.execute_token(othertoken, sys.maxint - 1)
  3522. assert self.cpu.get_int_value(deadframe, 0) == 3
  3523. def test_assembler_call_float(self):
  3524. if not self.cpu.supports_floats:
  3525. py.test.skip("requires floats")
  3526. called = []
  3527. def assembler_helper(deadframe, virtualizable):
  3528. x = self.cpu.get_float_value(deadframe, 0)
  3529. assert longlong.getrealfloat(x) == 1.2 + 3.2
  3530. called.append(self.cpu.get_latest_descr(deadframe))
  3531. print '!' * 30 + 'assembler_helper'
  3532. return 13.5
  3533. FUNCPTR = lltype.Ptr(lltype.FuncType([llmemory.GCREF,
  3534. llmemory.GCREF],
  3535. lltype.Float))
  3536. class FakeJitDriverSD:
  3537. index_of_virtualizable = -1
  3538. _assembler_helper_ptr = llhelper(FUNCPTR, assembler_helper)
  3539. assembler_helper_adr = llmemory.cast_ptr_to_adr(
  3540. _assembler_helper_ptr)
  3541. ARGS = [lltype.Float, lltype.Float]
  3542. RES = lltype.Float
  3543. FakeJitDriverSD.portal_calldescr = self.cpu.calldescrof(
  3544. lltype.Ptr(lltype.FuncType(ARGS, RES)), ARGS, RES,
  3545. EffectInfo.MOST_GENERAL)
  3546. ops = '''
  3547. [f0, f1]
  3548. f2 = float_add(f0, f1)
  3549. finish(f2)'''
  3550. loop = parse(ops)
  3551. finish_descr = loop.operations[-1].getdescr()
  3552. looptoken = JitCellToken()
  3553. looptoken.outermost_jitdriver_sd = FakeJitDriverSD()
  3554. self.cpu.done_with_this_frame_descr_float = BasicFinalDescr()
  3555. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  3556. args = [longlong.getfloatstorage(1.2),
  3557. longlong.getfloatstorage(2.3)]
  3558. deadframe = self.cpu.execute_token(looptoken, *args)
  3559. x = self.cpu.get_float_value(deadframe, 0)
  3560. assert longlong.getrealfloat(x) == 1.2 + 2.3
  3561. ops = '''
  3562. [f4, f5]
  3563. f3 = call_assembler_f(f4, f5, descr=looptoken)
  3564. guard_not_forced()[]
  3565. finish(f3)
  3566. '''
  3567. loop = parse(ops, namespace=locals())
  3568. othertoken = JitCellToken()
  3569. self.cpu.compile_loop(loop.inputargs, loop.operations, othertoken)
  3570. args = [longlong.getfloatstorage(1.2),
  3571. longlong.getfloatstorage(3.2)]
  3572. deadframe = self.cpu.execute_token(othertoken, *args)
  3573. x = self.cpu.get_float_value(deadframe, 0)
  3574. assert longlong.getrealfloat(x) == 13.5
  3575. assert called == [finish_descr]
  3576. # test the fast path, which should not call assembler_helper()
  3577. del called[:]
  3578. self.cpu.done_with_this_frame_descr_float = finish_descr
  3579. othertoken = JitCellToken()
  3580. loop = parse(ops, namespace=locals())
  3581. self.cpu.compile_loop(loop.inputargs, loop.operations, othertoken)
  3582. args = [longlong.getfloatstorage(1.2),
  3583. longlong.getfloatstorage(4.2)]
  3584. deadframe = self.cpu.execute_token(othertoken, *args)
  3585. x = self.cpu.get_float_value(deadframe, 0)
  3586. assert longlong.getrealfloat(x) == 1.2 + 4.2
  3587. assert not called
  3588. def test_raw_malloced_getarrayitem(self):
  3589. ARRAY = rffi.CArray(lltype.Signed)
  3590. descr = self.cpu.arraydescrof(ARRAY)
  3591. a = lltype.malloc(ARRAY, 10, flavor='raw')
  3592. a[7] = -4242
  3593. addr = llmemory.cast_ptr_to_adr(a)
  3594. abox = InputArgInt(heaptracker.adr2int(addr))
  3595. r1 = self.execute_operation(rop.GETARRAYITEM_RAW_I, [abox, InputArgInt(7)],
  3596. 'int', descr=descr)
  3597. assert r1 == -4242
  3598. lltype.free(a, flavor='raw')
  3599. def test_raw_malloced_setarrayitem(self):
  3600. ARRAY = rffi.CArray(lltype.Signed)
  3601. descr = self.cpu.arraydescrof(ARRAY)
  3602. a = lltype.malloc(ARRAY, 10, flavor='raw')
  3603. addr = llmemory.cast_ptr_to_adr(a)
  3604. abox = InputArgInt(heaptracker.adr2int(addr))
  3605. self.execute_operation(rop.SETARRAYITEM_RAW, [abox, InputArgInt(5),
  3606. InputArgInt(12345)],
  3607. 'void', descr=descr)
  3608. assert a[5] == 12345
  3609. lltype.free(a, flavor='raw')
  3610. def test_redirect_call_assembler(self):
  3611. if not self.cpu.supports_floats:
  3612. py.test.skip("requires floats")
  3613. called = []
  3614. def assembler_helper(deadframe, virtualizable):
  3615. x = self.cpu.get_float_value(deadframe, 0)
  3616. assert longlong.getrealfloat(x) == 1.25 + 3.25
  3617. called.append(self.cpu.get_latest_descr(deadframe))
  3618. return 13.5
  3619. FUNCPTR = lltype.Ptr(lltype.FuncType([llmemory.GCREF, llmemory.GCREF],
  3620. lltype.Float))
  3621. class FakeJitDriverSD:
  3622. index_of_virtualizable = -1
  3623. _assembler_helper_ptr = llhelper(FUNCPTR, assembler_helper)
  3624. assembler_helper_adr = llmemory.cast_ptr_to_adr(
  3625. _assembler_helper_ptr)
  3626. ARGS = [lltype.Float, lltype.Float]
  3627. RES = lltype.Float
  3628. FakeJitDriverSD.portal_calldescr = self.cpu.calldescrof(
  3629. lltype.Ptr(lltype.FuncType(ARGS, RES)), ARGS, RES,
  3630. EffectInfo.MOST_GENERAL)
  3631. ops = '''
  3632. [f0, f1]
  3633. f2 = float_add(f0, f1)
  3634. finish(f2)'''
  3635. loop = parse(ops)
  3636. looptoken = JitCellToken()
  3637. looptoken.outermost_jitdriver_sd = FakeJitDriverSD()
  3638. self.cpu.done_with_this_frame_descr_float = BasicFinalDescr()
  3639. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  3640. finish_descr = loop.operations[-1].getdescr()
  3641. args = [longlong.getfloatstorage(1.25),
  3642. longlong.getfloatstorage(2.35)]
  3643. deadframe = self.cpu.execute_token(looptoken, *args)
  3644. x = self.cpu.get_float_value(deadframe, 0)
  3645. assert longlong.getrealfloat(x) == 1.25 + 2.35
  3646. assert not called
  3647. ops = '''
  3648. [f4, f5]
  3649. f3 = call_assembler_f(f4, f5, descr=looptoken)
  3650. guard_not_forced()[]
  3651. finish(f3)
  3652. '''
  3653. loop = parse(ops, namespace=locals())
  3654. othertoken = JitCellToken()
  3655. self.cpu.compile_loop(loop.inputargs, loop.operations, othertoken)
  3656. # normal call_assembler: goes to looptoken
  3657. args = [longlong.getfloatstorage(1.25),
  3658. longlong.getfloatstorage(3.25)]
  3659. deadframe = self.cpu.execute_token(othertoken, *args)
  3660. x = self.cpu.get_float_value(deadframe, 0)
  3661. assert longlong.getrealfloat(x) == 13.5
  3662. assert called == [finish_descr]
  3663. del called[:]
  3664. # compile a replacement which needs more jitframe stack space
  3665. ops = '''
  3666. [f0, f1]
  3667. f2 = float_sub(f0, f1)
  3668. f3 = float_sub(f0, f1)
  3669. f4 = float_sub(f0, f1)
  3670. f5 = float_sub(f0, f1)
  3671. f6 = float_sub(f0, f1)
  3672. f7 = float_sub(f0, f1)
  3673. f8 = float_sub(f0, f1)
  3674. f9 = float_sub(f0, f1)
  3675. f10 = float_sub(f0, f1)
  3676. f11 = float_sub(f0, f1)
  3677. f12 = float_sub(f0, f1)
  3678. f13 = float_sub(f0, f1)
  3679. f14 = float_sub(f0, f1)
  3680. f15 = float_sub(f0, f1)
  3681. f16 = float_sub(f0, f1)
  3682. f17 = float_sub(f0, f1)
  3683. f18 = float_sub(f0, f1)
  3684. f19 = float_sub(f0, f1)
  3685. i3 = float_eq(f2, f3)
  3686. i4 = float_eq(f2, f4)
  3687. i5 = float_eq(f2, f5)
  3688. i6 = float_eq(f2, f6)
  3689. i7 = float_eq(f2, f7)
  3690. i8 = float_eq(f2, f8)
  3691. i9 = float_eq(f2, f9)
  3692. i10 = float_eq(f2, f10)
  3693. i11 = float_eq(f2, f11)
  3694. i12 = float_eq(f2, f12)
  3695. i13 = float_eq(f2, f13)
  3696. i14 = float_eq(f2, f14)
  3697. i15 = float_eq(f2, f15)
  3698. i16 = float_eq(f2, f16)
  3699. i17 = float_eq(f2, f17)
  3700. i18 = float_eq(f2, f18)
  3701. i19 = float_eq(f2, f19)
  3702. guard_true(i3) []
  3703. guard_true(i4) []
  3704. guard_true(i5) []
  3705. guard_true(i6) []
  3706. guard_true(i7) []
  3707. guard_true(i8) []
  3708. guard_true(i9) []
  3709. guard_true(i10) []
  3710. guard_true(i11) []
  3711. guard_true(i12) []
  3712. guard_true(i13) []
  3713. guard_true(i14) []
  3714. guard_true(i15) []
  3715. guard_true(i16) []
  3716. guard_true(i17) []
  3717. guard_true(i18) []
  3718. guard_true(i19) []
  3719. finish(f2)'''
  3720. loop2 = parse(ops)
  3721. looptoken2 = JitCellToken()
  3722. looptoken2.outermost_jitdriver_sd = FakeJitDriverSD()
  3723. self.cpu.compile_loop(loop2.inputargs, loop2.operations, looptoken2)
  3724. finish_descr2 = loop2.operations[-1].getdescr()
  3725. # check the jitframeinfo
  3726. if isinstance(self.cpu, AbstractLLCPU):
  3727. num1 = looptoken.compiled_loop_token.frame_info.jfi_frame_depth
  3728. num2 = looptoken2.compiled_loop_token.frame_info.jfi_frame_depth
  3729. assert num1 < num2
  3730. # install it
  3731. self.cpu.redirect_call_assembler(looptoken, looptoken2)
  3732. # check that the jitframeinfo was updated
  3733. if isinstance(self.cpu, AbstractLLCPU):
  3734. num1 = looptoken.compiled_loop_token.frame_info.jfi_frame_depth
  3735. num2 = looptoken2.compiled_loop_token.frame_info.jfi_frame_depth
  3736. assert num1 == num2
  3737. # now, our call_assembler should go to looptoken2
  3738. args = [longlong.getfloatstorage(6.0),
  3739. longlong.getfloatstorage(1.5)] # 6.0-1.5 == 1.25+3.25
  3740. deadframe = self.cpu.execute_token(othertoken, *args)
  3741. x = self.cpu.get_float_value(deadframe, 0)
  3742. assert longlong.getrealfloat(x) == 13.5
  3743. assert called == [finish_descr2]
  3744. del called[:]
  3745. # compile a second replacement
  3746. ops = '''
  3747. [f0, f1]
  3748. f2 = float_mul(f0, f1)
  3749. finish(f2)'''
  3750. loop3 = parse(ops)
  3751. looptoken3 = JitCellToken()
  3752. looptoken3.outermost_jitdriver_sd = FakeJitDriverSD()
  3753. self.cpu.compile_loop(loop3.inputargs, loop3.operations, looptoken3)
  3754. finish_descr3 = loop3.operations[-1].getdescr()
  3755. # install it
  3756. self.cpu.redirect_call_assembler(looptoken2, looptoken3)
  3757. # now, our call_assembler should go to looptoken3
  3758. args = [longlong.getfloatstorage(0.5),
  3759. longlong.getfloatstorage(9.0)] # 0.5*9.0 == 1.25+3.25
  3760. deadframe = self.cpu.execute_token(othertoken, *args)
  3761. x = self.cpu.get_float_value(deadframe, 0)
  3762. assert longlong.getrealfloat(x) == 13.5
  3763. assert called == [finish_descr3]
  3764. del called[:]
  3765. def test_short_result_of_getfield_direct(self):
  3766. # Test that a getfield that returns a CHAR, SHORT or INT, signed
  3767. # or unsigned, properly gets zero-extended or sign-extended.
  3768. # Direct bh_xxx test.
  3769. cpu = self.cpu
  3770. for RESTYPE in [rffi.SIGNEDCHAR, rffi.UCHAR,
  3771. rffi.SHORT, rffi.USHORT,
  3772. rffi.INT, rffi.UINT,
  3773. rffi.LONG, rffi.ULONG]:
  3774. S = lltype.GcStruct('S', ('x', RESTYPE))
  3775. descrfld_x = cpu.fielddescrof(S, 'x')
  3776. s = lltype.malloc(S)
  3777. value = intmask(0xFFEEDDCCBBAA9988)
  3778. expected = rffi.cast(lltype.Signed, rffi.cast(RESTYPE, value))
  3779. s.x = rffi.cast(RESTYPE, value)
  3780. x = cpu.bh_getfield_gc_i(lltype.cast_opaque_ptr(llmemory.GCREF, s),
  3781. descrfld_x)
  3782. assert x == expected, (
  3783. "%r: got %r, expected %r" % (RESTYPE, x, expected))
  3784. def test_short_result_of_getfield_compiled(self):
  3785. # Test that a getfield that returns a CHAR, SHORT or INT, signed
  3786. # or unsigned, properly gets zero-extended or sign-extended.
  3787. # Machine code compilation test.
  3788. cpu = self.cpu
  3789. for RESTYPE in [rffi.SIGNEDCHAR, rffi.UCHAR,
  3790. rffi.SHORT, rffi.USHORT,
  3791. rffi.INT, rffi.UINT,
  3792. rffi.LONG, rffi.ULONG]:
  3793. S = lltype.GcStruct('S', ('x', RESTYPE))
  3794. descrfld_x = cpu.fielddescrof(S, 'x')
  3795. s = lltype.malloc(S)
  3796. value = intmask(0xFFEEDDCCBBAA9988)
  3797. expected = rffi.cast(lltype.Signed, rffi.cast(RESTYPE, value))
  3798. s.x = rffi.cast(RESTYPE, value)
  3799. s_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, s)
  3800. res = self.execute_operation(rop.GETFIELD_GC_I,
  3801. [InputArgRef(s_gcref)],
  3802. 'int', descr=descrfld_x)
  3803. assert res == expected, (
  3804. "%r: got %r, expected %r" % (RESTYPE, res, expected))
  3805. def test_short_result_of_getarrayitem_direct(self):
  3806. # Test that a getarrayitem that returns a CHAR, SHORT or INT, signed
  3807. # or unsigned, properly gets zero-extended or sign-extended.
  3808. # Direct bh_xxx test.
  3809. cpu = self.cpu
  3810. for RESTYPE in [rffi.SIGNEDCHAR, rffi.UCHAR,
  3811. rffi.SHORT, rffi.USHORT,
  3812. rffi.INT, rffi.UINT,
  3813. rffi.LONG, rffi.ULONG]:
  3814. A = lltype.GcArray(RESTYPE)
  3815. descrarray = cpu.arraydescrof(A)
  3816. a = lltype.malloc(A, 5)
  3817. value = intmask(0xFFEEDDCCBBAA9988)
  3818. expected = rffi.cast(lltype.Signed, rffi.cast(RESTYPE, value))
  3819. a[3] = rffi.cast(RESTYPE, value)
  3820. x = cpu.bh_getarrayitem_gc_i(
  3821. lltype.cast_opaque_ptr(llmemory.GCREF, a), 3, descrarray)
  3822. assert x == expected, (
  3823. "%r: got %r, expected %r" % (RESTYPE, x, expected))
  3824. def test_short_result_of_getarrayitem_compiled(self):
  3825. # Test that a getarrayitem that returns a CHAR, SHORT or INT, signed
  3826. # or unsigned, properly gets zero-extended or sign-extended.
  3827. # Machine code compilation test.
  3828. cpu = self.cpu
  3829. for RESTYPE in [rffi.SIGNEDCHAR, rffi.UCHAR,
  3830. rffi.SHORT, rffi.USHORT,
  3831. rffi.INT, rffi.UINT,
  3832. rffi.LONG, rffi.ULONG]:
  3833. A = lltype.GcArray(RESTYPE)
  3834. descrarray = cpu.arraydescrof(A)
  3835. a = lltype.malloc(A, 5)
  3836. value = intmask(0xFFEEDDCCBBAA9988)
  3837. expected = rffi.cast(lltype.Signed, rffi.cast(RESTYPE, value))
  3838. a[3] = rffi.cast(RESTYPE, value)
  3839. a_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, a)
  3840. res = self.execute_operation(rop.GETARRAYITEM_GC_I,
  3841. [InputArgRef(a_gcref), InputArgInt(3)],
  3842. 'int', descr=descrarray)
  3843. assert res == expected, (
  3844. "%r: got %r, expected %r" % (RESTYPE, res, expected))
  3845. def test_short_result_of_getarrayitem_raw_direct(self):
  3846. # Test that a getarrayitem that returns a CHAR, SHORT or INT, signed
  3847. # or unsigned, properly gets zero-extended or sign-extended.
  3848. # Direct bh_xxx test.
  3849. cpu = self.cpu
  3850. for RESTYPE in [rffi.SIGNEDCHAR, rffi.UCHAR,
  3851. rffi.SHORT, rffi.USHORT,
  3852. rffi.INT, rffi.UINT,
  3853. rffi.LONG, rffi.ULONG]:
  3854. A = rffi.CArray(RESTYPE)
  3855. descrarray = cpu.arraydescrof(A)
  3856. a = lltype.malloc(A, 5, flavor='raw')
  3857. value = intmask(0xFFEEDDCCBBAA9988)
  3858. expected = rffi.cast(lltype.Signed, rffi.cast(RESTYPE, value))
  3859. a[3] = rffi.cast(RESTYPE, value)
  3860. a_rawint = heaptracker.adr2int(llmemory.cast_ptr_to_adr(a))
  3861. x = cpu.bh_getarrayitem_raw_i(a_rawint, 3, descrarray)
  3862. assert x == expected, (
  3863. "%r: got %r, expected %r" % (RESTYPE, x, expected))
  3864. lltype.free(a, flavor='raw')
  3865. def test_short_result_of_getarrayitem_raw_compiled(self):
  3866. # Test that a getarrayitem that returns a CHAR, SHORT or INT, signed
  3867. # or unsigned, properly gets zero-extended or sign-extended.
  3868. # Machine code compilation test.
  3869. cpu = self.cpu
  3870. for RESTYPE in [rffi.SIGNEDCHAR, rffi.UCHAR,
  3871. rffi.SHORT, rffi.USHORT,
  3872. rffi.INT, rffi.UINT,
  3873. rffi.LONG, rffi.ULONG]:
  3874. A = rffi.CArray(RESTYPE)
  3875. descrarray = cpu.arraydescrof(A)
  3876. a = lltype.malloc(A, 5, flavor='raw')
  3877. value = intmask(0xFFEEDDCCBBAA9988)
  3878. expected = rffi.cast(lltype.Signed, rffi.cast(RESTYPE, value))
  3879. a[3] = rffi.cast(RESTYPE, value)
  3880. a_rawint = heaptracker.adr2int(llmemory.cast_ptr_to_adr(a))
  3881. res = self.execute_operation(rop.GETARRAYITEM_RAW_I,
  3882. [InputArgInt(a_rawint), InputArgInt(3)],
  3883. 'int', descr=descrarray)
  3884. assert res == expected, (
  3885. "%r: got %r, expected %r" % (RESTYPE, res, expected))
  3886. lltype.free(a, flavor='raw')
  3887. def test_short_result_of_call_direct(self):
  3888. # Test that calling a function that returns a CHAR, SHORT or INT,
  3889. # signed or unsigned, properly gets zero-extended or sign-extended.
  3890. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  3891. for RESTYPE in [rffi.SIGNEDCHAR, rffi.UCHAR,
  3892. rffi.SHORT, rffi.USHORT,
  3893. rffi.INT, rffi.UINT,
  3894. rffi.LONG, rffi.ULONG]:
  3895. # Tested with a function that intentionally does not cast the
  3896. # result to RESTYPE, but makes sure that we return the whole
  3897. # value in eax or rax.
  3898. eci = ExternalCompilationInfo(
  3899. separate_module_sources=["""
  3900. RPY_EXPORTED long fn_test_result_of_call(long x)
  3901. {
  3902. return x + 1;
  3903. }
  3904. """])
  3905. f = rffi.llexternal('fn_test_result_of_call', [lltype.Signed],
  3906. RESTYPE, compilation_info=eci, _nowrapper=True)
  3907. value = intmask(0xFFEEDDCCBBAA9988)
  3908. expected = rffi.cast(lltype.Signed, rffi.cast(RESTYPE, value + 1))
  3909. assert intmask(f(value)) == expected
  3910. #
  3911. FUNC = self.FuncType([lltype.Signed], RESTYPE)
  3912. FPTR = self.Ptr(FUNC)
  3913. calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  3914. EffectInfo.MOST_GENERAL)
  3915. x = self.cpu.bh_call_i(self.get_funcbox(self.cpu, f).value,
  3916. [value], None, None, calldescr)
  3917. assert x == expected, (
  3918. "%r: got %r, expected %r" % (RESTYPE, x, expected))
  3919. def test_short_result_of_call_compiled(self):
  3920. # Test that calling a function that returns a CHAR, SHORT or INT,
  3921. # signed or unsigned, properly gets zero-extended or sign-extended.
  3922. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  3923. for RESTYPE in [rffi.SIGNEDCHAR, rffi.UCHAR,
  3924. rffi.SHORT, rffi.USHORT,
  3925. rffi.INT, rffi.UINT,
  3926. rffi.LONG, rffi.ULONG]:
  3927. # Tested with a function that intentionally does not cast the
  3928. # result to RESTYPE, but makes sure that we return the whole
  3929. # value in eax or rax.
  3930. eci = ExternalCompilationInfo(
  3931. separate_module_sources=["""
  3932. RPY_EXPORTED long fn_test_result_of_call(long x)
  3933. {
  3934. return x + 1;
  3935. }
  3936. """])
  3937. f = rffi.llexternal('fn_test_result_of_call', [lltype.Signed],
  3938. RESTYPE, compilation_info=eci, _nowrapper=True)
  3939. value = intmask(0xFFEEDDCCBBAA9988)
  3940. expected = rffi.cast(lltype.Signed, rffi.cast(RESTYPE, value + 1))
  3941. assert intmask(f(value)) == expected
  3942. #
  3943. FUNC = self.FuncType([lltype.Signed], RESTYPE)
  3944. FPTR = self.Ptr(FUNC)
  3945. calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  3946. EffectInfo.MOST_GENERAL)
  3947. funcbox = self.get_funcbox(self.cpu, f)
  3948. res = self.execute_operation(rop.CALL_I, [funcbox, InputArgInt(value)],
  3949. 'int', descr=calldescr)
  3950. assert res == expected, (
  3951. "%r: got %r, expected %r" % (RESTYPE, res, expected))
  3952. def test_supports_longlong(self):
  3953. if IS_64_BIT:
  3954. assert not self.cpu.supports_longlong, (
  3955. "supports_longlong should be False on 64-bit platforms")
  3956. def test_longlong_result_of_call_direct(self):
  3957. if not self.cpu.supports_longlong:
  3958. py.test.skip("longlong test")
  3959. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  3960. from rpython.rlib.rarithmetic import r_longlong
  3961. eci = ExternalCompilationInfo(
  3962. separate_module_sources=["""
  3963. RPY_EXPORTED long long fn_test_result_of_call(long long x)
  3964. {
  3965. return x - 100000000000000;
  3966. }
  3967. """])
  3968. f = rffi.llexternal('fn_test_result_of_call', [lltype.SignedLongLong],
  3969. lltype.SignedLongLong,
  3970. compilation_info=eci, _nowrapper=True)
  3971. value = r_longlong(0x7ff05af3307a3fff)
  3972. expected = r_longlong(0x7ff000001fffffff)
  3973. assert f(value) == expected
  3974. #
  3975. FUNC = self.FuncType([lltype.SignedLongLong], lltype.SignedLongLong)
  3976. FPTR = self.Ptr(FUNC)
  3977. calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  3978. EffectInfo.MOST_GENERAL)
  3979. x = self.cpu.bh_call_f(self.get_funcbox(self.cpu, f).value,
  3980. None, None, [value], calldescr)
  3981. assert x == expected
  3982. def test_longlong_result_of_call_compiled(self):
  3983. if not self.cpu.supports_longlong:
  3984. py.test.skip("test of longlong result")
  3985. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  3986. from rpython.rlib.rarithmetic import r_longlong
  3987. eci = ExternalCompilationInfo(
  3988. separate_module_sources=["""
  3989. RPY_EXPORTED long long fn_test_result_of_call(long long x)
  3990. {
  3991. return x - 100000000000000;
  3992. }
  3993. """])
  3994. f = rffi.llexternal('fn_test_result_of_call', [lltype.SignedLongLong],
  3995. lltype.SignedLongLong,
  3996. compilation_info=eci, _nowrapper=True)
  3997. value = r_longlong(0x7ff05af3307a3fff)
  3998. expected = r_longlong(0x7ff000001fffffff)
  3999. assert f(value) == expected
  4000. #
  4001. FUNC = self.FuncType([lltype.SignedLongLong], lltype.SignedLongLong)
  4002. FPTR = self.Ptr(FUNC)
  4003. calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  4004. EffectInfo.MOST_GENERAL)
  4005. funcbox = self.get_funcbox(self.cpu, f)
  4006. res = self.execute_operation(rop.CALL_F,
  4007. [funcbox, InputArgFloat(value)],
  4008. 'float', descr=calldescr)
  4009. assert res == expected
  4010. def test_singlefloat_result_of_call_direct(self):
  4011. if not self.cpu.supports_singlefloats:
  4012. py.test.skip("singlefloat test")
  4013. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  4014. from rpython.rlib.rarithmetic import r_singlefloat
  4015. eci = ExternalCompilationInfo(
  4016. separate_module_sources=["""
  4017. RPY_EXPORTED float fn_test_result_of_call(float x)
  4018. {
  4019. return x / 2.0f;
  4020. }
  4021. """])
  4022. f = rffi.llexternal('fn_test_result_of_call', [lltype.SingleFloat],
  4023. lltype.SingleFloat,
  4024. compilation_info=eci, _nowrapper=True)
  4025. value = r_singlefloat(-42.5)
  4026. expected = r_singlefloat(-21.25)
  4027. assert f(value) == expected
  4028. #
  4029. FUNC = self.FuncType([lltype.SingleFloat], lltype.SingleFloat)
  4030. FPTR = self.Ptr(FUNC)
  4031. calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  4032. EffectInfo.MOST_GENERAL)
  4033. ivalue = longlong.singlefloat2int(value)
  4034. iexpected = longlong.singlefloat2int(expected)
  4035. x = self.cpu.bh_call_i(self.get_funcbox(self.cpu, f).value,
  4036. [ivalue], None, None, calldescr)
  4037. assert x == iexpected
  4038. def test_singlefloat_result_of_call_compiled(self):
  4039. if not self.cpu.supports_singlefloats:
  4040. py.test.skip("test of singlefloat result")
  4041. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  4042. from rpython.rlib.rarithmetic import r_singlefloat
  4043. eci = ExternalCompilationInfo(
  4044. separate_module_sources=["""
  4045. RPY_EXPORTED float fn_test_result_of_call(float x)
  4046. {
  4047. return x / 2.0f;
  4048. }
  4049. """])
  4050. f = rffi.llexternal('fn_test_result_of_call', [lltype.SingleFloat],
  4051. lltype.SingleFloat,
  4052. compilation_info=eci, _nowrapper=True)
  4053. value = r_singlefloat(-42.5)
  4054. expected = r_singlefloat(-21.25)
  4055. assert f(value) == expected
  4056. #
  4057. FUNC = self.FuncType([lltype.SingleFloat], lltype.SingleFloat)
  4058. FPTR = self.Ptr(FUNC)
  4059. calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  4060. EffectInfo.MOST_GENERAL)
  4061. funcbox = self.get_funcbox(self.cpu, f)
  4062. ivalue = longlong.singlefloat2int(value)
  4063. iexpected = longlong.singlefloat2int(expected)
  4064. res = self.execute_operation(rop.CALL_I, [funcbox, InputArgInt(ivalue)],
  4065. 'int', descr=calldescr)
  4066. assert res == iexpected
  4067. def test_free_loop_and_bridges(self):
  4068. if not isinstance(self.cpu, AbstractLLCPU):
  4069. py.test.skip("not a subclass of llmodel.AbstractLLCPU")
  4070. if hasattr(self.cpu, 'setup_once'):
  4071. self.cpu.setup_once()
  4072. mem0 = self.cpu.asmmemmgr.total_mallocs
  4073. looptoken = self.test_compile_bridge()
  4074. mem1 = self.cpu.asmmemmgr.total_mallocs
  4075. self.cpu.free_loop_and_bridges(looptoken.compiled_loop_token)
  4076. mem2 = self.cpu.asmmemmgr.total_mallocs
  4077. assert mem2 < mem1
  4078. assert mem2 == mem0
  4079. def test_memoryerror(self):
  4080. excdescr = BasicFailDescr(666)
  4081. self.cpu.propagate_exception_descr = excdescr
  4082. self.cpu.setup_once() # xxx redo it, because we added
  4083. # propagate_exception
  4084. i0 = InputArgInt()
  4085. p0 = ResOperation(rop.NEWUNICODE, [i0])
  4086. operations = [
  4087. p0,
  4088. ResOperation(rop.FINISH, [p0], descr=BasicFinalDescr(1))
  4089. ]
  4090. inputargs = [i0]
  4091. looptoken = JitCellToken()
  4092. self.cpu.compile_loop(inputargs, operations, looptoken)
  4093. # overflowing value:
  4094. unisize = self.cpu.gc_ll_descr.unicode_descr.itemsize
  4095. assert unisize in (2, 4)
  4096. deadframe = self.cpu.execute_token(looptoken, sys.maxint // unisize + 1)
  4097. fail = self.cpu.get_latest_descr(deadframe)
  4098. assert fail.identifier == excdescr.identifier
  4099. exc = self.cpu.grab_exc_value(deadframe)
  4100. assert not exc
  4101. def test_math_sqrt(self):
  4102. if not self.cpu.supports_floats:
  4103. py.test.skip("requires floats")
  4104. def math_sqrt(a):
  4105. assert False, 'should not be called'
  4106. from rpython.jit.codewriter.effectinfo import EffectInfo
  4107. effectinfo = EffectInfo([], [], [], [], [], [], EffectInfo.EF_CANNOT_RAISE, EffectInfo.OS_MATH_SQRT)
  4108. FPTR = self.Ptr(self.FuncType([lltype.Float], lltype.Float))
  4109. func_ptr = llhelper(FPTR, math_sqrt)
  4110. FUNC = deref(FPTR)
  4111. funcbox = self.get_funcbox(self.cpu, func_ptr)
  4112. calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, effectinfo)
  4113. testcases = [(4.0, 2.0), (6.25, 2.5)]
  4114. for arg, expected in testcases:
  4115. res = self.execute_operation(rop.CALL_F,
  4116. [funcbox, boxfloat(arg)],
  4117. 'float', descr=calldescr)
  4118. assert longlong.getrealfloat(res) == expected
  4119. def test_check_memory_error(self):
  4120. self.execute_operation(
  4121. rop.CHECK_MEMORY_ERROR, [InputArgInt(12345)], 'void')
  4122. py.test.raises(MissingLatestDescrError, self.execute_operation,
  4123. rop.CHECK_MEMORY_ERROR, [InputArgInt(0)], 'void')
  4124. def test_compile_loop_with_target(self):
  4125. looptoken = JitCellToken()
  4126. targettoken1 = TargetToken()
  4127. targettoken2 = TargetToken()
  4128. faildescr = BasicFailDescr(2)
  4129. faildescr3 = BasicFailDescr(3)
  4130. loop = parse("""
  4131. [i0]
  4132. label(i0, descr=targettoken1)
  4133. i1 = int_add(i0, 1)
  4134. i2 = int_le(i1, 9)
  4135. guard_true(i2, descr=faildescr) [i1]
  4136. label(i1, descr=targettoken2)
  4137. i3 = int_ge(i1, 0)
  4138. guard_true(i3, descr=faildescr3) [i1]
  4139. jump(i1, descr=targettoken1)
  4140. """, namespace=locals())
  4141. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  4142. deadframe = self.cpu.execute_token(looptoken, 2)
  4143. fail = self.cpu.get_latest_descr(deadframe)
  4144. assert fail.identifier == 2
  4145. res = self.cpu.get_int_value(deadframe, 0)
  4146. assert res == 10
  4147. bridge = parse("""
  4148. [i0]
  4149. i2 = int_sub(i0, 20)
  4150. jump(i2, descr=targettoken2)
  4151. """, namespace=locals())
  4152. self.cpu.compile_bridge(faildescr, bridge.inputargs,
  4153. bridge.operations, looptoken)
  4154. deadframe = self.cpu.execute_token(looptoken, 2)
  4155. fail = self.cpu.get_latest_descr(deadframe)
  4156. assert fail.identifier == 3
  4157. res = self.cpu.get_int_value(deadframe, 0)
  4158. assert res == -10
  4159. def test_int_force_ge_zero(self):
  4160. ops = """
  4161. [i0]
  4162. i1 = int_force_ge_zero(i0) # but forced to be in a register
  4163. finish(i1, descr=descr)
  4164. """
  4165. descr = BasicFinalDescr()
  4166. loop = parse(ops, self.cpu, namespace=locals())
  4167. looptoken = JitCellToken()
  4168. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  4169. for inp, outp in [(2,2), (-3, 0)]:
  4170. deadframe = self.cpu.execute_token(looptoken, inp)
  4171. assert outp == self.cpu.get_int_value(deadframe, 0)
  4172. def test_int_signext(self):
  4173. numbytes_cases = [1, 2] if IS_32_BIT else [1, 2, 4]
  4174. for spill in ["", "force_spill(i1)"]:
  4175. for numbytes in numbytes_cases:
  4176. print (spill, numbytes)
  4177. ops = """
  4178. [i0]
  4179. i1 = int_sub(i0, 0) # force in register
  4180. %s
  4181. i2 = int_signext(i1, %d)
  4182. finish(i2, descr=descr)
  4183. """ % (spill, numbytes)
  4184. descr = BasicFinalDescr()
  4185. loop = parse(ops, self.cpu, namespace=locals())
  4186. looptoken = JitCellToken()
  4187. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  4188. test_cases = [random.randrange(-sys.maxint-1, sys.maxint+1)
  4189. for _ in range(100)]
  4190. for test_case in test_cases:
  4191. deadframe = self.cpu.execute_token(looptoken, test_case)
  4192. got = self.cpu.get_int_value(deadframe, 0)
  4193. expected = heaptracker.int_signext(test_case, numbytes)
  4194. assert got == expected
  4195. def test_compile_asmlen(self):
  4196. if not isinstance(self.cpu, AbstractLLCPU):
  4197. py.test.skip("pointless test on non-asm")
  4198. from rpython.jit.backend.tool.viewcode import machine_code_dump, ObjdumpNotFound
  4199. import ctypes
  4200. targettoken = TargetToken()
  4201. ops = """
  4202. [i2]
  4203. i0 = same_as_i(i2) # but forced to be in a register
  4204. label(i0, descr=targettoken)
  4205. i1 = int_add(i0, i0)
  4206. guard_true(i1, descr=faildescr) [i1]
  4207. jump(i1, descr=targettoken)
  4208. """
  4209. faildescr = BasicFailDescr(2)
  4210. loop = parse(ops, self.cpu, namespace=locals())
  4211. bridge_ops = """
  4212. [i0]
  4213. jump(i0, descr=targettoken)
  4214. """
  4215. bridge = parse(bridge_ops, self.cpu, namespace=locals())
  4216. looptoken = JitCellToken()
  4217. self.cpu.assembler.set_debug(False)
  4218. info = self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  4219. bridge_info = self.cpu.compile_bridge(faildescr, bridge.inputargs,
  4220. bridge.operations,
  4221. looptoken)
  4222. self.cpu.assembler.set_debug(True) # always on untranslated
  4223. assert info.asmlen != 0
  4224. cpuname = autodetect()
  4225. # XXX we have to check the precise assembler, otherwise
  4226. # we don't quite know if borders are correct
  4227. def checkops(mc, ops_regexp):
  4228. import re
  4229. words = []
  4230. print '----- checkops -----'
  4231. for line in mc:
  4232. print line.rstrip()
  4233. t = line.split("\t")
  4234. if len(t) <= 2:
  4235. continue
  4236. w = t[2].split()
  4237. if len(w) == 0:
  4238. if '<UNDEFINED>' in line:
  4239. w = ['UNDEFINED']
  4240. else:
  4241. continue
  4242. words.append(w[0] + ';')
  4243. print '[[%s]]' % (w[0],)
  4244. text = ' '.join(words)
  4245. assert re.compile(ops_regexp).match(text)
  4246. data = ctypes.string_at(info.asmaddr, info.asmlen)
  4247. try:
  4248. mc = list(machine_code_dump(data, info.asmaddr, cpuname))
  4249. checkops(mc, self.add_loop_instructions)
  4250. data = ctypes.string_at(bridge_info.asmaddr, bridge_info.asmlen)
  4251. mc = list(machine_code_dump(data, bridge_info.asmaddr, cpuname))
  4252. checkops(mc, self.bridge_loop_instructions)
  4253. except ObjdumpNotFound:
  4254. py.test.skip("requires (g)objdump")
  4255. def test_compile_bridge_with_target(self):
  4256. # This test creates a loopy piece of code in a bridge, and builds another
  4257. # unrelated loop that ends in a jump directly to this loopy bit of code.
  4258. # It catches a case in which we underestimate the needed frame_depth across
  4259. # the cross-loop JUMP, because we estimate it based on the frame_depth stored
  4260. # in the original loop.
  4261. looptoken1 = JitCellToken()
  4262. targettoken1 = TargetToken()
  4263. faildescr1 = BasicFailDescr(2)
  4264. finaldescr1 = BasicFinalDescr(1234)
  4265. loop = parse("""
  4266. [i0]
  4267. i1 = int_le(i0, 1)
  4268. guard_true(i1, descr=faildescr1) [i0]
  4269. finish(i0, descr=finaldescr1)
  4270. """, namespace=locals())
  4271. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken1)
  4272. def func(a, b, c, d, e, f, g, h, i):
  4273. assert a + 2 == b
  4274. assert a + 4 == c
  4275. assert a + 6 == d
  4276. assert a + 8 == e
  4277. assert a + 10 == f
  4278. assert a + 12 == g
  4279. assert a + 14 == h
  4280. assert a + 16 == i
  4281. FPTR = self.Ptr(self.FuncType([lltype.Signed]*9, lltype.Void))
  4282. func_ptr = llhelper(FPTR, func)
  4283. cpu = self.cpu
  4284. calldescr = cpu.calldescrof(deref(FPTR), (lltype.Signed,)*9, lltype.Void,
  4285. EffectInfo.MOST_GENERAL)
  4286. faildescr=BasicFailDescr(42)
  4287. loop = parse("""
  4288. [i0]
  4289. label(i0, descr=targettoken1)
  4290. i1 = int_add(i0, 1)
  4291. i2 = int_add(i1, 1)
  4292. i3 = int_add(i2, 1)
  4293. i4 = int_add(i3, 1)
  4294. i5 = int_add(i4, 1)
  4295. i6 = int_add(i5, 1)
  4296. i7 = int_add(i6, 1)
  4297. i8 = int_add(i7, 1)
  4298. i9 = int_add(i8, 1)
  4299. i10 = int_add(i9, 1)
  4300. i11 = int_add(i10, 1)
  4301. i12 = int_add(i11, 1)
  4302. i13 = int_add(i12, 1)
  4303. i14 = int_add(i13, 1)
  4304. i15 = int_add(i14, 1)
  4305. i16 = int_add(i15, 1)
  4306. i17 = int_add(i16, 1)
  4307. i18 = int_add(i17, 1)
  4308. i19 = int_add(i18, 1)
  4309. call_n(ConstClass(func_ptr), i2, i4, i6, i8, i10, i12, i14, i16, i18, descr=calldescr)
  4310. call_n(ConstClass(func_ptr), i2, i4, i6, i8, i10, i12, i14, i16, i18, descr=calldescr)
  4311. i20 = int_lt(i19, 100)
  4312. guard_true(i20, descr=faildescr) []
  4313. jump(i19, descr=targettoken1)
  4314. """, namespace=locals())
  4315. self.cpu.compile_bridge(faildescr1, loop.inputargs,
  4316. loop.operations, looptoken1)
  4317. looptoken2 = JitCellToken()
  4318. inputargs = [InputArgInt()]
  4319. operations3 = [
  4320. ResOperation(rop.JUMP, [ConstInt(0)], descr=targettoken1),
  4321. ]
  4322. self.cpu.compile_loop(inputargs, operations3, looptoken2)
  4323. deadframe = self.cpu.execute_token(looptoken2, -9)
  4324. fail = self.cpu.get_latest_descr(deadframe)
  4325. assert fail.identifier == 42
  4326. def test_wrong_guard_nonnull_class(self):
  4327. t_box, T_box, _ = self.alloc_instance(self.T)
  4328. null_box = self.null_instance()
  4329. faildescr = BasicFailDescr(42)
  4330. operations = [
  4331. ResOperation(rop.GUARD_NONNULL_CLASS, [t_box, T_box],
  4332. descr=faildescr),
  4333. ResOperation(rop.FINISH, [], descr=BasicFinalDescr(1))]
  4334. operations[0].setfailargs([])
  4335. looptoken = JitCellToken()
  4336. inputargs = [t_box]
  4337. self.cpu.compile_loop(inputargs, operations, looptoken)
  4338. operations = [
  4339. ResOperation(rop.FINISH, [], descr=BasicFinalDescr(99))
  4340. ]
  4341. self.cpu.compile_bridge(faildescr, [], operations, looptoken)
  4342. deadframe = self.cpu.execute_token(looptoken, null_box.getref_base())
  4343. fail = self.cpu.get_latest_descr(deadframe)
  4344. assert fail.identifier == 99
  4345. def test_raw_load_int(self):
  4346. from rpython.rlib import rawstorage
  4347. for T in [rffi.UCHAR, rffi.SIGNEDCHAR,
  4348. rffi.USHORT, rffi.SHORT,
  4349. rffi.UINT, rffi.INT,
  4350. rffi.ULONG, rffi.LONG]:
  4351. ops = """
  4352. [i0, i1]
  4353. i2 = raw_load_i(i0, i1, descr=arraydescr)
  4354. finish(i2)
  4355. """
  4356. arraydescr = self.cpu.arraydescrof(rffi.CArray(T))
  4357. p = rawstorage.alloc_raw_storage(31)
  4358. for i in range(31):
  4359. p[i] = '\xDD'
  4360. value = rffi.cast(T, -0x4243444546474849)
  4361. rawstorage.raw_storage_setitem(p, 16, value)
  4362. got = self.cpu.bh_raw_load_i(rffi.cast(lltype.Signed, p), 16,
  4363. arraydescr)
  4364. assert got == rffi.cast(lltype.Signed, value)
  4365. #
  4366. loop = parse(ops, self.cpu, namespace=locals())
  4367. looptoken = JitCellToken()
  4368. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  4369. deadframe = self.cpu.execute_token(looptoken,
  4370. rffi.cast(lltype.Signed, p), 16)
  4371. result = self.cpu.get_int_value(deadframe, 0)
  4372. assert result == rffi.cast(lltype.Signed, value)
  4373. rawstorage.free_raw_storage(p)
  4374. def test_raw_load_float(self):
  4375. if not self.cpu.supports_floats:
  4376. py.test.skip("requires floats")
  4377. from rpython.rlib import rawstorage
  4378. for T in [rffi.DOUBLE]:
  4379. ops = """
  4380. [i0, i1]
  4381. f2 = raw_load_f(i0, i1, descr=arraydescr)
  4382. finish(f2)
  4383. """
  4384. arraydescr = self.cpu.arraydescrof(rffi.CArray(T))
  4385. p = rawstorage.alloc_raw_storage(31)
  4386. for i in range(31):
  4387. p[i] = '\xDD'
  4388. value = rffi.cast(T, 1.12e20)
  4389. rawstorage.raw_storage_setitem(p, 16, value)
  4390. got = self.cpu.bh_raw_load_f(rffi.cast(lltype.Signed, p), 16,
  4391. arraydescr)
  4392. got = longlong.getrealfloat(got)
  4393. assert got == rffi.cast(lltype.Float, value)
  4394. #
  4395. loop = parse(ops, self.cpu, namespace=locals())
  4396. looptoken = JitCellToken()
  4397. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  4398. deadframe = self.cpu.execute_token(looptoken,
  4399. rffi.cast(lltype.Signed, p), 16)
  4400. result = self.cpu.get_float_value(deadframe, 0)
  4401. result = longlong.getrealfloat(result)
  4402. assert result == rffi.cast(lltype.Float, value)
  4403. rawstorage.free_raw_storage(p)
  4404. def test_raw_load_singlefloat(self):
  4405. if not self.cpu.supports_singlefloats:
  4406. py.test.skip("requires singlefloats")
  4407. from rpython.rlib import rawstorage
  4408. for T in [rffi.FLOAT]:
  4409. ops = """
  4410. [i0, i1]
  4411. i2 = raw_load_i(i0, i1, descr=arraydescr)
  4412. finish(i2)
  4413. """
  4414. arraydescr = self.cpu.arraydescrof(rffi.CArray(T))
  4415. p = rawstorage.alloc_raw_storage(31)
  4416. for i in range(31):
  4417. p[i] = '\xDD'
  4418. value = rffi.cast(T, 1.12e20)
  4419. rawstorage.raw_storage_setitem(p, 16, value)
  4420. got = self.cpu.bh_raw_load_i(rffi.cast(lltype.Signed, p), 16,
  4421. arraydescr)
  4422. assert got == longlong.singlefloat2int(value)
  4423. #
  4424. loop = parse(ops, self.cpu, namespace=locals())
  4425. looptoken = JitCellToken()
  4426. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  4427. deadframe = self.cpu.execute_token(looptoken,
  4428. rffi.cast(lltype.Signed, p), 16)
  4429. result = self.cpu.get_int_value(deadframe, 0)
  4430. assert result == longlong.singlefloat2int(value)
  4431. rawstorage.free_raw_storage(p)
  4432. def test_raw_store_int(self):
  4433. from rpython.rlib import rawstorage
  4434. for T in [rffi.UCHAR, rffi.SIGNEDCHAR,
  4435. rffi.USHORT, rffi.SHORT,
  4436. rffi.UINT, rffi.INT,
  4437. rffi.ULONG, rffi.LONG]:
  4438. arraydescr = self.cpu.arraydescrof(rffi.CArray(T))
  4439. p = rawstorage.alloc_raw_storage(31)
  4440. value = (-0x4243444546474849) & sys.maxint
  4441. self.cpu.bh_raw_store_i(rffi.cast(lltype.Signed, p), 16, value,
  4442. arraydescr)
  4443. result = rawstorage.raw_storage_getitem(T, p, 16)
  4444. assert result == rffi.cast(T, value)
  4445. rawstorage.free_raw_storage(p)
  4446. #
  4447. ops = """
  4448. [i0, i1, i2]
  4449. raw_store(i0, i1, i2, descr=arraydescr)
  4450. finish()
  4451. """
  4452. p = rawstorage.alloc_raw_storage(31)
  4453. for i in range(31):
  4454. p[i] = '\xDD'
  4455. loop = parse(ops, self.cpu, namespace=locals())
  4456. looptoken = JitCellToken()
  4457. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  4458. self.cpu.execute_token(looptoken,
  4459. rffi.cast(lltype.Signed, p), 16, value)
  4460. result = rawstorage.raw_storage_getitem(T, p, 16)
  4461. assert result == rffi.cast(T, value)
  4462. rawstorage.free_raw_storage(p)
  4463. def test_raw_store_float(self):
  4464. if not self.cpu.supports_floats:
  4465. py.test.skip("requires floats")
  4466. from rpython.rlib import rawstorage
  4467. for T in [rffi.DOUBLE]:
  4468. arraydescr = self.cpu.arraydescrof(rffi.CArray(T))
  4469. p = rawstorage.alloc_raw_storage(31)
  4470. value = 1.23e20
  4471. self.cpu.bh_raw_store_f(rffi.cast(lltype.Signed, p), 16,
  4472. longlong.getfloatstorage(value),
  4473. arraydescr)
  4474. result = rawstorage.raw_storage_getitem(T, p, 16)
  4475. assert result == rffi.cast(T, value)
  4476. rawstorage.free_raw_storage(p)
  4477. #
  4478. ops = """
  4479. [i0, i1, f2]
  4480. raw_store(i0, i1, f2, descr=arraydescr)
  4481. finish()
  4482. """
  4483. p = rawstorage.alloc_raw_storage(31)
  4484. for i in range(31):
  4485. p[i] = '\xDD'
  4486. loop = parse(ops, self.cpu, namespace=locals())
  4487. looptoken = JitCellToken()
  4488. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  4489. self.cpu.execute_token(looptoken,
  4490. rffi.cast(lltype.Signed, p), 16,
  4491. longlong.getfloatstorage(value))
  4492. result = rawstorage.raw_storage_getitem(T, p, 16)
  4493. assert result == rffi.cast(T, value)
  4494. rawstorage.free_raw_storage(p)
  4495. def test_raw_store_singlefloat(self):
  4496. if not self.cpu.supports_singlefloats:
  4497. py.test.skip("requires singlefloats")
  4498. from rpython.rlib import rawstorage
  4499. for T in [rffi.FLOAT]:
  4500. arraydescr = self.cpu.arraydescrof(rffi.CArray(T))
  4501. p = rawstorage.alloc_raw_storage(31)
  4502. value = rffi.cast(T, 1.23e20)
  4503. self.cpu.bh_raw_store_i(rffi.cast(lltype.Signed, p), 16,
  4504. longlong.singlefloat2int(value),
  4505. arraydescr)
  4506. result = rawstorage.raw_storage_getitem(T, p, 16)
  4507. assert (rffi.cast(lltype.Float, result) ==
  4508. rffi.cast(lltype.Float, value))
  4509. rawstorage.free_raw_storage(p)
  4510. #
  4511. ops = """
  4512. [i0, i1, i2]
  4513. raw_store(i0, i1, i2, descr=arraydescr)
  4514. finish()
  4515. """
  4516. p = rawstorage.alloc_raw_storage(31)
  4517. for i in range(31):
  4518. p[i] = '\xDD'
  4519. loop = parse(ops, self.cpu, namespace=locals())
  4520. looptoken = JitCellToken()
  4521. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  4522. self.cpu.execute_token(looptoken,
  4523. rffi.cast(lltype.Signed, p), 16,
  4524. longlong.singlefloat2int(value))
  4525. result = rawstorage.raw_storage_getitem(T, p, 16)
  4526. assert (rffi.cast(lltype.Float, result) ==
  4527. rffi.cast(lltype.Float, value))
  4528. rawstorage.free_raw_storage(p)
  4529. def test_forcing_op_with_fail_arg_in_reg(self):
  4530. values = []
  4531. def maybe_force(token, flag):
  4532. deadframe = self.cpu.force(token)
  4533. values.append(self.cpu.get_int_value(deadframe, 0))
  4534. return 42
  4535. FUNC = self.FuncType([llmemory.GCREF, lltype.Signed], lltype.Signed)
  4536. func_ptr = llhelper(lltype.Ptr(FUNC), maybe_force)
  4537. calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  4538. EffectInfo.MOST_GENERAL)
  4539. finaldescr=BasicFinalDescr(0)
  4540. faildescr = BasicFailDescr(23)
  4541. loop = parse("""
  4542. [i0, i1]
  4543. p2 = force_token()
  4544. i3 = call_may_force_i(ConstClass(func_ptr), p2, i1, descr=calldescr)
  4545. guard_not_forced(descr=faildescr) [i3]
  4546. finish(i3, descr=finaldescr)
  4547. """, namespace=locals())
  4548. looptoken = JitCellToken()
  4549. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  4550. deadframe = self.cpu.execute_token(looptoken, 20, 0)
  4551. fail = self.cpu.get_latest_descr(deadframe)
  4552. assert fail.identifier == 23
  4553. assert self.cpu.get_int_value(deadframe, 0) == 42
  4554. def test_compile_bridge_while_running(self):
  4555. def func():
  4556. bridge = parse("""
  4557. [i1, i2, px]
  4558. i3 = int_add(i1, i2)
  4559. i4 = int_add(i1, i3)
  4560. i5 = int_add(i1, i4)
  4561. i6 = int_add(i4, i5)
  4562. i7 = int_add(i6, i5)
  4563. i8 = int_add(i5, 1)
  4564. i9 = int_add(i8, 1)
  4565. force_spill(i1)
  4566. force_spill(i2)
  4567. force_spill(i3)
  4568. force_spill(i4)
  4569. force_spill(i5)
  4570. force_spill(i6)
  4571. force_spill(i7)
  4572. force_spill(i8)
  4573. force_spill(i9)
  4574. call_n(ConstClass(func2_ptr), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, descr=calldescr2)
  4575. guard_true(i1, descr=guarddescr) [i1, i2, i3, i4, i5, i6, i7, i8, i9, px]
  4576. finish(i1, descr=finaldescr)
  4577. """, namespace={'finaldescr': finaldescr, 'calldescr2': calldescr2,
  4578. 'guarddescr': guarddescr, 'func2_ptr': func2_ptr})
  4579. self.cpu.compile_bridge(faildescr, bridge.inputargs,
  4580. bridge.operations, looptoken)
  4581. cpu = self.cpu
  4582. finaldescr = BasicFinalDescr(13)
  4583. finaldescr2 = BasicFinalDescr(133)
  4584. guarddescr = BasicFailDescr(8)
  4585. FUNC = self.FuncType([], lltype.Void)
  4586. FPTR = self.Ptr(FUNC)
  4587. func_ptr = llhelper(FPTR, func)
  4588. calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  4589. EffectInfo.MOST_GENERAL)
  4590. def func2(a, b, c, d, e, f, g, h, i, j, k, l):
  4591. pass
  4592. FUNC2 = self.FuncType([lltype.Signed] * 12, lltype.Void)
  4593. FPTR2 = self.Ptr(FUNC2)
  4594. func2_ptr = llhelper(FPTR2, func2)
  4595. calldescr2 = cpu.calldescrof(FUNC2, FUNC2.ARGS, FUNC2.RESULT,
  4596. EffectInfo.MOST_GENERAL)
  4597. faildescr = BasicFailDescr(0)
  4598. looptoken = JitCellToken()
  4599. loop = parse("""
  4600. [i0, i1, i2]
  4601. call_n(ConstClass(func_ptr), descr=calldescr)
  4602. px = force_token()
  4603. guard_true(i0, descr=faildescr) [i1, i2, px]
  4604. finish(i2, descr=finaldescr2)
  4605. """, namespace=locals())
  4606. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  4607. frame = self.cpu.execute_token(looptoken, 0, 0, 3)
  4608. assert self.cpu.get_latest_descr(frame) is guarddescr
  4609. if not isinstance(self.cpu, AbstractLLCPU):
  4610. py.test.skip("pointless test on non-asm")
  4611. frame = lltype.cast_opaque_ptr(jitframe.JITFRAMEPTR, frame)
  4612. assert len(frame.jf_frame) == frame.jf_frame_info.jfi_frame_depth
  4613. ref = self.cpu.get_ref_value(frame, 9)
  4614. token = lltype.cast_opaque_ptr(jitframe.JITFRAMEPTR, ref)
  4615. assert token != frame
  4616. token = token.resolve()
  4617. assert token == frame
  4618. def test_compile_bridge_while_running_guard_no_exc(self):
  4619. xtp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
  4620. xtp.subclassrange_min = 1
  4621. xtp.subclassrange_max = 3
  4622. X = lltype.GcStruct('X', ('parent', rclass.OBJECT),
  4623. hints={'vtable': xtp._obj})
  4624. xptr = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(X))
  4625. def raising():
  4626. bridge = parse("""
  4627. [i1, i2]
  4628. px = guard_exception(ConstClass(xtp), descr=faildescr2) [i1, i2]
  4629. i3 = int_add(i1, i2)
  4630. i4 = int_add(i1, i3)
  4631. i5 = int_add(i1, i4)
  4632. i6 = int_add(i4, i5)
  4633. i7 = int_add(i6, i5)
  4634. i8 = int_add(i5, 1)
  4635. i9 = int_add(i8, 1)
  4636. force_spill(i1)
  4637. force_spill(i2)
  4638. force_spill(i3)
  4639. force_spill(i4)
  4640. force_spill(i5)
  4641. force_spill(i6)
  4642. force_spill(i7)
  4643. force_spill(i8)
  4644. force_spill(i9)
  4645. i10 = int_is_true(i9)
  4646. guard_true(i10) [i3, i4, i5, i6, i7, i8, i9]
  4647. finish(i9, descr=finaldescr)
  4648. """, namespace={'finaldescr': BasicFinalDescr(42),
  4649. 'faildescr2': BasicFailDescr(1),
  4650. 'xtp': xtp
  4651. })
  4652. self.cpu.compile_bridge(faildescr, bridge.inputargs,
  4653. bridge.operations, looptoken)
  4654. raise LLException(xtp, xptr)
  4655. faildescr = BasicFailDescr(0)
  4656. FUNC = self.FuncType([], lltype.Void)
  4657. raising_ptr = llhelper(lltype.Ptr(FUNC), raising)
  4658. calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
  4659. EffectInfo.MOST_GENERAL)
  4660. looptoken = JitCellToken()
  4661. loop = parse("""
  4662. [i0, i1, i2]
  4663. call_n(ConstClass(raising_ptr), descr=calldescr)
  4664. guard_no_exception(descr=faildescr) [i1, i2]
  4665. finish(i2, descr=finaldescr2)
  4666. """, namespace={'raising_ptr': raising_ptr,
  4667. 'calldescr': calldescr,
  4668. 'faildescr': faildescr,
  4669. 'finaldescr2': BasicFinalDescr(1)})
  4670. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  4671. frame = self.cpu.execute_token(looptoken, 1, 2, 3)
  4672. descr = self.cpu.get_latest_descr(frame)
  4673. assert descr.identifier == 42
  4674. assert not self.cpu.grab_exc_value(frame)
  4675. def test_setarrayitem_raw_short(self):
  4676. # setarrayitem_raw(140737353744432, 0, 30583, descr=<ArrayS 2>)
  4677. A = rffi.CArray(rffi.SHORT)
  4678. arraydescr = self.cpu.arraydescrof(A)
  4679. a = lltype.malloc(A, 2, flavor='raw')
  4680. a[0] = rffi.cast(rffi.SHORT, 666)
  4681. a[1] = rffi.cast(rffi.SHORT, 777)
  4682. addr = llmemory.cast_ptr_to_adr(a)
  4683. a_int = heaptracker.adr2int(addr)
  4684. print 'a_int:', a_int
  4685. self.execute_operation(rop.SETARRAYITEM_RAW,
  4686. [ConstInt(a_int), ConstInt(0), ConstInt(-7654)],
  4687. 'void', descr=arraydescr)
  4688. assert rffi.cast(lltype.Signed, a[0]) == -7654
  4689. assert rffi.cast(lltype.Signed, a[1]) == 777
  4690. lltype.free(a, flavor='raw')
  4691. def test_increment_debug_counter(self):
  4692. foo = lltype.malloc(rffi.CArray(lltype.Signed), 1, flavor='raw')
  4693. foo[0] = 1789200
  4694. self.execute_operation(rop.INCREMENT_DEBUG_COUNTER,
  4695. [ConstInt(rffi.cast(lltype.Signed, foo))],
  4696. 'void')
  4697. assert foo[0] == 1789201
  4698. lltype.free(foo, flavor='raw')
  4699. def test_cast_float_to_singlefloat(self):
  4700. if not self.cpu.supports_singlefloats:
  4701. py.test.skip("requires singlefloats")
  4702. res = self.execute_operation(rop.CAST_FLOAT_TO_SINGLEFLOAT,
  4703. [boxfloat(12.5)], 'int')
  4704. assert res == struct.unpack("I", struct.pack("f", 12.5))[0]
  4705. def test_zero_array(self):
  4706. if not isinstance(self.cpu, AbstractLLCPU):
  4707. py.test.skip("llgraph does not do zero_array")
  4708. PAIR = lltype.Struct('PAIR', ('a', lltype.Signed), ('b', lltype.Signed))
  4709. for OF in [lltype.Signed, rffi.INT, rffi.SHORT, rffi.UCHAR, PAIR]:
  4710. A = lltype.GcArray(OF)
  4711. arraydescr = self.cpu.arraydescrof(A)
  4712. a = lltype.malloc(A, 100)
  4713. addr = llmemory.cast_ptr_to_adr(a)
  4714. a_int = heaptracker.adr2int(addr)
  4715. a_ref = lltype.cast_opaque_ptr(llmemory.GCREF, a)
  4716. for (start, length) in [(0, 100), (49, 49), (1, 98),
  4717. (15, 9), (10, 10), (47, 0),
  4718. (0, 4)]:
  4719. for cls1 in [ConstInt, InputArgInt]:
  4720. for cls2 in [ConstInt, InputArgInt]:
  4721. print 'a_int:', a_int
  4722. print 'of:', OF
  4723. print 'start:', cls1.__name__, start
  4724. print 'length:', cls2.__name__, length
  4725. for i in range(100):
  4726. if OF == PAIR:
  4727. a[i].a = a[i].b = -123456789
  4728. else:
  4729. a[i] = rffi.cast(OF, -123456789)
  4730. startbox = cls1(start)
  4731. lengthbox = cls2(length)
  4732. if cls1 == cls2 and start == length:
  4733. lengthbox = startbox # same box!
  4734. scale = arraydescr.itemsize
  4735. ops = []
  4736. def emit(op):
  4737. ops.append(op)
  4738. helper = GcRewriterAssembler(None, self.cpu)
  4739. helper.emit_op = emit
  4740. offset = 0
  4741. scale_start, s_offset, v_start = \
  4742. helper._emit_mul_if_factor_offset_not_supported(
  4743. startbox, scale, offset)
  4744. if v_start is None:
  4745. v_start = ConstInt(s_offset)
  4746. scale_len, e_offset, v_len = \
  4747. helper._emit_mul_if_factor_offset_not_supported(
  4748. lengthbox, scale, offset)
  4749. if v_len is None:
  4750. v_len = ConstInt(e_offset)
  4751. args = [InputArgRef(a_ref), v_start, v_len,
  4752. ConstInt(scale_start), ConstInt(scale_len)]
  4753. ops.append(ResOperation(rop.ZERO_ARRAY, args,
  4754. descr=arraydescr))
  4755. scalebox = ConstInt(arraydescr.itemsize)
  4756. inputargs, oplist = self._get_operation_list(ops,'void')
  4757. self.execute_operations(inputargs, oplist, 'void')
  4758. assert len(a) == 100
  4759. for i in range(100):
  4760. val = (0 if start <= i < start + length
  4761. else -123456789)
  4762. if OF == PAIR:
  4763. assert a[i].a == a[i].b == val
  4764. else:
  4765. assert a[i] == rffi.cast(OF, val)
  4766. def test_jump_float_constant(self):
  4767. loop = parse("""
  4768. [f0, f1]
  4769. label(f0, f1, descr=targettoken)
  4770. i2 = cast_float_to_int(f1)
  4771. guard_value(i2, 123456, descr=faildescr6) []
  4772. f3 = float_add(f0, -0.5)
  4773. i4 = float_gt(f3, 9.12)
  4774. guard_true(i4, descr=faildescr2) [f1, f3]
  4775. jump(f3, 123456.78912, descr=targettoken)
  4776. """, namespace={'targettoken': TargetToken(),
  4777. 'faildescr2': BasicFailDescr(2),
  4778. 'faildescr6': BasicFailDescr(6)})
  4779. looptoken = JitCellToken()
  4780. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  4781. deadframe = self.cpu.execute_token(looptoken,
  4782. longlong.getfloatstorage(12.25),
  4783. longlong.getfloatstorage(123456.01))
  4784. fail = self.cpu.get_latest_descr(deadframe)
  4785. assert fail.identifier == 2
  4786. res = longlong.getrealfloat(self.cpu.get_float_value(deadframe, 0))
  4787. assert res == 123456.78912
  4788. res = longlong.getrealfloat(self.cpu.get_float_value(deadframe, 1))
  4789. assert res == 8.75
  4790. def test_passing_guard_gc_type_struct(self):
  4791. if not self.cpu.supports_guard_gc_type:
  4792. py.test.skip("guard_gc_type not available")
  4793. t_box, _, descr = self.alloc_instance(self.T)
  4794. c_typeid = ConstInt(descr.get_type_id())
  4795. self.execute_operation(rop.GUARD_GC_TYPE, [t_box, c_typeid], 'void')
  4796. assert not self.guard_failed
  4797. #
  4798. got_typeid = self.cpu.get_actual_typeid(t_box.getref_base())
  4799. assert got_typeid == c_typeid.getint()
  4800. def test_passing_guard_gc_type_array(self):
  4801. if not self.cpu.supports_guard_gc_type:
  4802. py.test.skip("guard_gc_type not available")
  4803. a_box, A = self.alloc_array_of(rffi.SHORT, 342)
  4804. arraydescr = self.cpu.arraydescrof(A)
  4805. c_typeid = ConstInt(arraydescr.get_type_id())
  4806. self.execute_operation(rop.GUARD_GC_TYPE, [a_box, c_typeid], 'void')
  4807. assert not self.guard_failed
  4808. #
  4809. got_typeid = self.cpu.get_actual_typeid(a_box.getref_base())
  4810. assert got_typeid == c_typeid.getint()
  4811. def test_failing_guard_gc_type(self):
  4812. if not self.cpu.supports_guard_gc_type:
  4813. py.test.skip("guard_gc_type not available")
  4814. t_box, _, tdescr = self.alloc_instance(self.T)
  4815. u_box, _, udescr = self.alloc_instance(self.U)
  4816. a_box, A = self.alloc_array_of(rffi.SHORT, 342)
  4817. adescr = self.cpu.arraydescrof(A)
  4818. c_ttypeid = ConstInt(tdescr.get_type_id())
  4819. c_utypeid = ConstInt(udescr.get_type_id())
  4820. c_atypeid = ConstInt(adescr.get_type_id())
  4821. for opname, args in [(rop.GUARD_GC_TYPE, [t_box, c_utypeid]),
  4822. (rop.GUARD_GC_TYPE, [u_box, c_ttypeid]),
  4823. (rop.GUARD_GC_TYPE, [a_box, c_utypeid]),
  4824. (rop.GUARD_GC_TYPE, [t_box, c_atypeid]),
  4825. ]:
  4826. assert self.execute_operation(opname, args, 'void') == None
  4827. assert self.guard_failed
  4828. #
  4829. got_typeid = self.cpu.get_actual_typeid(args[0].getref_base())
  4830. assert got_typeid != args[1].getint()
  4831. def test_guard_is_object(self):
  4832. if not self.cpu.supports_guard_gc_type:
  4833. py.test.skip("guard_gc_type not available")
  4834. t_box, _, _ = self.alloc_instance(self.T)
  4835. self.execute_operation(rop.GUARD_IS_OBJECT, [t_box], 'void')
  4836. assert not self.guard_failed
  4837. assert self.cpu.check_is_object(t_box.getref_base())
  4838. #
  4839. a_box, _ = self.alloc_array_of(rffi.SHORT, 342)
  4840. self.execute_operation(rop.GUARD_IS_OBJECT, [a_box], 'void')
  4841. assert self.guard_failed
  4842. assert not self.cpu.check_is_object(a_box.getref_base())
  4843. #
  4844. S = lltype.GcStruct('S')
  4845. s = lltype.malloc(S, immortal=True, zero=True)
  4846. s_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, s))
  4847. self.execute_operation(rop.GUARD_IS_OBJECT, [s_box], 'void')
  4848. assert self.guard_failed
  4849. assert not self.cpu.check_is_object(s_box.getref_base())
  4850. def test_guard_subclass(self):
  4851. if not self.cpu.supports_guard_gc_type:
  4852. py.test.skip("guard_gc_type not available")
  4853. xtp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
  4854. xtp.subclassrange_min = 1
  4855. xtp.subclassrange_max = 3
  4856. X = lltype.GcStruct('X', ('parent', rclass.OBJECT),
  4857. hints={'vtable': xtp._obj})
  4858. xptr = lltype.malloc(X)
  4859. xptr.parent.typeptr = xtp
  4860. x_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, xptr))
  4861. X_box = ConstInt(heaptracker.adr2int(llmemory.cast_ptr_to_adr(xtp)))
  4862. ytp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
  4863. ytp.subclassrange_min = 2
  4864. ytp.subclassrange_max = 2
  4865. assert rclass.ll_issubclass(ytp, xtp)
  4866. Y = lltype.GcStruct('Y', ('parent', X),
  4867. hints={'vtable': ytp._obj})
  4868. yptr = lltype.malloc(Y)
  4869. yptr.parent.parent.typeptr = ytp
  4870. y_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, yptr))
  4871. Y_box = ConstInt(heaptracker.adr2int(llmemory.cast_ptr_to_adr(ytp)))
  4872. ztp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
  4873. ztp.subclassrange_min = 4
  4874. ztp.subclassrange_max = 5
  4875. assert not rclass.ll_issubclass(ztp, xtp)
  4876. assert not rclass.ll_issubclass(xtp, ztp)
  4877. Z = lltype.GcStruct('Z', ('parent', rclass.OBJECT),
  4878. hints={'vtable': ztp._obj})
  4879. zptr = lltype.malloc(Z)
  4880. zptr.parent.typeptr = ztp
  4881. z_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, zptr))
  4882. Z_box = ConstInt(heaptracker.adr2int(llmemory.cast_ptr_to_adr(ztp)))
  4883. for num, arg, klass, is_subclass in [
  4884. (1, x_box, X_box, True),
  4885. (2, x_box, Y_box, False),
  4886. (3, x_box, Z_box, False),
  4887. (4, y_box, X_box, True),
  4888. (5, y_box, Y_box, True),
  4889. (6, y_box, Z_box, False),
  4890. (7, z_box, X_box, False),
  4891. (8, z_box, Y_box, False),
  4892. (9, z_box, Z_box, True),
  4893. ]:
  4894. self.execute_operation(rop.GUARD_SUBCLASS, [arg, klass], 'void')
  4895. assert self.guard_failed == (not is_subclass)
  4896. def test_bug_from_optimize_cond_call(self):
  4897. loop = parse("""
  4898. [i0, i1]
  4899. i99 = int_sub(i0, i0)
  4900. force_spill(i99)
  4901. i2 = int_add(i0, i1)
  4902. i3 = int_add(i0, i1)
  4903. i4 = int_add(i0, i1)
  4904. i5 = int_add(i0, i1)
  4905. i6 = int_add(i0, i1)
  4906. i7 = int_add(i0, i1)
  4907. i8 = int_add(i0, i1)
  4908. i9 = int_add(i0, i1)
  4909. i10 = int_add(i0, i1)
  4910. i11 = int_add(i0, i1)
  4911. i12 = int_add(i0, i1)
  4912. i13 = int_add(i0, i1)
  4913. i14 = int_add(i0, i1)
  4914. i15 = int_add(i0, i1)
  4915. i16 = int_add(i0, i1)
  4916. i17 = int_add(i0, i1)
  4917. i18 = int_add(i0, i1)
  4918. i19 = int_add(i0, i1)
  4919. i20 = int_is_true(i99)
  4920. force_spill(i0)
  4921. force_spill(i1)
  4922. force_spill(i2)
  4923. force_spill(i3)
  4924. force_spill(i4)
  4925. force_spill(i5)
  4926. force_spill(i6)
  4927. force_spill(i7)
  4928. force_spill(i8)
  4929. force_spill(i9)
  4930. force_spill(i10)
  4931. force_spill(i11)
  4932. force_spill(i12)
  4933. force_spill(i13)
  4934. force_spill(i14)
  4935. force_spill(i15)
  4936. force_spill(i16)
  4937. force_spill(i17)
  4938. force_spill(i18)
  4939. force_spill(i19)
  4940. finish(i20, descr=finaldescr)
  4941. """, namespace={"finaldescr": BasicFinalDescr(1)})
  4942. looptoken = JitCellToken()
  4943. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  4944. deadframe = self.cpu.execute_token(looptoken, 40, 2)
  4945. fail = self.cpu.get_latest_descr(deadframe)
  4946. res = self.cpu.get_int_value(deadframe, 0)
  4947. assert res == 0
  4948. def test_load_from_gc_table_many(self):
  4949. # Test that 'load_from_gc_table' handles a table of NUM entries.
  4950. # Done by writing NUM setfield_gc on constants. Each one
  4951. # requires a load_from_gc_table. The value of NUM is choosen
  4952. # so that not all of them fit into the ARM's 4096-bytes offset.
  4953. NUM = 1025
  4954. S = lltype.GcStruct('S', ('x', lltype.Signed))
  4955. fielddescr = self.cpu.fielddescrof(S, 'x')
  4956. table = [lltype.malloc(S) for i in range(NUM)]
  4957. looptoken = JitCellToken()
  4958. targettoken = TargetToken()
  4959. ops = [
  4960. '[]',
  4961. ]
  4962. namespace = {'fielddescr': fielddescr,
  4963. 'finaldescr': BasicFinalDescr(5)}
  4964. for i, s in enumerate(table):
  4965. ops.append('setfield_gc(ConstPtr(ptr%d), %d, descr=fielddescr)'
  4966. % (i, i))
  4967. namespace['ptr%d' % i] = lltype.cast_opaque_ptr(llmemory.GCREF, s)
  4968. ops.append('finish(descr=finaldescr)')
  4969. loop = parse('\n'.join(ops), namespace=namespace)
  4970. self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
  4971. deadframe = self.cpu.execute_token(looptoken)
  4972. fail = self.cpu.get_latest_descr(deadframe)
  4973. assert fail.identifier == 5
  4974. # check that all setfield_gc() worked
  4975. for i, s in enumerate(table):
  4976. assert s.x == i