/rpython/jit/backend/test/runner_test.py
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
- import py, sys, random, os, struct, operator
- from rpython.jit.metainterp.history import (AbstractFailDescr,
- AbstractDescr,
- BasicFailDescr,
- BasicFinalDescr,
- JitCellToken, TargetToken,
- ConstInt, ConstPtr,
- ConstFloat, Const)
- from rpython.jit.metainterp.resoperation import ResOperation, rop, InputArgInt,\
- InputArgFloat, opname, InputArgRef
- from rpython.jit.metainterp.typesystem import deref
- from rpython.jit.metainterp.executor import wrap_constant
- from rpython.jit.codewriter.effectinfo import EffectInfo
- from rpython.jit.tool.oparser import parse
- from rpython.rtyper.lltypesystem import lltype, llmemory, rstr, rffi
- from rpython.rtyper import rclass
- from rpython.rtyper.annlowlevel import llhelper
- from rpython.rtyper.llinterp import LLException
- from rpython.jit.codewriter import heaptracker, longlong
- from rpython.rlib import longlong2float
- from rpython.rlib.rarithmetic import intmask, is_valid_int
- from rpython.jit.backend.detect_cpu import autodetect
- from rpython.jit.backend.llsupport import jitframe
- from rpython.jit.backend.llsupport.llmodel import AbstractLLCPU
- from rpython.jit.backend.llsupport.llmodel import MissingLatestDescrError
- from rpython.jit.backend.llsupport.rewrite import GcRewriterAssembler
- IS_32_BIT = sys.maxint < 2**32
- IS_64_BIT = sys.maxint > 2**32
- boxfloat = InputArgFloat.fromfloat
- constfloat = ConstFloat.fromfloat
- def clone(op):
- if op.type == 'i':
- return InputArgInt(op.getint())
- elif op.type == 'r':
- return InputArgRef(op.getref_base())
- return InputArgFloat(op.getfloatstorage())
- def boxlonglong(ll):
- if longlong.is_64_bit:
- return InputArgInt(ll)
- else:
- return InputArgFloat(ll)
- STUFF = lltype.GcStruct('STUFF')
- random_gcref = lltype.cast_opaque_ptr(llmemory.GCREF,
- lltype.malloc(STUFF, immortal=True))
- class Runner(object):
- add_loop_instructions = ['overload for a specific cpu']
- bridge_loop_instructions = ['overload for a specific cpu']
-
- def execute_operation(self, opname, valueboxes, result_type, descr=None):
- inputargs, operations = self._get_single_operation_list(opname,
- result_type,
- valueboxes,
- descr)
- return self.execute_operations(inputargs, operations, result_type)
- def execute_operations(self, inputargs, operations, result_type):
- looptoken = JitCellToken()
- self.cpu.compile_loop(inputargs, operations, looptoken)
- args = []
- for box in inputargs:
- if box.type == 'i':
- args.append(box.getint())
- elif box.type == 'r':
- args.append(box.getref_base())
- elif box.type == 'f':
- args.append(box.getfloatstorage())
- else:
- raise NotImplementedError(box)
- deadframe = self.cpu.execute_token(looptoken, *args)
- if self.cpu.get_latest_descr(deadframe) is operations[-1].getdescr():
- self.guard_failed = False
- else:
- self.guard_failed = True
- if result_type == 'int':
- return self.cpu.get_int_value(deadframe, 0)
- elif result_type == 'ref':
- return self.cpu.get_ref_value(deadframe, 0)
- elif result_type == 'float':
- return self.cpu.get_float_value(deadframe, 0)
- elif result_type == 'void':
- return None
- else:
- assert False
- def _get_operation_list(self, operations, result_type):
- inputargs = []
- blacklist = set()
- for op in operations:
- for arg in op.getarglist():
- if not isinstance(arg, Const) and arg not in inputargs and \
- arg not in blacklist:
- inputargs.append(arg)
- if op.type != 'v':
- blacklist.add(op)
- if result_type == 'void':
- op1 = ResOperation(rop.FINISH, [], descr=BasicFinalDescr(0))
- else:
- op1 = ResOperation(rop.FINISH, [operations[-1]], descr=BasicFinalDescr(0))
- operations.append(op1)
- return inputargs, operations
- def _get_single_operation_list(self, opnum, result_type, valueboxes,
- descr):
- op0 = ResOperation(opnum, valueboxes)
- if result_type == 'void':
- op1 = ResOperation(rop.FINISH, [], descr=BasicFinalDescr(0))
- else:
- op1 = ResOperation(rop.FINISH, [op0], descr=BasicFinalDescr(0))
- operations = [op0, op1]
- if operations[0].is_guard():
- operations[0].setfailargs([])
- if not descr:
- descr = BasicFailDescr(1)
- if descr is not None:
- operations[0].setdescr(descr)
- inputargs = []
- for box in valueboxes:
- if not isinstance(box, Const) and box not in inputargs:
- inputargs.append(box)
- return inputargs, operations
- class BaseBackendTest(Runner):
- avoid_instances = False
- def setup_method(self, _):
- self.cpu = self.get_cpu()
- self.cpu.done_with_this_frame_descr_int = None
- self.cpu.done_with_this_frame_descr_ref = None
- self.cpu.done_with_this_frame_descr_float = None
- self.cpu.done_with_this_frame_descr_void = None
- def test_compile_linear_loop(self):
- loop = parse("""
- [i0]
- i1 = int_add(i0, 1)
- finish(i1, descr=faildescr)
- """, namespace={"faildescr": BasicFinalDescr(1)})
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, 2)
- fail = self.cpu.get_latest_descr(deadframe)
- res = self.cpu.get_int_value(deadframe, 0)
- assert res == 3
- assert fail.identifier == 1
- def test_compile_linear_float_loop(self):
- if not self.cpu.supports_floats:
- py.test.skip("requires floats")
- loop = parse("""
- [f0]
- f1 = float_add(f0, 2.3)
- finish(f1, descr=fdescr)
- """, namespace={'fdescr': BasicFinalDescr(1)})
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken,
- longlong.getfloatstorage(2.8))
- fail = self.cpu.get_latest_descr(deadframe)
- res = self.cpu.get_float_value(deadframe, 0)
- assert longlong.getrealfloat(res) == 5.1
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 1
- def test_compile_loop(self):
- looptoken = JitCellToken()
- targettoken = TargetToken()
- loop = parse("""
- [i0]
- label(i0, descr=targettoken)
- i1 = int_add(i0, 1)
- i2 = int_le(i1, 9)
- guard_true(i2, descr=fdescr) [i1]
- jump(i1, descr=targettoken)
- """, namespace={'targettoken': targettoken,
- 'fdescr': BasicFailDescr(2)})
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, 2)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 2
- res = self.cpu.get_int_value(deadframe, 0)
- assert res == 10
- def test_compile_with_holes_in_fail_args(self):
- targettoken = TargetToken()
- loop = parse("""
- [i3]
- i0 = int_sub(i3, 42)
- label(i0, descr=targettoken)
- i1 = int_add(i0, 1)
- i2 = int_le(i1, 9)
- guard_true(i2, descr=fdescr) []
- jump(i1, descr=targettoken)
- """, namespace={'targettoken': targettoken,
- 'fdescr': BasicFailDescr(2)})
- looptoken = JitCellToken()
- loop.operations[4].setfailargs([None, None, loop.operations[2], None])
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, 44)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 2
- res = self.cpu.get_int_value(deadframe, 2)
- assert res == 10
- def test_backends_dont_keep_loops_alive(self):
- import weakref, gc
- self.cpu.dont_keepalive_stuff = True
- targettoken = TargetToken()
- loop = parse("""
- [i0]
- label(i0, descr=targettoken)
- i1 = int_add(i0, 1)
- i2 = int_le(i1, 9)
- guard_true(i2, descr=fdescr) [i1]
- jump(i1, descr=targettoken)
- """, namespace={'targettoken': targettoken, 'fdescr': BasicFailDescr()})
- looptoken = JitCellToken()
- wr_i1 = weakref.ref(loop.operations[1])
- wr_guard = weakref.ref(loop.operations[3])
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- if hasattr(looptoken, '_x86_ops_offset'):
- del looptoken._x86_ops_offset # else it's kept alive
- if hasattr(looptoken, '_ppc_ops_offset'):
- del looptoken._ppc_ops_offset # else it's kept alive
- if hasattr(looptoken, '_zarch_ops_offset'):
- del looptoken._zarch_ops_offset # else it's kept alive
- del loop
- gc.collect()
- assert not wr_i1() and not wr_guard()
- def test_compile_bridge(self):
- self.cpu.tracker.total_compiled_loops = 0
- self.cpu.tracker.total_compiled_bridges = 0
- targettoken = TargetToken()
- faildescr1 = BasicFailDescr(1)
- faildescr2 = BasicFailDescr(2)
- loop = parse("""
- [i0]
- label(i0, descr=targettoken)
- i1 = int_add(i0, 1)
- i2 = int_le(i1, 9)
- guard_true(i2, descr=faildescr1) [i1]
- jump(i1, descr=targettoken)
- """, namespace={'targettoken': targettoken,
- 'faildescr1': faildescr1})
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- bridge = parse("""
- [i1]
- i3 = int_le(i1, 19)
- guard_true(i3, descr=faildescr2) [i1]
- jump(i1, descr=targettoken)
- """, namespace={"targettoken": targettoken,
- 'faildescr2': faildescr2})
- self.cpu.compile_bridge(faildescr1, bridge.inputargs,
- bridge.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, 2)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 2
- res = self.cpu.get_int_value(deadframe, 0)
- assert res == 20
- assert self.cpu.tracker.total_compiled_loops == 1
- assert self.cpu.tracker.total_compiled_bridges == 1
- return looptoken
- def test_compile_bridge_with_holes(self):
- faildescr1 = BasicFailDescr(1)
- faildescr2 = BasicFailDescr(2)
- looptoken = JitCellToken()
- targettoken = TargetToken()
- loop = parse("""
- [i3]
- i0 = int_sub(i3, 42)
- label(i0, descr=targettoken)
- i1 = int_add(i0, 1)
- i2 = int_le(i1, 9)
- guard_true(i2, descr=faildescr1) []
- jump(i1, descr=targettoken)
- """, namespace={'targettoken': targettoken,
- 'faildescr1': faildescr1})
- loop.operations[-2].setfailargs([None, loop.operations[2], None])
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- bridge = parse("""
- [i1]
- i3 = int_le(i1, 19)
- guard_true(i3, descr=faildescr2) [i1]
- jump(i1, descr=targettoken)
- """, namespace={'targettoken': targettoken,
- 'faildescr2': faildescr2})
- self.cpu.compile_bridge(faildescr1, bridge.inputargs,
- bridge.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, 2)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 2
- res = self.cpu.get_int_value(deadframe, 0)
- assert res == 20
- def test_compile_big_bridge_out_of_small_loop(self):
- faildescr1 = BasicFailDescr(1)
- loop = parse("""
- [i0]
- guard_false(i0, descr=faildescr1) [i0]
- finish(descr=finaldescr)
- """, namespace={'faildescr1': faildescr1,
- 'finaldescr': BasicFinalDescr(2)})
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- bridge = []
- i0 = InputArgInt()
- iprev = i0
- for i in range(150):
- iprev = ResOperation(rop.INT_ADD, [iprev, ConstInt(1)])
- bridge.append(iprev)
- bridge.append(ResOperation(rop.GUARD_FALSE, [i0],
- descr=BasicFailDescr(3)))
- bridge.append(ResOperation(rop.FINISH, [],
- descr=BasicFinalDescr(4)))
- bridge[-2].setfailargs(bridge[:-2])
- self.cpu.compile_bridge(faildescr1, [i0], bridge, looptoken)
- deadframe = self.cpu.execute_token(looptoken, 1)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 3
- for i in range(150):
- res = self.cpu.get_int_value(deadframe, i)
- assert res == 2 + i
- def test_finish(self):
- from rpython.jit.backend.llsupport.llmodel import final_descr_rd_locs
- class UntouchableFailDescr(AbstractFailDescr):
- final_descr = True
- rd_locs = final_descr_rd_locs
- def __setattr__(self, name, value):
- if (name == 'index' or name == '_carry_around_for_tests'
- or name == '_TYPE' or name == '_cpu'):
- return AbstractFailDescr.__setattr__(self, name, value)
- py.test.fail("finish descrs should not be touched")
- faildescr = UntouchableFailDescr() # to check that is not touched
- looptoken = JitCellToken()
- loop = parse("""
- [i0]
- finish(i0, descr=faildescr)
- """, namespace={'faildescr': faildescr})
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, 99)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail is faildescr
- res = self.cpu.get_int_value(deadframe, 0)
- assert res == 99
- looptoken = JitCellToken()
- operations = [
- ResOperation(rop.FINISH, [ConstInt(42)], descr=faildescr)
- ]
- self.cpu.compile_loop([], operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail is faildescr
- res = self.cpu.get_int_value(deadframe, 0)
- assert res == 42
- looptoken = JitCellToken()
- operations = [
- ResOperation(rop.FINISH, [], descr=faildescr)
- ]
- self.cpu.compile_loop([], operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail is faildescr
- if self.cpu.supports_floats:
- looptoken = JitCellToken()
- f0 = InputArgFloat()
- operations = [
- ResOperation(rop.FINISH, [f0], descr=faildescr)
- ]
- self.cpu.compile_loop([f0], operations, looptoken)
- value = longlong.getfloatstorage(-61.25)
- deadframe = self.cpu.execute_token(looptoken, value)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail is faildescr
- res = self.cpu.get_float_value(deadframe, 0)
- assert longlong.getrealfloat(res) == -61.25
- looptoken = JitCellToken()
- operations = [
- ResOperation(rop.FINISH, [constfloat(42.5)], descr=faildescr)
- ]
- self.cpu.compile_loop([], operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail is faildescr
- res = self.cpu.get_float_value(deadframe, 0)
- assert longlong.getrealfloat(res) == 42.5
- def test_execute_operations_in_env(self):
- cpu = self.cpu
- targettoken = TargetToken()
- loop = parse("""
- [i1, i0]
- label(i0, i1, descr=targettoken)
- i2 = int_add(i1, i0)
- i3 = int_sub(i0, 1)
- i4 = int_eq(i3, 0)
- guard_false(i4, descr=fdescr) [i3, i2]
- jump(i3, i2, descr=targettoken)
- """, namespace={'targettoken': targettoken,
- 'fdescr': BasicFailDescr()})
- looptoken = JitCellToken()
- cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, 0, 10)
- assert self.cpu.get_int_value(deadframe, 0) == 0
- assert self.cpu.get_int_value(deadframe, 1) == 55
- def test_int_operations(self):
- from rpython.jit.metainterp.test.test_executor import get_int_tests
- for opnum, boxargs, retvalue in get_int_tests():
- print opnum
- res = self.execute_operation(opnum, boxargs, 'int')
- assert res == retvalue
- def test_float_operations(self):
- from rpython.jit.metainterp.test.test_executor import get_float_tests
- from rpython.jit.metainterp.resoperation import opname
- for opnum, boxargs, rettype, retvalue in get_float_tests(self.cpu):
- print("testing", opname[opnum])
- res = self.execute_operation(opnum, boxargs, rettype)
- if rettype == 'float':
- res = longlong.getrealfloat(res)
- assert res == retvalue
- def test_ovf_operations(self, reversed=False):
- minint = -sys.maxint-1
- boom = 'boom'
- for opnum, testcases in [
- (rop.INT_ADD_OVF, [(10, -2, 8),
- (-1, minint, boom),
- (sys.maxint//2, sys.maxint//2+2, boom)]),
- (rop.INT_SUB_OVF, [(-20, -23, 3),
- (-2, sys.maxint, boom),
- (sys.maxint//2, -(sys.maxint//2+2), boom)]),
- (rop.INT_MUL_OVF, [(minint/2, 2, minint),
- (-2, -(minint/2), minint),
- (minint/2, -2, boom)]),
- ]:
- v1 = InputArgInt(testcases[0][0])
- v2 = InputArgInt(testcases[0][1])
- #
- if not reversed:
- op0 = ResOperation(opnum, [v1, v2])
- op1 = ResOperation(rop.GUARD_NO_OVERFLOW, [],
- descr=BasicFailDescr(1))
- op2 = ResOperation(rop.FINISH, [op0], descr=BasicFinalDescr(2))
- ops = [op0, op1, op2]
- op1.setfailargs([])
- else:
- op0 = ResOperation(opnum, [v1, v2])
- op1 = ResOperation(rop.GUARD_OVERFLOW, [],
- descr=BasicFailDescr(1))
- op2 = ResOperation(rop.FINISH, [], descr=BasicFinalDescr(2))
- ops = [op0, op1, op2]
- op1.setfailargs([op0])
- #
- looptoken = JitCellToken()
- self.cpu.compile_loop([v1, v2], ops, looptoken)
- for x, y, z in testcases:
- deadframe = self.cpu.execute_token(looptoken, x, y)
- fail = self.cpu.get_latest_descr(deadframe)
- if (z == boom) ^ reversed:
- assert fail.identifier == 1
- else:
- assert fail.identifier == 2
- if z != boom:
- assert self.cpu.get_int_value(deadframe, 0) == z
- excvalue = self.cpu.grab_exc_value(deadframe)
- assert not excvalue
- def test_ovf_operations_reversed(self):
- self.test_ovf_operations(reversed=True)
- def test_bh_call(self):
- cpu = self.cpu
- #
- def func(c):
- return chr(ord(c) + 1)
- FPTR = self.Ptr(self.FuncType([lltype.Char], lltype.Char))
- func_ptr = llhelper(FPTR, func)
- calldescr = cpu.calldescrof(deref(FPTR), (lltype.Char,), lltype.Char,
- EffectInfo.MOST_GENERAL)
- x = cpu.bh_call_i(self.get_funcbox(cpu, func_ptr).value,
- [ord('A')], None, None, calldescr)
- assert x == ord('B')
- if cpu.supports_floats:
- def func(f, i):
- assert isinstance(f, float)
- assert is_valid_int(i)
- return f - float(i)
- FPTR = self.Ptr(self.FuncType([lltype.Float, lltype.Signed],
- lltype.Float))
- func_ptr = llhelper(FPTR, func)
- FTP = deref(FPTR)
- calldescr = cpu.calldescrof(FTP, FTP.ARGS, FTP.RESULT,
- EffectInfo.MOST_GENERAL)
- x = cpu.bh_call_f(self.get_funcbox(cpu, func_ptr).value,
- [42], None, [longlong.getfloatstorage(3.5)],
- calldescr)
- assert longlong.getrealfloat(x) == 3.5 - 42
- def test_call(self):
- from rpython.rlib.jit_libffi import types
- def func_int(a, b):
- return a + b
- def func_char(c, c1):
- return chr(ord(c) + ord(c1))
- functions = [
- (func_int, lltype.Signed, types.sint, 655360, 655360),
- (func_int, lltype.Signed, types.sint, 655360, -293999429),
- (func_int, rffi.SHORT, types.sint16, 1213, 1213),
- (func_int, rffi.SHORT, types.sint16, 1213, -12020),
- (func_char, lltype.Char, types.uchar, 12, 12),
- ]
- cpu = self.cpu
- for func, TP, ffi_type, num, num1 in functions:
- #
- FPTR = self.Ptr(self.FuncType([TP, TP], TP))
- func_ptr = llhelper(FPTR, func)
- FUNC = deref(FPTR)
- funcbox = self.get_funcbox(cpu, func_ptr)
- # first, try it with the "normal" calldescr
- calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
- res = self.execute_operation(rop.CALL_I,
- [funcbox, InputArgInt(num),
- InputArgInt(num1)],
- 'int', descr=calldescr)
- assert res == num + num1
- # then, try it with the dynamic calldescr
- dyn_calldescr = cpu._calldescr_dynamic_for_tests(
- [ffi_type, ffi_type], ffi_type)
- res = self.execute_operation(rop.CALL_I,
- [funcbox, InputArgInt(num),
- InputArgInt(num1)],
- 'int', descr=dyn_calldescr)
- assert res == num + num1
- # last, try it with one constant argument
- calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL)
- res = self.execute_operation(rop.CALL_I,
- [funcbox, ConstInt(num),
- InputArgInt(num1)],
- 'int', descr=calldescr)
- assert res == num + num1
- if cpu.supports_floats:
- def func(f0, f1, f2, f3, f4, f5, f6, i0, f7, i1, f8, f9):
- seen.append((f0, f1, f2, f3, f4, f5, f6, i0, f7, i1, f8, f9))
- return f0 + f1 + f2 + f3 + f4 + f5 + f6 + float(i0 + i1) + f7 + f8 + f9
- seen = []
- F = lltype.Float
- I = lltype.Signed
- FUNC = self.FuncType([F] * 7 + [I] + [F] + [I] + [F]* 2, F)
- FPTR = self.Ptr(FUNC)
- func_ptr = llhelper(FPTR, func)
- calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
- funcbox = self.get_funcbox(cpu, func_ptr)
- args = ([boxfloat(.0), boxfloat(.1), boxfloat(.2), boxfloat(.3),
- boxfloat(.4), boxfloat(.5), boxfloat(.6),
- InputArgInt(1), boxfloat(.7), InputArgInt(2), boxfloat(.8),
- boxfloat(.9)])
- res = self.execute_operation(rop.CALL_F,
- [funcbox] + args,
- 'float', descr=calldescr)
- assert seen == [(.0, .1, .2, .3, .4, .5, .6, 1, .7, 2, .8, .9)]
- assert abs(longlong.getrealfloat(res) - 7.5) < 0.0001
- def test_call_many_arguments(self):
- # Test calling a function with a large number of arguments (more than
- # 6, which will force passing some arguments on the stack on 64-bit)
- def func(*args):
- assert len(args) == 16
- # Try to sum up args in a way that would probably detect a
- # transposed argument
- return sum(arg * (2**i) for i, arg in enumerate(args))
- FUNC = self.FuncType([lltype.Signed]*16, lltype.Signed)
- FPTR = self.Ptr(FUNC)
- calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
- func_ptr = llhelper(FPTR, func)
- args = range(16)
- funcbox = self.get_funcbox(self.cpu, func_ptr)
- res = self.execute_operation(rop.CALL_I, [funcbox] + map(InputArgInt, args), 'int', descr=calldescr)
- assert res == func(*args)
- def test_call_box_func(self):
- def a(a1, a2):
- return a1 + a2
- def b(b1, b2):
- return b1 * b2
- arg1 = 40
- arg2 = 2
- for f in [a, b]:
- TP = lltype.Signed
- FPTR = self.Ptr(self.FuncType([TP, TP], TP))
- func_ptr = llhelper(FPTR, f)
- FUNC = deref(FPTR)
- funcconst = self.get_funcbox(self.cpu, func_ptr)
- funcbox = InputArgInt(funcconst.getint())
- calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
- res = self.execute_operation(rop.CALL_I,
- [funcbox, InputArgInt(arg1),
- InputArgInt(arg2)],
- 'int', descr=calldescr)
- assert res == f(arg1, arg2)
- def test_call_stack_alignment(self):
- # test stack alignment issues, notably for Mac OS/X.
- # also test the ordering of the arguments.
- def func_ints(*ints):
- s = str(ints) + '\n'
- os.write(1, s) # don't remove -- crash if the stack is misaligned
- return sum([(10+i)*(5+j) for i, j in enumerate(ints)])
- for nb_args in range(0, 35):
- cpu = self.cpu
- TP = lltype.Signed
- #
- FPTR = self.Ptr(self.FuncType([TP] * nb_args, TP))
- func_ptr = llhelper(FPTR, func_ints)
- FUNC = deref(FPTR)
- calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
- funcbox = self.get_funcbox(cpu, func_ptr)
- args = [280-24*i for i in range(nb_args)]
- res = self.execute_operation(rop.CALL_I,
- [funcbox] + map(InputArgInt, args),
- 'int', descr=calldescr)
- assert res == func_ints(*args)
- def test_call_with_const_floats(self):
- if not self.cpu.supports_floats:
- py.test.skip("requires floats")
- def func(f1, f2):
- return f1 + f2
- FUNC = self.FuncType([lltype.Float, lltype.Float], lltype.Float)
- FPTR = self.Ptr(FUNC)
- calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
- func_ptr = llhelper(FPTR, func)
- funcbox = self.get_funcbox(self.cpu, func_ptr)
- res = self.execute_operation(rop.CALL_F, [funcbox, constfloat(1.5),
- constfloat(2.5)], 'float',
- descr=calldescr)
- assert longlong.getrealfloat(res) == 4.0
- def test_field_basic(self):
- t_box, T_box, d = self.alloc_instance(self.T)
- fielddescr = self.cpu.fielddescrof(self.S, 'value')
- assert not fielddescr.is_pointer_field()
- #
- res = self.execute_operation(rop.SETFIELD_GC, [t_box, InputArgInt(39082)],
- 'void', descr=fielddescr)
- assert res is None
- res = self.execute_operation(rop.GETFIELD_GC_I, [t_box],
- 'int', descr=fielddescr)
- assert res == 39082
- #
- fielddescr1 = self.cpu.fielddescrof(self.S, 'chr1')
- fielddescr2 = self.cpu.fielddescrof(self.S, 'chr2')
- shortdescr = self.cpu.fielddescrof(self.S, 'short')
- self.execute_operation(rop.SETFIELD_GC, [t_box, InputArgInt(250)],
- 'void', descr=fielddescr2)
- self.execute_operation(rop.SETFIELD_GC, [t_box, InputArgInt(133)],
- 'void', descr=fielddescr1)
- self.execute_operation(rop.SETFIELD_GC, [t_box, InputArgInt(1331)],
- 'void', descr=shortdescr)
- res = self.execute_operation(rop.GETFIELD_GC_I, [t_box],
- 'int', descr=fielddescr2)
- assert res == 250
- res = self.execute_operation(rop.GETFIELD_GC_I, [t_box],
- 'int', descr=fielddescr1)
- assert res == 133
- res = self.execute_operation(rop.GETFIELD_GC_I, [t_box],
- 'int', descr=shortdescr)
- assert res == 1331
- #
- u_box, U_box, d = self.alloc_instance(self.U)
- fielddescr2 = self.cpu.fielddescrof(self.S, 'next')
- assert fielddescr2.is_pointer_field()
- res = self.execute_operation(rop.SETFIELD_GC, [t_box, u_box],
- 'void', descr=fielddescr2)
- assert res is None
- res = self.execute_operation(rop.GETFIELD_GC_R, [t_box],
- 'ref', descr=fielddescr2)
- assert res == u_box.getref_base()
- #
- null_const = wrap_constant(self.null_instance().getref_base())
- res = self.execute_operation(rop.SETFIELD_GC, [t_box, null_const],
- 'void', descr=fielddescr2)
- assert res is None
- res = self.execute_operation(rop.GETFIELD_GC_R, [t_box],
- 'ref', descr=fielddescr2)
- assert not res
- if self.cpu.supports_floats:
- floatdescr = self.cpu.fielddescrof(self.S, 'float')
- self.execute_operation(rop.SETFIELD_GC, [t_box, boxfloat(3.4)],
- 'void', descr=floatdescr)
- res = self.execute_operation(rop.GETFIELD_GC_F, [t_box],
- 'float', descr=floatdescr)
- assert longlong.getrealfloat(res) == 3.4
- #
- self.execute_operation(rop.SETFIELD_GC, [t_box, constfloat(-3.6)],
- 'void', descr=floatdescr)
- res = self.execute_operation(rop.GETFIELD_GC_F, [t_box],
- 'float', descr=floatdescr)
- assert longlong.getrealfloat(res) == -3.6
- def test_passing_guards(self):
- t_box, T_box, d = self.alloc_instance(self.T)
- nullbox = self.null_instance()
- all = [(rop.GUARD_TRUE, [InputArgInt(1)]),
- (rop.GUARD_FALSE, [InputArgInt(0)]),
- (rop.GUARD_VALUE, [InputArgInt(42), ConstInt(42)]),
- ]
- if not self.avoid_instances:
- all.extend([
- (rop.GUARD_NONNULL, [t_box]),
- (rop.GUARD_ISNULL, [nullbox])
- ])
- if self.cpu.supports_floats:
- all.append((rop.GUARD_VALUE, [boxfloat(3.5), constfloat(3.5)]))
- for (opname, args) in all:
- assert self.execute_operation(opname, args, 'void') == None
- assert not self.guard_failed
- def test_passing_guard_class(self):
- t_box, T_box, d = self.alloc_instance(self.T)
- #null_box = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.nullptr(T)))
- self.execute_operation(rop.GUARD_CLASS, [t_box, T_box], 'void')
- assert not self.guard_failed
- self.execute_operation(rop.GUARD_NONNULL_CLASS, [t_box, T_box], 'void')
- assert not self.guard_failed
- def test_failing_guards(self):
- t_box, T_box, d = self.alloc_instance(self.T)
- nullbox = self.null_instance()
- all = [(rop.GUARD_TRUE, [InputArgInt(0)]),
- (rop.GUARD_FALSE, [InputArgInt(1)]),
- (rop.GUARD_VALUE, [InputArgInt(42), ConstInt(41)]),
- ]
- if not self.avoid_instances:
- all.extend([
- (rop.GUARD_NONNULL, [nullbox]),
- (rop.GUARD_ISNULL, [t_box])])
- if self.cpu.supports_floats:
- all.append((rop.GUARD_VALUE, [boxfloat(-1.0), constfloat(1.0)]))
- for opname, args in all:
- assert self.execute_operation(opname, args, 'void') == None
- assert self.guard_failed
- def test_failing_guard_class(self):
- t_box, T_box, _ = self.alloc_instance(self.T)
- u_box, U_box, _ = self.alloc_instance(self.U)
- null_box = self.null_instance()
- for opname, args in [(rop.GUARD_CLASS, [t_box, U_box]),
- (rop.GUARD_CLASS, [u_box, T_box]),
- (rop.GUARD_NONNULL_CLASS, [t_box, U_box]),
- (rop.GUARD_NONNULL_CLASS, [u_box, T_box]),
- (rop.GUARD_NONNULL_CLASS, [null_box, T_box]),
- ]:
- assert self.execute_operation(opname, args, 'void') == None
- assert self.guard_failed
- def test_ooops(self):
- u1_box, U_box, _ = self.alloc_instance(self.U)
- u2_box, U_box, _ = self.alloc_instance(self.U)
- r = self.execute_operation(rop.PTR_EQ, [u1_box,
- clone(u1_box)], 'int')
- assert r == 1
- r = self.execute_operation(rop.PTR_NE, [u2_box,
- clone(u2_box)], 'int')
- assert r == 0
- r = self.execute_operation(rop.PTR_EQ, [u1_box, u2_box], 'int')
- assert r == 0
- r = self.execute_operation(rop.PTR_NE, [u2_box, u1_box], 'int')
- assert r == 1
- #
- null_box = self.null_instance()
- r = self.execute_operation(rop.PTR_EQ, [null_box,
- clone(null_box)], 'int')
- assert r == 1
- r = self.execute_operation(rop.PTR_EQ, [u1_box, null_box], 'int')
- assert r == 0
- r = self.execute_operation(rop.PTR_EQ, [null_box, u2_box], 'int')
- assert r == 0
- r = self.execute_operation(rop.PTR_NE, [null_box,
- clone(null_box)], 'int')
- assert r == 0
- r = self.execute_operation(rop.PTR_NE, [u2_box, null_box], 'int')
- assert r == 1
- r = self.execute_operation(rop.PTR_NE, [null_box, u1_box], 'int')
- assert r == 1
- # These operations are supposed to be the same as PTR_EQ/PTR_NE
- # just checking that the operations are defined in the backend.
- r = self.execute_operation(rop.INSTANCE_PTR_EQ, [u1_box, u2_box], 'int')
- assert r == 0
- r = self.execute_operation(rop.INSTANCE_PTR_NE, [u2_box, u1_box], 'int')
- assert r == 1
- def test_array_basic(self):
- a_box, A = self.alloc_array_of(rffi.SHORT, 342)
- arraydescr = self.cpu.arraydescrof(A)
- assert not arraydescr.is_array_of_pointers()
- #
- r = self.execute_operation(rop.ARRAYLEN_GC, [a_box],
- 'int', descr=arraydescr)
- assert r == 342
- r = self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(310),
- InputArgInt(744)],
- 'void', descr=arraydescr)
- assert r is None
- r = self.execute_operation(rop.GETARRAYITEM_GC_I, [a_box, InputArgInt(310)],
- 'int', descr=arraydescr)
- assert r == 744
- a_box, A = self.alloc_array_of(lltype.Signed, 342)
- arraydescr = self.cpu.arraydescrof(A)
- assert not arraydescr.is_array_of_pointers()
- #
- r = self.execute_operation(rop.ARRAYLEN_GC, [a_box],
- 'int', descr=arraydescr)
- assert r == 342
- r = self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(310),
- InputArgInt(7441)],
- 'void', descr=arraydescr)
- assert r is None
- r = self.execute_operation(rop.GETARRAYITEM_GC_I, [a_box, InputArgInt(310)],
- 'int', descr=arraydescr)
- assert r == 7441
- #
- a_box, A = self.alloc_array_of(lltype.Char, 11)
- arraydescr = self.cpu.arraydescrof(A)
- assert not arraydescr.is_array_of_pointers()
- r = self.execute_operation(rop.ARRAYLEN_GC, [a_box],
- 'int', descr=arraydescr)
- assert r == 11
- r = self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(4),
- InputArgInt(150)],
- 'void', descr=arraydescr)
- assert r is None
- r = self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(3),
- InputArgInt(160)],
- 'void', descr=arraydescr)
- assert r is None
- r = self.execute_operation(rop.GETARRAYITEM_GC_I, [a_box, InputArgInt(4)],
- 'int', descr=arraydescr)
- assert r == 150
- r = self.execute_operation(rop.GETARRAYITEM_GC_I, [a_box, InputArgInt(3)],
- 'int', descr=arraydescr)
- assert r == 160
- #
- if isinstance(A, lltype.GcArray):
- A = lltype.Ptr(A)
- b_box, B = self.alloc_array_of(A, 3)
- arraydescr = self.cpu.arraydescrof(B)
- assert arraydescr.is_array_of_pointers()
- r = self.execute_operation(rop.ARRAYLEN_GC, [b_box],
- 'int', descr=arraydescr)
- assert r == 3
- r = self.execute_operation(rop.SETARRAYITEM_GC, [b_box, InputArgInt(1),
- a_box],
- 'void', descr=arraydescr)
- assert r is None
- r = self.execute_operation(rop.GETARRAYITEM_GC_R, [b_box, InputArgInt(1)],
- 'ref', descr=arraydescr)
- assert r == a_box.getvalue()
- #
- # Unsigned should work the same as Signed
- a_box, A = self.alloc_array_of(lltype.Unsigned, 342)
- arraydescr = self.cpu.arraydescrof(A)
- assert not arraydescr.is_array_of_pointers()
- r = self.execute_operation(rop.ARRAYLEN_GC, [a_box],
- 'int', descr=arraydescr)
- assert r == 342
- r = self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(310),
- InputArgInt(7441)],
- 'void', descr=arraydescr)
- assert r is None
- r = self.execute_operation(rop.GETARRAYITEM_GC_I, [a_box, InputArgInt(310)],
- 'int', descr=arraydescr)
- assert r == 7441
- #
- # Bool should work the same as Char
- a_box, A = self.alloc_array_of(lltype.Bool, 311)
- arraydescr = self.cpu.arraydescrof(A)
- assert not arraydescr.is_array_of_pointers()
- r = self.execute_operation(rop.ARRAYLEN_GC, [a_box],
- 'int', descr=arraydescr)
- assert r == 311
- r = self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(304),
- InputArgInt(1)],
- 'void', descr=arraydescr)
- assert r is None
- r = self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(303),
- InputArgInt(0)],
- 'void', descr=arraydescr)
- assert r is None
- r = self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(302),
- InputArgInt(1)],
- 'void', descr=arraydescr)
- assert r is None
- r = self.execute_operation(rop.GETARRAYITEM_GC_I, [a_box, InputArgInt(304)],
- 'int', descr=arraydescr)
- assert r == 1
- r = self.execute_operation(rop.GETARRAYITEM_GC_I, [a_box, InputArgInt(303)],
- 'int', descr=arraydescr)
- assert r == 0
- r = self.execute_operation(rop.GETARRAYITEM_GC_I, [a_box, InputArgInt(302)],
- 'int', descr=arraydescr)
- assert r == 1
- if self.cpu.supports_floats:
- a_box, A = self.alloc_array_of(lltype.Float, 31)
- arraydescr = self.cpu.arraydescrof(A)
- self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(1),
- boxfloat(3.5)],
- 'void', descr=arraydescr)
- self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(2),
- constfloat(4.5)],
- 'void', descr=arraydescr)
- r = self.execute_operation(rop.GETARRAYITEM_GC_F, [a_box, InputArgInt(1)],
- 'float', descr=arraydescr)
- assert longlong.getrealfloat(r) == 3.5
- r = self.execute_operation(rop.GETARRAYITEM_GC_F, [a_box, InputArgInt(2)],
- 'float', descr=arraydescr)
- assert longlong.getrealfloat(r) == 4.5
- # For platforms where sizeof(INT) != sizeof(Signed) (ie, x86-64)
- a_box, A = self.alloc_array_of(rffi.INT, 342)
- arraydescr = self.cpu.arraydescrof(A)
- assert not arraydescr.is_array_of_pointers()
- r = self.execute_operation(rop.ARRAYLEN_GC, [a_box],
- 'int', descr=arraydescr)
- assert r == 342
- r = self.execute_operation(rop.SETARRAYITEM_GC, [a_box, InputArgInt(310),
- InputArgInt(7441)],
- 'void', descr=arraydescr)
- assert r is None
- r = self.execute_operation(rop.GETARRAYITEM_GC_I, [a_box, InputArgInt(310)],
- 'int', descr=arraydescr)
- assert r == 7441
- def test_array_of_structs(self):
- TP = lltype.GcStruct('x')
- ITEM = lltype.Struct('x',
- ('vs', lltype.Signed),
- ('vu', lltype.Unsigned),
- ('vsc', rffi.SIGNEDCHAR),
- ('vuc', rffi.UCHAR),
- ('vss', rffi.SHORT),
- ('vus', rffi.USHORT),
- ('vsi', rffi.INT),
- ('vui', rffi.UINT),
- ('k', lltype.Float),
- ('p', lltype.Ptr(TP)))
- a_box, A = self.alloc_array_of(ITEM, 15)
- s_box, S, _ = self.alloc_instance(TP)
- vsdescr = self.cpu.interiorfielddescrof(A, 'vs')
- kdescr = self.cpu.interiorfielddescrof(A, 'k')
- pdescr = self.cpu.interiorfielddescrof(A, 'p')
- self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, InputArgInt(3),
- boxfloat(1.5)],
- 'void', descr=kdescr)
- f = self.cpu.bh_getinteriorfield_gc_f(a_box.getref_base(), 3, kdescr)
- assert longlong.getrealfloat(f) == 1.5
- self.cpu.bh_setinteriorfield_gc_f(a_box.getref_base(), 3, longlong.getfloatstorage(2.5), kdescr)
- r = self.execute_operation(rop.GETINTERIORFIELD_GC_F, [a_box, InputArgInt(3)],
- 'float', descr=kdescr)
- assert longlong.getrealfloat(r) == 2.5
- #
- NUMBER_FIELDS = [('vs', lltype.Signed),
- ('vu', lltype.Unsigned),
- ('vsc', rffi.SIGNEDCHAR),
- ('vuc', rffi.UCHAR),
- ('vss', rffi.SHORT),
- ('vus', rffi.USHORT),
- ('vsi', rffi.INT),
- ('vui', rffi.UINT)]
- for name, TYPE in NUMBER_FIELDS[::-1]:
- vdescr = self.cpu.interiorfielddescrof(A, name)
- self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, InputArgInt(3),
- InputArgInt(-15)],
- 'void', descr=vdescr)
- for name, TYPE in NUMBER_FIELDS:
- vdescr = self.cpu.interiorfielddescrof(A, name)
- i = self.cpu.bh_getinteriorfield_gc_i(a_box.getref_base(), 3,
- vdescr)
- assert i == rffi.cast(lltype.Signed, rffi.cast(TYPE, -15))
- for name, TYPE in NUMBER_FIELDS[::-1]:
- vdescr = self.cpu.interiorfielddescrof(A, name)
- self.cpu.bh_setinteriorfield_gc_i(a_box.getref_base(), 3,
- -25, vdescr)
- for name, TYPE in NUMBER_FIELDS:
- vdescr = self.cpu.interiorfielddescrof(A, name)
- r = self.execute_operation(rop.GETINTERIORFIELD_GC_I,
- [a_box, InputArgInt(3)],
- 'int', descr=vdescr)
- assert r == rffi.cast(lltype.Signed, rffi.cast(TYPE, -25))
- #
- self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, InputArgInt(4),
- s_box],
- 'void', descr=pdescr)
- r = self.cpu.bh_getinteriorfield_gc_r(a_box.getref_base(), 4, pdescr)
- assert r == s_box.getref_base()
- self.cpu.bh_setinteriorfield_gc_r(a_box.getref_base(), 3,
- s_box.getref_base(), pdescr)
- r = self.execute_operation(rop.GETINTERIORFIELD_GC_R, [a_box, InputArgInt(3)],
- 'ref', descr=pdescr)
- assert r == s_box.getref_base()
- #
- # test a corner case that used to fail on x86
- i4 = InputArgInt(4)
- self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, i4, i4],
- 'void', descr=vsdescr)
- r = self.cpu.bh_getinteriorfield_gc_i(a_box.getref_base(), 4, vsdescr)
- assert r == 4
- def test_array_of_structs_all_sizes(self):
- # x86 has special support that can be used for sizes
- # 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 16, 18, 20, 24, 32, 36, 40, 64, 72
- for length in range(1, 75):
- ITEM = lltype.FixedSizeArray(lltype.Char, length)
- a_box, A = self.alloc_array_of(ITEM, 5)
- a = lltype.cast_opaque_ptr(lltype.Ptr(A), a_box.getref_base())
- middle = length // 2
- a[3][middle] = chr(65 + length)
- fdescr = self.cpu.interiorfielddescrof(A, 'item%d' % middle)
- r = self.execute_operation(rop.GETINTERIORFIELD_GC_I,
- [a_box, InputArgInt(3)],
- 'int', descr=fdescr)
- assert r == 65 + length
- self.execute_operation(rop.SETINTERIORFIELD_GC,
- [a_box, InputArgInt(2), InputArgInt(r + 1)],
- 'void', descr=fdescr)
- r1 = self.cpu.bh_getinteriorfield_gc_i(a_box.getref_base(), 2,
- fdescr)
- assert r1 == r + 1
- def test_string_basic(self):
- s_box = self.alloc_string("hello\xfe")
- r = self.execute_operation(rop.STRLEN, [s_box], 'int')
- assert r == 6
- r = self.execute_operation(rop.STRGETITEM, [s_box, InputArgInt(5)], 'int')
- assert r == 254
- r = self.execute_operation(rop.STRSETITEM, [s_box, InputArgInt(4),
- InputArgInt(153)], 'void')
- assert r is None
- r = self.execute_operation(rop.STRGETITEM, [s_box, InputArgInt(5)], 'int')
- assert r == 254
- r = self.execute_operation(rop.STRGETITEM, [s_box, InputArgInt(4)], 'int')
- assert r == 153
- def test_copystrcontent(self):
- s_box = self.alloc_string("abcdef")
- for s_box in [s_box, wrap_constant(s_box.getref_base())]:
- for srcstart_box in [InputArgInt(2), ConstInt(2)]:
- for dststart_box in [InputArgInt(3), ConstInt(3)]:
- for length_box in [InputArgInt(4), ConstInt(4)]:
- for r_box_is_const in [False, True]:
- r_box = self.alloc_string("!???????!")
- if r_box_is_const:
- r_box = wrap_constant(r_box.getref_base())
- self.execute_operation(rop.COPYSTRCONTENT,
- [s_box, r_box,
- srcstart_box,
- dststart_box,
- length_box], 'void')
- assert self.look_string(r_box) == "!??cdef?!"
- def test_copyunicodecontent(self):
- s_box = self.alloc_unicode(u"abcdef")
- for s_box in [s_box, wrap_constant(s_box.getref_base())]:
- for srcstart_box in [InputArgInt(2), ConstInt(2)]:
- for dststart_box in [InputArgInt(3), ConstInt(3)]:
- for length_box in [InputArgInt(4), ConstInt(4)]:
- for r_box_is_const in [False, True]:
- r_box = self.alloc_unicode(u"!???????!")
- if r_box_is_const:
- r_box = wrap_constant(r_box.getref_base())
- self.execute_operation(rop.COPYUNICODECONTENT,
- [s_box, r_box,
- srcstart_box,
- dststart_box,
- length_box], 'void')
- assert self.look_unicode(r_box) == u"!??cdef?!"
- def test_do_unicode_basic(self):
- u = self.cpu.bh_newunicode(5)
- self.cpu.bh_unicodesetitem(u, 4, 123)
- r = self.cpu.bh_unicodegetitem(u, 4)
- assert r == 123
- def test_unicode_basic(self):
- u_box = self.alloc_unicode(u"hello\u1234")
- r = self.execute_operation(rop.UNICODELEN, [u_box], 'int')
- assert r == 6
- r = self.execute_operation(rop.UNICODEGETITEM, [u_box, InputArgInt(5)],
- 'int')
- assert r == 0x1234
- r = self.execute_operation(rop.UNICODESETITEM, [u_box, InputArgInt(4),
- InputArgInt(31313)], 'void')
- assert r is None
- r = self.execute_operation(rop.UNICODEGETITEM, [u_box, InputArgInt(5)],
- 'int')
- assert r == 0x1234
- r = self.execute_operation(rop.UNICODEGETITEM, [u_box, InputArgInt(4)],
- 'int')
- assert r == 31313
- def test_same_as(self):
- r = self.execute_operation(rop.SAME_AS_I, [ConstInt(5)], 'int')
- assert r == 5
- r = self.execute_operation(rop.SAME_AS_I, [InputArgInt(5)], 'int')
- assert r == 5
- u_box = self.alloc_unicode(u"hello\u1234")
- r = self.execute_operation(rop.SAME_AS_R, [wrap_constant(u_box.getref_base())], 'ref')
- assert r == u_box.getref_base()
- r = self.execute_operation(rop.SAME_AS_R, [u_box], 'ref')
- assert r == u_box.getref_base()
- if self.cpu.supports_floats:
- r = self.execute_operation(rop.SAME_AS_F, [constfloat(5.5)], 'float')
- assert longlong.getrealfloat(r) == 5.5
- r = self.execute_operation(rop.SAME_AS_F, [boxfloat(5.5)], 'float')
- assert longlong.getrealfloat(r) == 5.5
- def test_virtual_ref(self):
- pass # VIRTUAL_REF must not reach the backend nowadays
- def test_virtual_ref_finish(self):
- pass # VIRTUAL_REF_FINISH must not reach the backend nowadays
- def test_arguments_to_execute_token(self):
- # this test checks that execute_token() can be called with any
- # variant of ints and floats as arguments
- if self.cpu.supports_floats:
- numkinds = 2
- else:
- numkinds = 1
- seed = random.randrange(0, 10000)
- print 'Seed is', seed # or choose it by changing the previous line
- r = random.Random()
- r.seed(seed)
- for nb_args in range(50):
- print 'Passing %d arguments to execute_token...' % nb_args
- #
- inputargs = []
- values = []
- for k in range(nb_args):
- kind = r.randrange(0, numkinds)
- if kind == 0:
- inputargs.append(InputArgInt())
- values.append(r.randrange(-100000, 100000))
- else:
- inputargs.append(InputArgFloat())
- values.append(longlong.getfloatstorage(r.random()))
- #
- looptoken = JitCellToken()
- guarddescr = BasicFailDescr(42)
- faildescr = BasicFinalDescr(43)
- operations = []
- retboxes = []
- retvalues = []
- #
- ks = range(nb_args)
- random.shuffle(ks)
- for k in ks:
- if isinstance(inputargs[k], InputArgInt):
- x = r.randrange(-100000, 100000)
- operations.append(
- ResOperation(rop.INT_ADD, [inputargs[k],
- ConstInt(x)])
- )
- y = values[k] + x
- else:
- x = r.random()
- operations.append(
- ResOperation(rop.FLOAT_ADD, [inputargs[k],
- constfloat(x)])
- )
- y = longlong.getrealfloat(values[k]) + x
- y = longlong.getfloatstorage(y)
- kk = r.randrange(0, len(retboxes)+1)
- retboxes.insert(kk, operations[-1])
- retvalues.insert(kk, y)
- #
- op0 = ResOperation(rop.SAME_AS_I, [ConstInt(0)])
- op1 = ResOperation(rop.GUARD_TRUE, [op0], descr=guarddescr)
- op2 = ResOperation(rop.FINISH, [], descr=faildescr)
- operations += [op0, op1, op2]
- operations[-2].setfailargs(retboxes)
- print inputargs
- for op in operations:
- print op
- self.cpu.compile_loop(inputargs, operations, looptoken)
- #
- deadframe = self.cpu.execute_token(looptoken, *values)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 42
- #
- for k in range(len(retvalues)):
- if retboxes[k].type == 'i':
- got = self.cpu.get_int_value(deadframe, k)
- else:
- got = self.cpu.get_float_value(deadframe, k)
- assert got == retvalues[k]
- def test_jump(self):
- # this test generates small loops where the JUMP passes many
- # arguments of various types, shuffling them around.
- if self.cpu.supports_floats:
- numkinds = 3
- else:
- numkinds = 2
- seed = random.randrange(0, 10000)
- print 'Seed is', seed # or choose it by changing the previous line
- r = random.Random()
- r.seed(seed)
- for nb_args in range(50):
- print 'Passing %d arguments around...' % nb_args
- #
- inputargs = []
- for k in range(nb_args):
- kind = r.randrange(0, numkinds)
- if kind == 0:
- inputargs.append(InputArgInt())
- elif kind == 1:
- inputargs.append(InputArgRef())
- else:
- inputargs.append(InputArgFloat())
- jumpargs = []
- remixing = []
- for srcbox in inputargs:
- n = r.randrange(0, len(inputargs))
- otherbox = inputargs[n]
- if otherbox.type == srcbox.type:
- remixing.append((srcbox, otherbox))
- else:
- otherbox = srcbox
- jumpargs.append(otherbox)
- #
- index_counter = r.randrange(0, len(inputargs)+1)
- i0 = InputArgInt()
- inputargs.insert(index_counter, i0)
- #
- looptoken = JitCellToken()
- targettoken = TargetToken()
- faildescr = BasicFailDescr(15)
- op0 = ResOperation(rop.LABEL, inputargs, descr=targettoken)
- op1 = ResOperation(rop.INT_SUB, [i0, ConstInt(1)])
- op2 = ResOperation(rop.INT_GE, [op1, ConstInt(0)])
- op3 = ResOperation(rop.GUARD_TRUE, [op2])
- jumpargs.insert(index_counter, op1)
- op4 = ResOperation(rop.JUMP, jumpargs, descr=targettoken)
- operations = [op0, op1, op2, op3, op4]
- operations[3].setfailargs(inputargs[:])
- operations[3].setdescr(faildescr)
- #
- self.cpu.compile_loop(inputargs, operations, looptoken)
- #
- values = []
- S = lltype.GcStruct('S')
- for box in inputargs:
- if box.type == 'i':
- values.append(r.randrange(-10000, 10000))
- elif box.type == 'r':
- p = lltype.malloc(S)
- values.append(lltype.cast_opaque_ptr(llmemory.GCREF, p))
- elif box.type == 'f':
- values.append(longlong.getfloatstorage(r.random()))
- else:
- assert 0
- values[index_counter] = 11
- #
- deadframe = self.cpu.execute_token(looptoken, *values)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 15
- #
- dstvalues = values[:]
- for _ in range(11):
- expected = dstvalues[:]
- for tgtbox, srcbox in remixing:
- v = dstvalues[inputargs.index(srcbox)]
- expected[inputargs.index(tgtbox)] = v
- dstvalues = expected
- #
- assert dstvalues[index_counter] == 11
- dstvalues[index_counter] = 0
- for i, (box, val) in enumerate(zip(inputargs, dstvalues)):
- if box.type == 'i':
- got = self.cpu.get_int_value(deadframe, i)
- elif box.type == 'r':
- got = self.cpu.get_ref_value(deadframe, i)
- elif box.type == 'f':
- got = self.cpu.get_float_value(deadframe, i)
- else:
- assert 0
- assert type(got) == type(val)
- assert got == val
- def test_compile_bridge_float(self):
- if not self.cpu.supports_floats:
- py.test.skip("requires floats")
- targettoken = TargetToken()
- faildescr1 = BasicFailDescr(1)
- faildescr2 = BasicFailDescr(2)
- faildescr3 = BasicFinalDescr(3)
- loop = parse("""
- [f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11]
- label(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, descr=targettoken)
- i2 = float_le(f0, 9.2)
- guard_true(i2, descr=faildescr1) [f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11]
- guard_false(i2, descr=faildescr2) [f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11]
- finish(descr=faildescr3)
- """, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- bridge = parse("""
- [f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11]
- f15 = float_sub(f0, 1.0)
- jump(f15, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, descr=targettoken)
- """, namespace=locals())
- self.cpu.compile_bridge(faildescr1, bridge.inputargs,
- bridge.operations, looptoken)
- args = []
- for i in range(len(loop.inputargs)):
- x = 13.5 + 6.73 * i
- args.append(longlong.getfloatstorage(x))
- deadframe = self.cpu.execute_token(looptoken, *args)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 2
- res = self.cpu.get_float_value(deadframe, 0)
- assert longlong.getrealfloat(res) == 8.5
- for i in range(1, len(loop.inputargs)):
- got = longlong.getrealfloat(self.cpu.get_float_value(
- deadframe, i))
- assert got == 13.5 + 6.73 * i
- def test_compile_bridge_spilled_float(self):
- if not self.cpu.supports_floats:
- py.test.skip("requires floats")
- faildescr1 = BasicFailDescr(100)
- faildescr2 = BasicFinalDescr(102)
- loopops = """
- [i0,f1, f2]
- f3 = float_add(f1, f2)
- force_spill(f3)
- force_spill(f1)
- force_spill(f2)
- guard_false(i0) [f1, f2, f3]
- finish()"""
- loop = parse(loopops)
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- args = [1]
- args.append(longlong.getfloatstorage(132.25))
- args.append(longlong.getfloatstorage(0.75))
- deadframe = self.cpu.execute_token(looptoken, *args) #xxx check
- fail = self.cpu.get_latest_descr(deadframe)
- assert loop.operations[-2].getdescr() == fail
- f1 = self.cpu.get_float_value(deadframe, 0)
- f2 = self.cpu.get_float_value(deadframe, 1)
- f3 = self.cpu.get_float_value(deadframe, 2)
- assert longlong.getrealfloat(f1) == 132.25
- assert longlong.getrealfloat(f2) == 0.75
- assert longlong.getrealfloat(f3) == 133.0
- bridge = parse("""
- [f1, f2, f3]
- i0 = same_as_i(0)
- guard_true(i0, descr=faildescr1) [f1, f2, f3]
- finish(descr=faildescr2)
- """, namespace=locals())
- self.cpu.compile_bridge(loop.operations[-2].getdescr(),
- bridge.inputargs, bridge.operations,
- looptoken)
- args = [1,
- longlong.getfloatstorage(132.25),
- longlong.getfloatstorage(0.75)]
- deadframe = self.cpu.execute_token(looptoken, *args)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 100
- f1 = self.cpu.get_float_value(deadframe, 0)
- f2 = self.cpu.get_float_value(deadframe, 1)
- f3 = self.cpu.get_float_value(deadframe, 2)
- assert longlong.getrealfloat(f1) == 132.25
- assert longlong.getrealfloat(f2) == 0.75
- assert longlong.getrealfloat(f3) == 133.0
- def test_integers_and_guards2(self, extra_op=False):
- for opname, compare in [
- (rop.INT_IS_TRUE, lambda x: bool(x)),
- (rop.INT_IS_ZERO, lambda x: not bool(x))]:
- for opguard, guard_case in [
- (rop.GUARD_FALSE, False),
- (rop.GUARD_TRUE, True),
- ]:
- box = InputArgInt()
- faildescr1 = BasicFailDescr(1)
- faildescr2 = BasicFinalDescr(2)
- inputargs = [box]
- op0 = ResOperation(opname, [box])
- op1 = ResOperation(opguard, [op0], descr=faildescr1)
- op2 = ResOperation(rop.FINISH, [], descr=faildescr2)
- operations = [op0, op1, op2]
- if extra_op:
- operations.insert(1, ResOperation(rop.SAME_AS_I,
- [ConstInt(42)]))
- op1.setfailargs([])
- looptoken = JitCellToken()
- self.cpu.compile_loop(inputargs, operations, looptoken)
- #
- for value in [-42, 0, 1, 10]:
- deadframe = self.cpu.execute_token(looptoken, value)
- fail = self.cpu.get_latest_descr(deadframe)
- #
- expected = compare(value)
- expected ^= guard_case
- assert fail.identifier == 2 - expected
- def test_integers_and_guards2_x(self):
- self.test_integers_and_guards2(extra_op=True)
- def test_integers_and_guards(self, extra_op=False):
- for opname, compare in [
- (rop.INT_LT, lambda x, y: x < y),
- (rop.INT_LE, lambda x, y: x <= y),
- (rop.INT_EQ, lambda x, y: x == y),
- (rop.INT_NE, lambda x, y: x != y),
- (rop.INT_GT, lambda x, y: x > y),
- (rop.INT_GE, lambda x, y: x >= y),
- ]:
- for opguard, guard_case in [
- (rop.GUARD_FALSE, False),
- (rop.GUARD_TRUE, True),
- ]:
- for combinaison in ["bb", "bc", "cb"]:
- #
- if combinaison[0] == 'b':
- ibox1 = InputArgInt()
- else:
- ibox1 = ConstInt(-42)
- if combinaison[1] == 'b':
- ibox2 = InputArgInt()
- else:
- ibox2 = ConstInt(-42)
- faildescr1 = BasicFailDescr(1)
- faildescr2 = BasicFinalDescr(2)
- inputargs = [ib for ib in [ibox1, ibox2]
- if isinstance(ib, InputArgInt)]
- op0 = ResOperation(opname, [ibox1, ibox2])
- op1 = ResOperation(opguard, [op0], descr=faildescr1)
- op2 = ResOperation(rop.FINISH, [], descr=faildescr2)
- operations = [op0, op1, op2]
- if extra_op:
- operations.insert(1, ResOperation(rop.SAME_AS_I,
- [ConstInt(42)]))
- operations[-2].setfailargs([])
- looptoken = JitCellToken()
- self.cpu.compile_loop(inputargs, operations, looptoken)
- #
- for test1 in [-65, -42, -11, 0, 1, 10]:
- if test1 == -42 or combinaison[0] == 'b':
- for test2 in [-65, -42, -11, 0, 1, 10]:
- if test2 == -42 or combinaison[1] == 'b':
- args = []
- if combinaison[0] == 'b':
- args.append(test1)
- if combinaison[1] == 'b':
- args.append(test2)
- deadframe = self.cpu.execute_token(
- looptoken, *args)
- fail = self.cpu.get_latest_descr(deadframe)
- #
- expected = compare(test1, test2)
- expected ^= guard_case
- assert fail.identifier == 2 - expected
- def test_integers_and_guards_x(self):
- self.test_integers_and_guards(extra_op=True)
- def test_integers_and_guards_uint(self, extra_op=False):
- for opname, compare in [
- (rop.UINT_LE, lambda x, y: (x) <= (y)),
- (rop.UINT_GT, lambda x, y: (x) > (y)),
- (rop.UINT_LT, lambda x, y: (x) < (y)),
- (rop.UINT_GE, lambda x, y: (x) >= (y)),
- ]:
- for opguard, guard_case in [
- (rop.GUARD_FALSE, False),
- (rop.GUARD_TRUE, True),
- ]:
- for combinaison in ["bb", "bc", "cb"]:
- #
- if combinaison[0] == 'b':
- ibox1 = InputArgInt()
- else:
- ibox1 = ConstInt(42)
- if combinaison[1] == 'b':
- ibox2 = InputArgInt()
- else:
- ibox2 = ConstInt(42)
- faildescr1 = BasicFailDescr(1)
- faildescr2 = BasicFinalDescr(2)
- inputargs = [ib for ib in [ibox1, ibox2]
- if isinstance(ib, InputArgInt)]
- op0 = ResOperation(opname, [ibox1, ibox2])
- op1 = ResOperation(opguard, [op0], descr=faildescr1)
- op2 = ResOperation(rop.FINISH, [], descr=faildescr2)
- operations = [op0, op1, op2]
- if extra_op:
- operations.insert(1, ResOperation(rop.SAME_AS_I,
- [ConstInt(42)]))
- operations[-2].setfailargs([])
- looptoken = JitCellToken()
- self.cpu.compile_loop(inputargs, operations, looptoken)
- #
- for test1 in [65, 42, 11, 0, 1]:
- if test1 == 42 or combinaison[0] == 'b':
- for test2 in [65, 42, 11, 0, 1]:
- if test2 == 42 or combinaison[1] == 'b':
- args = []
- if combinaison[0] == 'b':
- args.append(test1)
- if combinaison[1] == 'b':
- args.append(test2)
- deadframe = self.cpu.execute_token(
- looptoken, *args)
- fail = self.cpu.get_latest_descr(deadframe)
- #
- expected = compare(test1, test2)
- expected ^= guard_case
- assert fail.identifier == 2 - expected
- def test_integers_and_guards_uint_x(self):
- self.test_integers_and_guards_uint(extra_op=True)
- def test_floats_and_guards(self, extra_op=False):
- if not self.cpu.supports_floats:
- py.test.skip("requires floats")
- for opname, compare in [
- (rop.FLOAT_LT, lambda x, y: x < y),
- (rop.FLOAT_LE, lambda x, y: x <= y),
- (rop.FLOAT_EQ, lambda x, y: x == y),
- (rop.FLOAT_NE, lambda x, y: x != y),
- (rop.FLOAT_GT, lambda x, y: x > y),
- (rop.FLOAT_GE, lambda x, y: x >= y),
- ]:
- for opguard, guard_case in [
- (rop.GUARD_FALSE, False),
- (rop.GUARD_TRUE, True),
- ]:
- for combinaison in ["bb", "bc", "cb"]:
- #
- if combinaison[0] == 'b':
- fbox1 = InputArgFloat()
- else:
- fbox1 = constfloat(-4.5)
- if combinaison[1] == 'b':
- fbox2 = InputArgFloat()
- else:
- fbox2 = constfloat(-4.5)
- faildescr1 = BasicFailDescr(1)
- faildescr2 = BasicFinalDescr(2)
- inputargs = [fb for fb in [fbox1, fbox2]
- if not isinstance(fb, Const)]
- op0 = ResOperation(opname, [fbox1, fbox2])
- op1 = ResOperation(opguard, [op0], descr=faildescr1)
- op2 = ResOperation(rop.FINISH, [], descr=faildescr2)
- operations = [op0, op1, op2]
- if extra_op:
- operations.insert(1, ResOperation(rop.SAME_AS_I,
- [ConstInt(42)]))
- operations[-2].setfailargs([])
- looptoken = JitCellToken()
- self.cpu.compile_loop(inputargs, operations, looptoken)
- #
- nan = 1e200 * 1e200
- nan /= nan
- for test1 in [-6.5, -4.5, -2.5, nan]:
- if test1 == -4.5 or combinaison[0] == 'b':
- for test2 in [-6.5, -4.5, -2.5, nan]:
- if test2 == -4.5 or combinaison[1] == 'b':
- args = []
- if combinaison[0] == 'b':
- args.append(
- longlong.getfloatstorage(test1))
- if combinaison[1] == 'b':
- args.append(
- longlong.getfloatstorage(test2))
- deadframe = self.cpu.execute_token(
- looptoken, *args)
- fail = self.cpu.get_latest_descr(deadframe)
- #
- expected = compare(test1, test2)
- expected ^= guard_case
- assert fail.identifier == 2 - expected
- def test_floats_and_guards_x(self):
- self.test_floats_and_guards(extra_op=True)
- def test_unused_result_int(self):
- # test pure operations on integers whose result is not used
- from rpython.jit.metainterp.test.test_executor import get_int_tests
- int_tests = list(get_int_tests())
- int_tests = [(opnum, boxargs, 'int', retvalue)
- for opnum, boxargs, retvalue in int_tests]
- self._test_unused_result(int_tests)
- def test_unused_result_float(self):
- # same as test_unused_result_int, for float operations
- from rpython.jit.metainterp.test.test_executor import get_float_tests
- float_tests = list(get_float_tests(self.cpu))
- self._test_unused_result(float_tests)
- def _test_unused_result(self, tests):
- while len(tests) > 50: # only up to 50 tests at once
- self._test_unused_result(tests[:50])
- tests = tests[50:]
- inputargs = []
- operations = []
- for opnum, boxargs, rettype, retvalue in tests:
- inputargs += [box for box in boxargs if not isinstance(box, Const)]
- operations.append(ResOperation(opnum, boxargs))
- # Unique-ify inputargs
- inputargs = list(set(inputargs))
- faildescr = BasicFinalDescr(1)
- operations.append(ResOperation(rop.FINISH, [], descr=faildescr))
- looptoken = JitCellToken()
- #
- self.cpu.compile_loop(inputargs, operations, looptoken)
- #
- args = []
- for box in inputargs:
- if isinstance(box, InputArgInt):
- args.append(box.getint())
- elif isinstance(box, InputArgFloat):
- args.append(box.getfloatstorage())
- else:
- assert 0
- #
- deadframe = self.cpu.execute_token(looptoken, *args)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 1
- def test_nan_and_infinity(self):
- if not self.cpu.supports_floats:
- py.test.skip("requires floats")
- from rpython.rlib.rfloat import INFINITY, NAN, isinf, isnan
- from rpython.jit.metainterp.resoperation import opname
- fzer = 0.0
- fone = 1.0
- fmqr = -0.25
- finf = INFINITY
- fmnf = -INFINITY
- fnan = NAN
- all_cases_unary = [(a,) for a in [fzer,fone,fmqr,finf,fmnf,fnan]]
- all_cases_binary = [(a, b) for a in [fzer,fone,fmqr,finf,fmnf,fnan]
- for b in [fzer,fone,fmqr,finf,fmnf,fnan]]
- no_zero_divison = [(a, b) for a in [fzer,fone,fmqr,finf,fmnf,fnan]
- for b in [ fone,fmqr,finf,fmnf,fnan]]
- def nan_and_infinity(opnum, realoperation, testcases):
- for testcase in testcases:
- expected = realoperation(*testcase)
- inputargs = [boxfloat(x) for x in testcase]
- if isinstance(expected, float):
- expectedtype = 'float'
- else:
- expectedtype = 'int'
- got = self.execute_operation(opnum, inputargs,
- expectedtype)
- if not isinstance(expected, bool):
- got = longlong.getrealfloat(got)
- if isnan(expected):
- ok = isnan(got)
- elif isinf(expected):
- ok = isinf(got)
- else:
- ok = got == expected
- if not ok:
- raise AssertionError("%s(%s): got %r, expected %r" % (
- opname[opnum], ', '.join(map(repr, testcase)),
- got, expected))
- # if we expect a boolean, also check the combination with
- # a GUARD_TRUE or GUARD_FALSE
- if isinstance(expected, bool):
- for extra_op in (False, True):
- for guard_opnum, expected_id in [(rop.GUARD_TRUE, 1),
- (rop.GUARD_FALSE, 0)]:
- op0 = ResOperation(opnum, inputargs)
- op1 = ResOperation(guard_opnum, [op0],
- descr=BasicFailDescr(4))
- op2 = ResOperation(rop.FINISH, [],
- descr=BasicFinalDescr(5))
- operations = [op0, op1, op2]
- if extra_op:
- operations.insert(1, ResOperation(rop.SAME_AS_I,
- [ConstInt(42)]))
- operations[-2].setfailargs([])
- looptoken = JitCellToken()
- # Use "set" to unique-ify inputargs
- unique_testcase_list = list(set(inputargs))
- self.cpu.compile_loop(unique_testcase_list, operations,
- looptoken)
- args = [box.getfloatstorage() for box in
- unique_testcase_list]
- deadframe = self.cpu.execute_token(looptoken, *args)
- fail = self.cpu.get_latest_descr(deadframe)
- if fail.identifier != 5 - (expected_id^expected):
- if fail.identifier == 4:
- msg = "was taken"
- else:
- msg = "was not taken"
- raise AssertionError(
- "%s(%s)/%s took the wrong path: "
- "the failure path of the guard %s" % (
- opname[opnum],
- ', '.join(map(repr, testcase)),
- opname[guard_opnum], msg))
- yield nan_and_infinity, rop.FLOAT_ADD, operator.add, all_cases_binary
- yield nan_and_infinity, rop.FLOAT_SUB, operator.sub, all_cases_binary
- yield nan_and_infinity, rop.FLOAT_MUL, operator.mul, all_cases_binary
- yield nan_and_infinity, rop.FLOAT_TRUEDIV, \
- operator.truediv, no_zero_divison
- yield nan_and_infinity, rop.FLOAT_NEG, operator.neg, all_cases_unary
- yield nan_and_infinity, rop.FLOAT_ABS, abs, all_cases_unary
- yield nan_and_infinity, rop.FLOAT_LT, operator.lt, all_cases_binary
- yield nan_and_infinity, rop.FLOAT_LE, operator.le, all_cases_binary
- yield nan_and_infinity, rop.FLOAT_EQ, operator.eq, all_cases_binary
- yield nan_and_infinity, rop.FLOAT_NE, operator.ne, all_cases_binary
- yield nan_and_infinity, rop.FLOAT_GT, operator.gt, all_cases_binary
- yield nan_and_infinity, rop.FLOAT_GE, operator.ge, all_cases_binary
- def test_noops(self):
- c_box = wrap_constant(self.alloc_string("hi there").getref_base())
- c_nest = ConstInt(0)
- c_id = ConstInt(0)
- self.execute_operation(rop.DEBUG_MERGE_POINT, [c_box, c_nest, c_id, c_nest], 'void')
- self.execute_operation(rop.JIT_DEBUG, [c_box, c_nest, c_nest,
- c_nest, c_nest], 'void')
- def test_read_timestamp(self):
- if IS_32_BIT and not self.cpu.supports_longlong:
- py.test.skip("read_timestamp returns a longlong")
- if sys.platform == 'win32':
- # windows quite often is very inexact (like the old Intel 8259 PIC),
- # so we stretch the time a little bit.
- # On my virtual Parallels machine in a 2GHz Core i7 Mac Mini,
- # the test starts working at delay == 21670 and stops at 20600000.
- # We take the geometric mean value.
- from math import log, exp
- delay_min = 21670
- delay_max = 20600000
- delay = int(exp((log(delay_min)+log(delay_max))/2))
- def wait_a_bit():
- for i in xrange(delay): pass
- else:
- def wait_a_bit():
- pass
- from rpython.jit.codewriter.effectinfo import EffectInfo
- from rpython.rlib import rtimer
- effectinfo = EffectInfo([], [], [], [], [], [],
- EffectInfo.EF_CANNOT_RAISE,
- EffectInfo.OS_MATH_READ_TIMESTAMP)
- FPTR = self.Ptr(self.FuncType([], lltype.SignedLongLong))
- func_ptr = llhelper(FPTR, rtimer.read_timestamp)
- FUNC = deref(FPTR)
- funcbox = self.get_funcbox(self.cpu, func_ptr)
- calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, effectinfo)
- if longlong.is_64_bit:
- res1 = self.execute_operation(rop.CALL_I, [funcbox], 'int', calldescr)
- wait_a_bit()
- res2 = self.execute_operation(rop.CALL_I, [funcbox], 'int', calldescr)
- else:
- res1 = self.execute_operation(rop.CALL_F, [funcbox],'float',calldescr)
- wait_a_bit()
- res2 = self.execute_operation(rop.CALL_F, [funcbox],'float',calldescr)
- assert res1 < res2 < res1 + 2**32
- class LLtypeBackendTest(BaseBackendTest):
- Ptr = lltype.Ptr
- FuncType = lltype.FuncType
- malloc = staticmethod(lltype.malloc)
- nullptr = staticmethod(lltype.nullptr)
- @classmethod
- def get_funcbox(cls, cpu, func_ptr):
- addr = llmemory.cast_ptr_to_adr(func_ptr)
- return ConstInt(heaptracker.adr2int(addr))
- MY_VTABLE = rclass.OBJECT_VTABLE # for tests only
- S = lltype.GcForwardReference()
- S.become(lltype.GcStruct('S', ('parent', rclass.OBJECT),
- ('value', lltype.Signed),
- ('chr1', lltype.Char),
- ('chr2', lltype.Char),
- ('short', rffi.SHORT),
- ('next', lltype.Ptr(S)),
- ('float', lltype.Float)))
- T = lltype.GcStruct('T', ('parent', S),
- ('next', lltype.Ptr(S)))
- U = lltype.GcStruct('U', ('parent', T),
- ('next', lltype.Ptr(S)))
- def alloc_instance(self, T):
- if hasattr(T, 'parent'):
- vtable_for_T = lltype.malloc(self.MY_VTABLE, immortal=True)
- vtable_for_T_addr = llmemory.cast_ptr_to_adr(vtable_for_T)
- else:
- vtable_for_T = lltype.nullptr(rclass.OBJECT_VTABLE)
- cpu = self.cpu
- class FakeGCCache(object):
- pass
- if hasattr(cpu, 'gc_ll_descr'):
- if not hasattr(cpu.gc_ll_descr, '_cache_gcstruct2vtable'):
- cpu.gc_ll_descr._cache_gcstruct2vtable = {}
- cpu.gc_ll_descr._cache_gcstruct2vtable.update({T: vtable_for_T})
- p = T
- while hasattr(p, 'parent'):
- vtable_for_parent = lltype.malloc(self.MY_VTABLE, immortal=True)
- cpu.gc_ll_descr._cache_gcstruct2vtable[p.parent] = vtable_for_parent
- p = p.parent
- else:
- descr = cpu.sizeof(T, vtable_for_T)
- t = lltype.malloc(T)
- if T == self.T:
- t.parent.parent.typeptr = vtable_for_T
- elif T == self.U:
- t.parent.parent.parent.typeptr = vtable_for_T
- t_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, t))
- if not hasattr(T, 'parent'):
- vtable = lltype.nullptr(rclass.OBJECT_VTABLE)
- T_box = None
- else:
- vtable = vtable_for_T
- T_box = ConstInt(heaptracker.adr2int(vtable_for_T_addr))
- descr = cpu.sizeof(T, vtable)
- return t_box, T_box, descr
- def null_instance(self):
- return InputArgRef(lltype.nullptr(llmemory.GCREF.TO))
- def alloc_array_of(self, ITEM, length):
- A = lltype.GcArray(ITEM)
- a = lltype.malloc(A, length)
- a_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, a))
- return a_box, A
- def alloc_string(self, string):
- s = rstr.mallocstr(len(string))
- for i in range(len(string)):
- s.chars[i] = string[i]
- s_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, s))
- return s_box
- def look_string(self, string_box):
- s = string_box.getref(lltype.Ptr(rstr.STR))
- return ''.join(s.chars)
- def alloc_unicode(self, unicode):
- u = rstr.mallocunicode(len(unicode))
- for i in range(len(unicode)):
- u.chars[i] = unicode[i]
- u_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, u))
- return u_box
- def look_unicode(self, unicode_box):
- u = unicode_box.getref(lltype.Ptr(rstr.UNICODE))
- return u''.join(u.chars)
- def test_cast_int_to_ptr(self):
- res = self.execute_operation(rop.CAST_INT_TO_PTR,
- [InputArgInt(-17)], 'ref')
- assert lltype.cast_ptr_to_int(res) == -17
- def test_cast_ptr_to_int(self):
- x = lltype.cast_int_to_ptr(llmemory.GCREF, -19)
- res = self.execute_operation(rop.CAST_PTR_TO_INT,
- [InputArgRef(x)], 'int')
- assert res == -19
- def test_cast_int_to_float(self):
- if not self.cpu.supports_floats:
- py.test.skip("requires floats")
- for x in [-10, -1, 0, 3, 42, sys.maxint-1]:
- res = self.execute_operation(rop.CAST_INT_TO_FLOAT,
- [InputArgInt(x)], 'float')
- assert longlong.getrealfloat(res) == float(x)
- # --- the front-end never generates CAST_INT_TO_FLOAT(Const)
- #res = self.execute_operation(rop.CAST_INT_TO_FLOAT,
- # [ConstInt(x)], 'float').value
- #assert longlong.getrealfloat(res) == float(x)
- def test_cast_float_to_int(self):
- if not self.cpu.supports_floats:
- py.test.skip("requires floats")
- for x in [-24.23, -5.3, 0.0, 3.1234, 11.1, 0.1]:
- v = longlong.getfloatstorage(x)
- res = self.execute_operation(rop.CAST_FLOAT_TO_INT,
- [InputArgFloat(v)], 'int')
- assert res == int(x)
- # --- the front-end never generates CAST_FLOAT_TO_INT(Const)
- #res = self.execute_operation(rop.CAST_FLOAT_TO_INT,
- # [ConstFloat(v)], 'int').value
- #assert res == int(x)
- def test_convert_float_bytes(self):
- if not self.cpu.supports_floats:
- py.test.skip("requires floats")
- if IS_32_BIT and not self.cpu.supports_longlong:
- py.test.skip("longlong test")
- t = 'int' if longlong.is_64_bit else 'float'
- res = self.execute_operation(rop.CONVERT_FLOAT_BYTES_TO_LONGLONG,
- [boxfloat(2.5)], t)
- assert res == longlong2float.float2longlong(2.5)
- bytes = longlong2float.float2longlong(2.5)
- res = self.execute_operation(rop.CONVERT_LONGLONG_BYTES_TO_FLOAT,
- [boxlonglong(bytes)], 'float')
- assert longlong.getrealfloat(res) == 2.5
- def test_ooops_non_gc(self):
- x = lltype.malloc(lltype.Struct('x'), flavor='raw')
- v = heaptracker.adr2int(llmemory.cast_ptr_to_adr(x))
- r = self.execute_operation(rop.PTR_EQ, [InputArgInt(v), InputArgInt(v)], 'int')
- assert r == 1
- r = self.execute_operation(rop.PTR_NE, [InputArgInt(v), InputArgInt(v)], 'int')
- assert r == 0
- lltype.free(x, flavor='raw')
- def test_new_plain_struct(self):
- cpu = self.cpu
- S = lltype.GcStruct('S', ('x', lltype.Char), ('y', lltype.Char))
- sizedescr = cpu.sizeof(S)
- r1 = self.execute_operation(rop.NEW, [], 'ref', descr=sizedescr)
- r2 = self.execute_operation(rop.NEW, [], 'ref', descr=sizedescr)
- assert r1 != r2
- xdescr = cpu.fielddescrof(S, 'x')
- ydescr = cpu.fielddescrof(S, 'y')
- self.execute_operation(rop.SETFIELD_GC, [InputArgRef(r1),
- InputArgInt(150)],
- 'void', descr=ydescr)
- self.execute_operation(rop.SETFIELD_GC, [InputArgRef(r1),
- InputArgInt(190)],
- 'void', descr=xdescr)
- s = lltype.cast_opaque_ptr(lltype.Ptr(S), r1)
- assert s.x == chr(190)
- assert s.y == chr(150)
- def test_new_with_vtable(self):
- cpu = self.cpu
- t_box, T_box, descr = self.alloc_instance(self.T)
- vtable = llmemory.cast_adr_to_ptr(
- llmemory.cast_int_to_adr(T_box.getint()), rclass.CLASSTYPE)
- r1 = self.execute_operation(rop.NEW_WITH_VTABLE, [], 'ref', descr)
- r2 = self.execute_operation(rop.NEW_WITH_VTABLE, [], 'ref', descr)
- assert r1 != r2
- descr1 = cpu.fielddescrof(self.S, 'chr1')
- descr2 = cpu.fielddescrof(self.S, 'chr2')
- descrshort = cpu.fielddescrof(self.S, 'short')
- descrshort.parent_descr.vtable = vtable
- self.execute_operation(rop.SETFIELD_GC, [InputArgRef(r1),
- InputArgInt(150)],
- 'void', descr=descr2)
- self.execute_operation(rop.SETFIELD_GC, [InputArgRef(r1),
- InputArgInt(190)],
- 'void', descr=descr1)
- self.execute_operation(rop.SETFIELD_GC, [InputArgRef(r1),
- InputArgInt(1313)],
- 'void', descr=descrshort)
- s = lltype.cast_opaque_ptr(lltype.Ptr(self.T), r1)
- assert s.parent.chr1 == chr(190)
- assert s.parent.chr2 == chr(150)
- r = self.cpu.bh_getfield_gc_i(r1, descrshort)
- assert r == 1313
- self.cpu.bh_setfield_gc_i(r1, 1333, descrshort)
- r = self.cpu.bh_getfield_gc_i(r1, descrshort)
- assert r == 1333
- r = self.execute_operation(rop.GETFIELD_GC_I, [InputArgRef(r1)], 'int',
- descr=descrshort)
- assert r == 1333
- t = lltype.cast_opaque_ptr(lltype.Ptr(self.T), t_box.getref_base())
- assert s.parent.parent.typeptr == t.parent.parent.typeptr
- def test_new_array(self):
- A = lltype.GcArray(lltype.Signed)
- arraydescr = self.cpu.arraydescrof(A)
- r1 = self.execute_operation(rop.NEW_ARRAY, [InputArgInt(342)],
- 'ref', descr=arraydescr)
- r2 = self.execute_operation(rop.NEW_ARRAY, [InputArgInt(342)],
- 'ref', descr=arraydescr)
- assert r1 != r2
- a = lltype.cast_opaque_ptr(lltype.Ptr(A), r1)
- assert len(a) == 342
- def test_new_array_clear(self):
- A = lltype.GcArray(lltype.Signed)
- arraydescr = self.cpu.arraydescrof(A)
- r1 = self.execute_operation(rop.NEW_ARRAY_CLEAR, [InputArgInt(342)],
- 'ref', descr=arraydescr)
- a = lltype.cast_opaque_ptr(lltype.Ptr(A), r1)
- assert a[0] == 0
- assert len(a) == 342
- def test_new_string(self):
- r1 = self.execute_operation(rop.NEWSTR, [InputArgInt(342)], 'ref')
- r2 = self.execute_operation(rop.NEWSTR, [InputArgInt(342)], 'ref')
- assert r1 != r2
- a = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), r1)
- assert len(a.chars) == 342
- def test_new_unicode(self):
- r1 = self.execute_operation(rop.NEWUNICODE, [InputArgInt(342)], 'ref')
- r2 = self.execute_operation(rop.NEWUNICODE, [InputArgInt(342)], 'ref')
- assert r1 != r2
- a = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), r1)
- assert len(a.chars) == 342
- def test_exceptions(self):
- exc_tp = None
- exc_ptr = None
- def func(i):
- if i:
- raise LLException(exc_tp, exc_ptr)
- ops = '''
- [i0]
- i1 = same_as_i(1)
- call_n(ConstClass(fptr), i0, descr=calldescr)
- p0 = guard_exception(ConstClass(xtp)) [i1]
- finish(p0)
- '''
- FPTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void))
- fptr = llhelper(FPTR, func)
- calldescr = self.cpu.calldescrof(FPTR.TO, FPTR.TO.ARGS, FPTR.TO.RESULT,
- EffectInfo.MOST_GENERAL)
- xtp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
- xtp.subclassrange_min = 1
- xtp.subclassrange_max = 3
- X = lltype.GcStruct('X', ('parent', rclass.OBJECT),
- hints={'vtable': xtp._obj})
- xptr = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(X))
- exc_tp = xtp
- exc_ptr = xptr
- loop = parse(ops, self.cpu, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, 1)
- assert self.cpu.get_ref_value(deadframe, 0) == xptr
- excvalue = self.cpu.grab_exc_value(deadframe)
- assert not excvalue
- deadframe = self.cpu.execute_token(looptoken, 0)
- assert self.cpu.get_int_value(deadframe, 0) == 1
- excvalue = self.cpu.grab_exc_value(deadframe)
- assert not excvalue
- ytp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
- ytp.subclassrange_min = 2
- ytp.subclassrange_max = 2
- assert rclass.ll_issubclass(ytp, xtp)
- Y = lltype.GcStruct('Y', ('parent', rclass.OBJECT),
- hints={'vtable': ytp._obj})
- yptr = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(Y))
- # guard_exception uses an exact match
- exc_tp = ytp
- exc_ptr = yptr
- loop = parse(ops, self.cpu, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, 1)
- assert self.cpu.get_int_value(deadframe, 0) == 1
- excvalue = self.cpu.grab_exc_value(deadframe)
- assert excvalue == yptr
- exc_tp = xtp
- exc_ptr = xptr
- ops = '''
- [i0]
- i1 = same_as_i(1)
- call_n(ConstClass(fptr), i0, descr=calldescr)
- guard_no_exception() [i1]
- finish(0)
- '''
- loop = parse(ops, self.cpu, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, 1)
- assert self.cpu.get_int_value(deadframe, 0) == 1
- excvalue = self.cpu.grab_exc_value(deadframe)
- assert excvalue == xptr
- deadframe = self.cpu.execute_token(looptoken, 0)
- assert self.cpu.get_int_value(deadframe, 0) == 0
- excvalue = self.cpu.grab_exc_value(deadframe)
- assert not excvalue
- def test_save_restore_exceptions(self):
- exc_tp = None
- exc_ptr = None
- def func(i):
- if hasattr(self.cpu, '_exception_emulator'):
- assert not self.cpu._exception_emulator[0]
- assert not self.cpu._exception_emulator[1]
- called.append(i)
- if i:
- raise LLException(exc_tp, exc_ptr)
- ops = '''
- [i0]
- i1 = same_as_i(1)
- call_n(ConstClass(fptr), i0, descr=calldescr)
- i2 = save_exc_class()
- p2 = save_exception()
- call_n(ConstClass(fptr), 0, descr=calldescr)
- restore_exception(i2, p2)
- p0 = guard_exception(ConstClass(xtp)) [i1]
- finish(p0)
- '''
- FPTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void))
- fptr = llhelper(FPTR, func)
- calldescr = self.cpu.calldescrof(FPTR.TO, FPTR.TO.ARGS, FPTR.TO.RESULT,
- EffectInfo.MOST_GENERAL)
- xtp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
- xtp.subclassrange_min = 1
- xtp.subclassrange_max = 3
- X = lltype.GcStruct('X', ('parent', rclass.OBJECT),
- hints={'vtable': xtp._obj})
- xx = lltype.malloc(X)
- xx.parent.typeptr = xtp
- xptr = lltype.cast_opaque_ptr(llmemory.GCREF, xx)
- exc_tp = xtp
- exc_ptr = xptr
- loop = parse(ops, self.cpu, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- called = []
- deadframe = self.cpu.execute_token(looptoken, 5)
- assert called == [5, 0]
- assert self.cpu.get_ref_value(deadframe, 0) == xptr
- excvalue = self.cpu.grab_exc_value(deadframe)
- assert not excvalue
- called = []
- deadframe = self.cpu.execute_token(looptoken, 0)
- assert called == [0, 0]
- assert self.cpu.get_int_value(deadframe, 0) == 1
- excvalue = self.cpu.grab_exc_value(deadframe)
- assert not excvalue
- def test_cond_call_gc_wb(self):
- def func_void(a):
- record.append(rffi.cast(lltype.Signed, a))
- record = []
- #
- S = lltype.GcStruct('S', ('tid', lltype.Signed))
- FUNC = self.FuncType([lltype.Ptr(S)], lltype.Void)
- func_ptr = llhelper(lltype.Ptr(FUNC), func_void)
- funcbox = self.get_funcbox(self.cpu, func_ptr)
- class WriteBarrierDescr(AbstractDescr):
- jit_wb_if_flag = 4096
- jit_wb_if_flag_byteofs = struct.pack("l", 4096).index('\x10')
- jit_wb_if_flag_singlebyte = 0x10
- def get_write_barrier_fn(self, cpu):
- return funcbox.getint()
- #
- for cond in [False, True]:
- value = random.randrange(-sys.maxint, sys.maxint)
- if cond:
- value |= 4096
- else:
- value &= ~4096
- s = lltype.malloc(S)
- s.tid = value
- sgcref = lltype.cast_opaque_ptr(llmemory.GCREF, s)
- del record[:]
- self.execute_operation(rop.COND_CALL_GC_WB,
- [InputArgRef(sgcref)],
- 'void', descr=WriteBarrierDescr())
- if cond:
- assert record == [rffi.cast(lltype.Signed, sgcref)]
- else:
- assert record == []
- def test_cond_call_gc_wb_array(self):
- def func_void(a):
- record.append(rffi.cast(lltype.Signed, a))
- record = []
- #
- S = lltype.GcStruct('S', ('tid', lltype.Signed))
- FUNC = self.FuncType([lltype.Ptr(S)], lltype.Void)
- func_ptr = llhelper(lltype.Ptr(FUNC), func_void)
- funcbox = self.get_funcbox(self.cpu, func_ptr)
- class WriteBarrierDescr(AbstractDescr):
- jit_wb_if_flag = 4096
- jit_wb_if_flag_byteofs = struct.pack("l", 4096).index('\x10')
- jit_wb_if_flag_singlebyte = 0x10
- jit_wb_cards_set = 0 # <= without card marking
- def get_write_barrier_fn(self, cpu):
- return funcbox.getint()
- #
- for cond in [False, True]:
- value = random.randrange(-sys.maxint, sys.maxint)
- if cond:
- value |= 4096
- else:
- value &= ~4096
- s = lltype.malloc(S)
- s.tid = value
- sgcref = lltype.cast_opaque_ptr(llmemory.GCREF, s)
- del record[:]
- self.execute_operation(rop.COND_CALL_GC_WB_ARRAY,
- [InputArgRef(sgcref), ConstInt(123)],
- 'void', descr=WriteBarrierDescr())
- if cond:
- assert record == [rffi.cast(lltype.Signed, sgcref)]
- else:
- assert record == []
- def test_cond_call_gc_wb_array_card_marking_fast_path(self):
- def func_void(a):
- record.append(rffi.cast(lltype.Signed, a))
- if cond == 1: # the write barrier sets the flag
- s.data.tid |= 32768
- record = []
- #
- S = lltype.Struct('S', ('tid', lltype.Signed))
- S_WITH_CARDS = lltype.Struct('S_WITH_CARDS',
- ('card0', lltype.Char),
- ('card1', lltype.Char),
- ('card2', lltype.Char),
- ('card3', lltype.Char),
- ('card4', lltype.Char),
- ('card5', lltype.Char),
- ('card6', lltype.Char),
- ('card7', lltype.Char),
- ('data', S))
- FUNC = self.FuncType([lltype.Ptr(S)], lltype.Void)
- func_ptr = llhelper(lltype.Ptr(FUNC), func_void)
- funcbox = self.get_funcbox(self.cpu, func_ptr)
- class WriteBarrierDescr(AbstractDescr):
- jit_wb_if_flag = 4096
- jit_wb_if_flag_byteofs = struct.pack("l", 4096).index('\x10')
- jit_wb_if_flag_singlebyte = 0x10
- jit_wb_cards_set = 32768
- jit_wb_cards_set_byteofs = struct.pack("l", 32768).index('\x80')
- jit_wb_cards_set_singlebyte = -0x80
- jit_wb_card_page_shift = 7
- def get_write_barrier_from_array_fn(self, cpu):
- return funcbox.getint()
- #
- for BoxIndexCls in [InputArgInt, ConstInt]*3:
- for cond in [-1, 0, 1, 2]:
- # cond=-1:GCFLAG_TRACK_YOUNG_PTRS, GCFLAG_CARDS_SET are not set
- # cond=0: GCFLAG_CARDS_SET is never set
- # cond=1: GCFLAG_CARDS_SET is not set, but the wb sets it
- # cond=2: GCFLAG_CARDS_SET is already set
- print
- print '_'*79
- print 'BoxIndexCls =', BoxIndexCls
- print 'testing cond =', cond
- print
- value = random.randrange(-sys.maxint, sys.maxint)
- if cond >= 0:
- value |= 4096
- else:
- value &= ~4096
- if cond == 2:
- value |= 32768
- else:
- value &= ~32768
- s = lltype.malloc(S_WITH_CARDS, immortal=True, zero=True)
- s.data.tid = value
- sgcref = rffi.cast(llmemory.GCREF, s.data)
- del record[:]
- box_index = BoxIndexCls((9<<7) + 17)
- self.execute_operation(rop.COND_CALL_GC_WB_ARRAY,
- [InputArgRef(sgcref), box_index],
- 'void', descr=WriteBarrierDescr())
- if cond in [0, 1]:
- assert record == [rffi.cast(lltype.Signed, s.data)]
- else:
- assert record == []
- if cond in [1, 2]:
- assert s.card6 == '\x02'
- else:
- assert s.card6 == '\x00'
- assert s.card0 == '\x00'
- assert s.card1 == '\x00'
- assert s.card2 == '\x00'
- assert s.card3 == '\x00'
- assert s.card4 == '\x00'
- assert s.card5 == '\x00'
- assert s.card7 == '\x00'
- if cond == 1:
- value |= 32768
- assert s.data.tid == value
- def test_cond_call_1(self):
- def func_void(*args):
- called.append(args)
- for i in range(5):
- called = []
- FUNC = self.FuncType([lltype.Signed] * i, lltype.Void)
- func_ptr = llhelper(lltype.Ptr(FUNC), func_void)
- calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
- ops = '''
- [i0, i1, i2, i3, i4, i5, i6, f0, f1]
- cond_call(i1, ConstClass(func_ptr), %s)
- guard_false(i0, descr=faildescr) [i1, i2, i3, i4, i5, i6, f0, f1]
- ''' % ', '.join(['i%d' % (j + 2) for j in range(i)] + ["descr=calldescr"])
- loop = parse(ops, namespace={'faildescr': BasicFailDescr(),
- 'func_ptr': func_ptr,
- 'calldescr': calldescr})
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- f1 = longlong.getfloatstorage(1.2)
- f2 = longlong.getfloatstorage(3.4)
- frame = self.cpu.execute_token(looptoken, 1, 0, 1, 2, 3, 4, 5, f1, f2)
- assert not called
- for j in range(5):
- assert self.cpu.get_int_value(frame, j) == j
- assert longlong.getrealfloat(self.cpu.get_float_value(frame, 6)) == 1.2
- assert longlong.getrealfloat(self.cpu.get_float_value(frame, 7)) == 3.4
- frame = self.cpu.execute_token(looptoken, 1, 1, 1, 2, 3, 4, 5, f1, f2)
- assert called == [tuple(range(1, i + 1))]
- for j in range(4):
- assert self.cpu.get_int_value(frame, j + 1) == j + 1
- assert longlong.getrealfloat(self.cpu.get_float_value(frame, 6)) == 1.2
- assert longlong.getrealfloat(self.cpu.get_float_value(frame, 7)) == 3.4
- def test_cond_call_2(self):
- def func_void(*args):
- called.append(args)
- FUNC = self.FuncType([lltype.Signed, lltype.Signed], lltype.Void)
- func_ptr = llhelper(lltype.Ptr(FUNC), func_void)
- calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
- gfs = longlong.getfloatstorage
- for (operation, arg1, arg2_if_true, arg2_if_false) in [
- ('int_lt', -5, 2, -5),
- ('int_le', 5, 5, -6),
- ('int_eq', 11, 11, 12),
- ('int_ne', 11, 12, 11),
- ('int_gt', 8, -1, 8),
- ('int_xor', 7, 3, 7), # test without a comparison at all
- ('int_is_true', 4242, 1, 0),
- ('int_is_zero', 4242, 0, 1),
- ('float_lt', gfs(-0.5), gfs(0.2), gfs(-0.5)),
- ('float_eq', gfs(1.1), gfs(1.1), gfs(1.2)),
- ]:
- called = []
- ops = '''
- [%s, %s, i3, i4]
- i2 = %s(%s)
- cond_call(i2, ConstClass(func_ptr), i3, i4, descr=calldescr)
- guard_no_exception(descr=faildescr) []
- finish()
- ''' % ("i0" if operation.startswith('int') else "f0",
- "i1" if operation.startswith('int') else "f1",
- operation,
- ("i1" if operation.startswith('int_is_') else
- "i0, i1" if operation.startswith('int') else
- "f0, f1"))
- loop = parse(ops, namespace={'func_ptr': func_ptr,
- 'calldescr': calldescr,
- 'faildescr': BasicFailDescr()})
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- frame = self.cpu.execute_token(looptoken, arg1, arg2_if_false, 0, 0)
- assert called == []
- frame = self.cpu.execute_token(looptoken, arg1, arg2_if_true,
- 67, 89)
- assert called == [(67, 89)]
- def test_force_operations_returning_void(self):
- values = []
- def maybe_force(token, flag):
- if flag:
- deadframe = self.cpu.force(token)
- values.append(self.cpu.get_latest_descr(deadframe))
- values.append(self.cpu.get_int_value(deadframe, 0))
- values.append(self.cpu.get_int_value(deadframe, 1))
- self.cpu.set_savedata_ref(deadframe, random_gcref)
- FUNC = self.FuncType([llmemory.GCREF, lltype.Signed], lltype.Void)
- func_ptr = llhelper(lltype.Ptr(FUNC), maybe_force)
- calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
- cpu = self.cpu
- faildescr = BasicFailDescr(1)
- finaldescr = BasicFinalDescr(0)
- loop = parse("""
- [i0, i1]
- p2 = force_token()
- call_may_force_n(ConstClass(func_ptr), p2, i1, descr=calldescr)
- guard_not_forced(descr=faildescr) [i1, i0]
- finish(i0, descr=finaldescr)
- """, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, 20, 0)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 0
- assert self.cpu.get_int_value(deadframe, 0) == 20
- assert values == []
- deadframe = self.cpu.execute_token(looptoken, 10, 1)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 1
- assert self.cpu.get_int_value(deadframe, 0) == 1
- assert self.cpu.get_int_value(deadframe, 1) == 10
- assert values == [faildescr, 1, 10]
- assert self.cpu.get_savedata_ref(deadframe) # not NULL
- assert self.cpu.get_savedata_ref(deadframe) == random_gcref
- def test_force_operations_returning_int(self):
- values = []
- def maybe_force(token, flag):
- if flag:
- deadframe = self.cpu.force(token)
- values.append(self.cpu.get_int_value(deadframe, 0))
- values.append(self.cpu.get_int_value(deadframe, 2))
- self.cpu.set_savedata_ref(deadframe, random_gcref)
- return 42
- FUNC = self.FuncType([llmemory.GCREF, lltype.Signed], lltype.Signed)
- func_ptr = llhelper(lltype.Ptr(FUNC), maybe_force)
- calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
- cpu = self.cpu
- faildescr = BasicFailDescr(1)
- finaldescr = BasicFinalDescr(0)
- loop = parse("""
- [i0, i1]
- p3 = force_token()
- i2 = call_may_force_i(ConstClass(func_ptr), p3, i1, descr=calldescr)
- guard_not_forced(descr=faildescr) [i1, i2, i0]
- finish(i2, descr=finaldescr)
- """, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, 20, 0)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 0
- assert self.cpu.get_int_value(deadframe, 0) == 42
- assert values == []
- deadframe = self.cpu.execute_token(looptoken, 10, 1)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 1
- assert self.cpu.get_int_value(deadframe, 0) == 1
- assert self.cpu.get_int_value(deadframe, 1) == 42
- assert self.cpu.get_int_value(deadframe, 2) == 10
- assert values == [1, 10]
- assert self.cpu.get_savedata_ref(deadframe) == random_gcref
- def test_force_operations_returning_float(self):
- if not self.cpu.supports_floats:
- py.test.skip("requires floats")
- values = []
- def maybe_force(token, flag):
- if flag:
- deadframe = self.cpu.force(token)
- values.append(self.cpu.get_int_value(deadframe, 0))
- values.append(self.cpu.get_int_value(deadframe, 2))
- self.cpu.set_savedata_ref(deadframe, random_gcref)
- return 42.5
- FUNC = self.FuncType([llmemory.GCREF, lltype.Signed], lltype.Float)
- func_ptr = llhelper(lltype.Ptr(FUNC), maybe_force)
- funcbox = self.get_funcbox(self.cpu, func_ptr).constbox()
- calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
- cpu = self.cpu
- faildescr = BasicFailDescr(1)
- finaldescr = BasicFinalDescr(0)
- loop = parse("""
- [i0, i1]
- p3 = force_token()
- f2 = call_may_force_f(ConstClass(func_ptr), p3, i1, descr=calldescr)
- guard_not_forced(descr=faildescr) [i1, f2, i0]
- finish(f2, descr=finaldescr)
- """, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, 20, 0)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 0
- x = self.cpu.get_float_value(deadframe, 0)
- assert longlong.getrealfloat(x) == 42.5
- assert values == []
- deadframe = self.cpu.execute_token(looptoken, 10, 1)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 1
- assert self.cpu.get_int_value(deadframe, 0) == 1
- x = self.cpu.get_float_value(deadframe, 1)
- assert longlong.getrealfloat(x) == 42.5
- assert self.cpu.get_int_value(deadframe, 2) == 10
- assert values == [1, 10]
- assert self.cpu.get_savedata_ref(deadframe) == random_gcref
- def test_guard_not_forced_2(self):
- cpu = self.cpu
- faildescr = BasicFailDescr(1)
- finaldescr = BasicFinalDescr(0)
- loop = parse("""
- [i0]
- i1 = int_add(i0, 10)
- p2 = force_token()
- guard_not_forced_2(descr=faildescr) [i1]
- finish(p2, descr=finaldescr)
- """, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, 20)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 0
- frame = self.cpu.get_ref_value(deadframe, 0)
- # actually, we should get the same pointer in 'frame' and 'deadframe'
- # but it is not the case on LLGraph
- if not getattr(self.cpu, 'is_llgraph', False):
- assert frame == deadframe
- deadframe2 = self.cpu.force(frame)
- assert self.cpu.get_int_value(deadframe2, 0) == 30
- def test_call_to_c_function(self):
- from rpython.rlib.libffi import CDLL, types, ArgChain, FUNCFLAG_CDECL
- from rpython.rtyper.lltypesystem.ll2ctypes import libc_name
- libc = CDLL(libc_name)
- c_tolower = libc.getpointer('tolower', [types.uchar], types.sint)
- argchain = ArgChain().arg(ord('A'))
- assert c_tolower.call(argchain, rffi.INT) == ord('a')
- cpu = self.cpu
- func_adr = c_tolower.funcsym
- calldescr = cpu._calldescr_dynamic_for_tests([types.uchar], types.sint)
- faildescr = BasicFailDescr(1)
- finaldescr = BasicFinalDescr(0)
- loop = parse("""
- [i1]
- i2 = call_release_gil_i(0, ConstClass(func_adr), i1, descr=calldescr)
- guard_not_forced(descr=faildescr) [i1, i2]
- finish(i2, descr=finaldescr)
- """, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, ord('G'))
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 0
- assert self.cpu.get_int_value(deadframe, 0) == ord('g')
- def test_call_to_c_function_with_callback(self):
- from rpython.rlib.libffi import CDLL, types, ArgChain, clibffi
- from rpython.rtyper.lltypesystem.ll2ctypes import libc_name
- libc = CDLL(libc_name)
- types_size_t = clibffi.cast_type_to_ffitype(rffi.SIZE_T)
- c_qsort = libc.getpointer('qsort', [types.pointer, types_size_t,
- types_size_t, types.pointer],
- types.void)
- class Glob(object):
- pass
- glob = Glob()
- class X(object):
- pass
- #
- def callback(p1, p2):
- glob.lst.append(X())
- return rffi.cast(rffi.INT, 1)
- CALLBACK = lltype.Ptr(lltype.FuncType([lltype.Signed,
- lltype.Signed], rffi.INT))
- fn = llhelper(CALLBACK, callback)
- S = lltype.Struct('S', ('x', rffi.INT), ('y', rffi.INT))
- raw = lltype.malloc(S, flavor='raw')
- argchain = ArgChain()
- argchain = argchain.arg(rffi.cast(lltype.Signed, raw))
- argchain = argchain.arg(rffi.cast(rffi.SIZE_T, 2))
- argchain = argchain.arg(rffi.cast(rffi.SIZE_T, 4))
- argchain = argchain.arg(rffi.cast(lltype.Signed, fn))
- glob.lst = []
- c_qsort.call(argchain, lltype.Void)
- assert len(glob.lst) > 0
- del glob.lst[:]
- cpu = self.cpu
- func_adr = c_qsort.funcsym
- calldescr = cpu._calldescr_dynamic_for_tests(
- [types.pointer, types_size_t, types_size_t, types.pointer],
- types.void)
- faildescr = BasicFailDescr(1)
- finaldescr = BasicFinalDescr(0)
- loop = parse("""
- [i0, i1, i2, i3]
- call_release_gil_n(0, ConstClass(func_adr), i0, i1, i2, i3, descr=calldescr)
- guard_not_forced(descr=faildescr) []
- finish(descr=finaldescr)
- """, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- args = [rffi.cast(lltype.Signed, raw),
- 2,
- 4,
- rffi.cast(lltype.Signed, fn)]
- assert glob.lst == []
- deadframe = self.cpu.execute_token(looptoken, *args)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 0
- assert len(glob.lst) > 0
- lltype.free(raw, flavor='raw')
- def test_call_to_winapi_function(self):
- from rpython.rlib.clibffi import _WIN32
- if not _WIN32:
- py.test.skip("Windows test only")
- from rpython.rlib.libffi import WinDLL, types, ArgChain
- from rpython.rlib.rwin32 import DWORD
- libc = WinDLL('KERNEL32')
- c_GetCurrentDir = libc.getpointer('GetCurrentDirectoryA',
- [types.ulong, types.pointer],
- types.ulong)
- cwd = os.getcwd()
- buflen = len(cwd) + 10
- buffer = lltype.malloc(rffi.CCHARP.TO, buflen, flavor='raw')
- argchain = ArgChain().arg(rffi.cast(DWORD, buflen)).arg(buffer)
- res = c_GetCurrentDir.call(argchain, DWORD)
- assert rffi.cast(lltype.Signed, res) == len(cwd)
- assert rffi.charp2strn(buffer, buflen) == cwd
- lltype.free(buffer, flavor='raw')
- cpu = self.cpu
- func_adr = llmemory.cast_ptr_to_adr(c_GetCurrentDir.funcsym)
- funcbox = ConstInt(heaptracker.adr2int(func_adr))
- calldescr = cpu._calldescr_dynamic_for_tests(
- [types.ulong, types.pointer],
- types.ulong,
- abiname='FFI_STDCALL')
- i1 = InputArgInt()
- i2 = InputArgInt()
- faildescr = BasicFailDescr(1)
- # if the stdcall convention is ignored, then ESP is wrong after the
- # call: 8 bytes too much. If we repeat the call often enough, crash.
- ops = []
- for i in range(50):
- ops += [
- ResOperation(rop.CALL_RELEASE_GIL_I,
- [ConstInt(0), funcbox, i1, i2],
- descr=calldescr),
- ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr),
- ]
- i3 = ops[-2]
- ops[-1].setfailargs([])
- ops += [
- ResOperation(rop.FINISH, [i3], descr=BasicFinalDescr(0))
- ]
- looptoken = JitCellToken()
- self.cpu.compile_loop([i1, i2], ops, looptoken)
- buffer = lltype.malloc(rffi.CCHARP.TO, buflen, flavor='raw')
- args = [buflen, rffi.cast(lltype.Signed, buffer)]
- deadframe = self.cpu.execute_token(looptoken, *args)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 0
- assert self.cpu.get_int_value(deadframe, 0) == len(cwd)
- assert rffi.charp2strn(buffer, buflen) == cwd
- lltype.free(buffer, flavor='raw')
- def test_call_release_gil_return_types(self):
- from rpython.rlib.libffi import types
- from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong
- from rpython.rlib.rarithmetic import r_singlefloat
- cpu = self.cpu
- for ffitype, result, TP in [
- (types.ulong, r_uint(sys.maxint + 10), lltype.Unsigned),
- (types.slong, -4321, lltype.Signed),
- (types.uint8, 200, rffi.UCHAR),
- (types.sint8, -42, rffi.SIGNEDCHAR),
- (types.uint16, 50000, rffi.USHORT),
- (types.sint16, -20000, rffi.SHORT),
- (types.uint32, r_uint(3000000000), rffi.UINT),
- (types.sint32, -2000000000, rffi.INT),
- (types.uint64, r_ulonglong(9999999999999999999),
- lltype.UnsignedLongLong),
- (types.sint64, r_longlong(-999999999999999999),
- lltype.SignedLongLong),
- (types.double, 12.3475226, rffi.DOUBLE),
- (types.float, r_singlefloat(-592.75), rffi.FLOAT),
- ]:
- if IS_32_BIT and TP in (lltype.SignedLongLong,
- lltype.UnsignedLongLong):
- if not cpu.supports_longlong:
- continue
- if TP == rffi.DOUBLE:
- if not cpu.supports_floats:
- continue
- if TP == rffi.FLOAT:
- if not cpu.supports_singlefloats:
- continue
- #
- result = rffi.cast(TP, result)
- #
- def pseudo_c_function():
- return result
- #
- FPTR = self.Ptr(self.FuncType([], TP))
- func_ptr = llhelper(FPTR, pseudo_c_function)
- funcbox = self.get_funcbox(cpu, func_ptr)
- calldescr = cpu._calldescr_dynamic_for_tests([], ffitype)
- faildescr = BasicFailDescr(1)
- kind = types.getkind(ffitype)
- if kind in 'uis':
- opnum = rop.CALL_RELEASE_GIL_I
- elif kind in 'fUI':
- opnum = rop.CALL_RELEASE_GIL_F
- else:
- assert 0, kind
- #
- op0 = ResOperation(opnum, [ConstInt(0), funcbox], descr=calldescr)
- op1 = ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr)
- op2 = ResOperation(rop.FINISH, [op0], BasicFinalDescr(0))
- ops = [op0, op1, op2]
- ops[1].setfailargs([])
- looptoken = JitCellToken()
- self.cpu.compile_loop([], ops, looptoken)
- deadframe = self.cpu.execute_token(looptoken)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 0
- if kind in 'uis':
- r = self.cpu.get_int_value(deadframe, 0)
- if isinstance(result, r_singlefloat):
- assert -sys.maxint-1 <= r <= 0xFFFFFFFF
- r, = struct.unpack("f", struct.pack("I", r & 0xFFFFFFFF))
- result = float(result)
- else:
- r = rffi.cast(TP, r)
- assert r == result
- elif kind in 'fUI':
- r = self.cpu.get_float_value(deadframe, 0)
- if isinstance(result, float):
- r = longlong.getrealfloat(r)
- else:
- r = rffi.cast(TP, r)
- assert r == result
- def test_call_release_gil_variable_function_and_arguments(self):
- from rpython.translator.tool.cbuild import ExternalCompilationInfo
- from rpython.rlib.libffi import types
- from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong
- from rpython.rlib.rarithmetic import r_singlefloat
- from rpython.translator.c import primitive
- def same_as_for_box(b):
- if b.type == 'i':
- return rop.SAME_AS_I
- elif b.type == 'f':
- return rop.SAME_AS_F
- else:
- assert False
- cpu = self.cpu
- rnd = random.Random(525)
- seed = py.test.config.option.randomseed
- print("random seed %d" % seed)
- ALL_TYPES = [
- (types.ulong, lltype.Unsigned),
- (types.slong, lltype.Signed),
- (types.uint8, rffi.UCHAR),
- (types.sint8, rffi.SIGNEDCHAR),
- (types.uint16, rffi.USHORT),
- (types.sint16, rffi.SHORT),
- (types.uint32, rffi.UINT),
- (types.sint32, rffi.INT),
- ]
- if IS_32_BIT and cpu.supports_longlong:
- ALL_TYPES += [
- (types.uint64, lltype.UnsignedLongLong),
- (types.sint64, lltype.SignedLongLong),
- ] * 2
- if cpu.supports_floats:
- ALL_TYPES += [
- (types.double, rffi.DOUBLE),
- ] * 4
- if cpu.supports_singlefloats:
- ALL_TYPES += [
- (types.float, rffi.FLOAT),
- ] * 4
- NB_TESTS = 100
- c_source = []
- all_tests = []
- def prepare_c_source():
- """Pick a random choice of argument types and length,
- and build a C function with these arguments. The C
- function will simply copy them all into static global
- variables. There are then additional functions to fetch
- them, one per argument, with a signature 'void(ARG *)'.
- """
- POSSIBLE_TYPES = [rnd.choice(ALL_TYPES)
- for i in range(random.randrange(2, 5))]
- load_factor = rnd.random()
- keepalive_factor = rnd.random()
- #
- ffitypes = []
- ARGTYPES = []
- for i in range(rnd.randrange(4, 20)):
- ffitype, TP = rnd.choice(POSSIBLE_TYPES)
- ffitypes.append(ffitype)
- ARGTYPES.append(TP)
- fn_name = 'vartest%d' % k
- all_tests.append((ARGTYPES, ffitypes, fn_name))
- #
- fn_args = []
- for i, ARG in enumerate(ARGTYPES):
- arg_decl = primitive.cdecl(primitive.PrimitiveType[ARG],
- 'x%d' % i)
- fn_args.append(arg_decl)
- var_name = 'argcopy_%s_x%d' % (fn_name, i)
- var_decl = primitive.cdecl(primitive.PrimitiveType[ARG],
- var_name)
- c_source.append('static %s;' % var_decl)
- getter_name = '%s_get%d' % (fn_name, i)
- c_source.append('RPY_EXPORTED void %s(%s) { *p = %s; }' % (
- getter_name,
- primitive.cdecl(primitive.PrimitiveType[ARG], '*p'),
- var_name))
- c_source.append('')
- c_source.append('static void real%s(%s)' % (
- fn_name, ', '.join(fn_args)))
- c_source.append('{')
- for i in range(len(ARGTYPES)):
- c_source.append(' argcopy_%s_x%d = x%d;' % (fn_name, i, i))
- c_source.append('}')
- c_source.append('RPY_EXPORTED void *%s(void)' % fn_name)
- c_source.append('{')
- c_source.append(' return (void *)&real%s;' % fn_name)
- c_source.append('}')
- c_source.append('')
- for k in range(NB_TESTS):
- prepare_c_source()
- eci = ExternalCompilationInfo(
- separate_module_sources=['\n'.join(c_source)])
- for k in range(NB_TESTS):
- ARGTYPES, ffitypes, fn_name = all_tests[k]
- func_getter_ptr = rffi.llexternal(fn_name, [], lltype.Signed,
- compilation_info=eci, _nowrapper=True)
- load_factor = rnd.random()
- keepalive_factor = rnd.random()
- #
- func_raw = func_getter_ptr()
- calldescr = cpu._calldescr_dynamic_for_tests(ffitypes, types.void)
- faildescr = BasicFailDescr(1)
- #
- argboxes = [InputArgInt()] # for the function to call
- codes = ['X']
- for ffitype in ffitypes:
- kind = types.getkind(ffitype)
- codes.append(kind)
- if kind in 'uis':
- b1 = InputArgInt()
- elif kind in 'fUI':
- b1 = InputArgFloat()
- else:
- assert 0, kind
- argboxes.append(b1)
- codes = ''.join(codes) # useful for pdb
- print
- print codes
- #
- argvalues = [func_raw]
- for TP in ARGTYPES:
- r = (rnd.random() - 0.5) * 999999999999.9
- r = rffi.cast(TP, r)
- argvalues.append(r)
- #
- argvalues_normal = argvalues[:1]
- for ffitype, r in zip(ffitypes, argvalues[1:]):
- kind = types.getkind(ffitype)
- if kind in 'ui':
- r = rffi.cast(lltype.Signed, r)
- elif kind in 's':
- r, = struct.unpack("i", struct.pack("f", float(r)))
- elif kind in 'f':
- r = longlong.getfloatstorage(r)
- elif kind in 'UI': # 32-bit only
- r = rffi.cast(lltype.SignedLongLong, r)
- else:
- assert 0
- argvalues_normal.append(r)
- #
- ops = []
- loadcodes = []
- insideboxes = []
- for b1 in argboxes:
- load = rnd.random() < load_factor
- loadcodes.append(' ^'[load])
- if load:
- b2 = ResOperation(same_as_for_box(b1), [b1])
- ops.insert(rnd.randrange(0, len(ops)+1), b2)
- b1 = b2
- insideboxes.append(b1)
- loadcodes = ''.join(loadcodes)
- print loadcodes
- ops += [
- ResOperation(rop.CALL_RELEASE_GIL_N,
- [ConstInt(0)] + insideboxes,
- descr=calldescr),
- ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr),
- ResOperation(rop.FINISH, [], descr=BasicFinalDescr(0))
- ]
- ops[-2].setfailargs([])
- # keep alive a random subset of the insideboxes
- for b1 in insideboxes:
- if rnd.random() < keepalive_factor:
- ops.insert(-1, ResOperation(same_as_for_box(b1), [b1]))
- looptoken = JitCellToken()
- self.cpu.compile_loop(argboxes, ops, looptoken)
- #
- deadframe = self.cpu.execute_token(looptoken, *argvalues_normal)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 0
- expected = argvalues[1:]
- got = []
- for i, ARG in enumerate(ARGTYPES):
- PARG = rffi.CArrayPtr(ARG)
- getter_name = '%s_get%d' % (fn_name, i)
- getter_ptr = rffi.llexternal(getter_name, [PARG], lltype.Void,
- compilation_info=eci,
- _nowrapper=True)
- my_arg = lltype.malloc(PARG.TO, 1, zero=True, flavor='raw')
- getter_ptr(my_arg)
- got.append(my_arg[0])
- lltype.free(my_arg, flavor='raw')
- different_values = ['x%d: got %r, expected %r' % (i, a, b)
- for i, (a, b) in enumerate(zip(got, expected))
- if a != b]
- assert got == expected, '\n'.join(
- ['bad args, signature %r' % codes[1:]] + different_values)
- def test_call_release_gil_save_errno(self):
- from rpython.translator.tool.cbuild import ExternalCompilationInfo
- from rpython.rlib.libffi import types
- from rpython.jit.backend.llsupport import llerrno
- #
- if not isinstance(self.cpu, AbstractLLCPU):
- py.test.skip("not on LLGraph")
- eci = ExternalCompilationInfo(
- separate_module_sources=['''
- #include <errno.h>
- static long f1(long a, long b, long c, long d,
- long e, long f, long g) {
- errno = 42;
- return (a + 10*b + 100*c + 1000*d +
- 10000*e + 100000*f + 1000000*g);
- }
- RPY_EXPORTED
- long test_call_release_gil_save_errno(void) {
- return (long)&f1;
- }
- '''])
- fn_name = 'test_call_release_gil_save_errno'
- getter_ptr = rffi.llexternal(fn_name, [], lltype.Signed,
- compilation_info=eci, _nowrapper=True)
- func1_adr = getter_ptr()
- calldescr = self.cpu._calldescr_dynamic_for_tests([types.slong]*7,
- types.slong)
- #
- for saveerr in [rffi.RFFI_ERR_NONE,
- rffi.RFFI_SAVE_ERRNO,
- rffi.RFFI_ERR_NONE | rffi.RFFI_ALT_ERRNO,
- rffi.RFFI_SAVE_ERRNO | rffi.RFFI_ALT_ERRNO,
- ]:
- faildescr = BasicFailDescr(1)
- inputargs = [InputArgInt() for i in range(7)]
- op0 = ResOperation(rop.CALL_RELEASE_GIL_I,
- [ConstInt(saveerr), ConstInt(func1_adr)]
- + inputargs,
- descr=calldescr)
- ops = [
- op0,
- ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr),
- ResOperation(rop.FINISH, [op0], descr=BasicFinalDescr(0))
- ]
- ops[-2].setfailargs([])
- looptoken = JitCellToken()
- self.cpu.compile_loop(inputargs, ops, looptoken)
- #
- llerrno.set_debug_saved_errno(self.cpu, 24)
- llerrno.set_debug_saved_alterrno(self.cpu, 25)
- deadframe = self.cpu.execute_token(looptoken, 9, 8, 7, 6, 5, 4, 3)
- original_result = self.cpu.get_int_value(deadframe, 0)
- result = llerrno.get_debug_saved_errno(self.cpu)
- altresult = llerrno.get_debug_saved_alterrno(self.cpu)
- print 'saveerr =', saveerr, ': got result =', result, \
- 'altresult =', altresult
- #
- expected = {
- rffi.RFFI_ERR_NONE: (24, 25),
- rffi.RFFI_SAVE_ERRNO: (42, 25),
- rffi.RFFI_ERR_NONE | rffi.RFFI_ALT_ERRNO: (24, 25),
- rffi.RFFI_SAVE_ERRNO | rffi.RFFI_ALT_ERRNO: (24, 42),
- }
- # expected (24, 25) as originally set, with possibly one
- # of the two changed to 42 by the assembler code
- assert (result, altresult) == expected[saveerr]
- assert original_result == 3456789
- def test_call_release_gil_readsaved_errno(self):
- from rpython.translator.tool.cbuild import ExternalCompilationInfo
- from rpython.rlib.libffi import types
- from rpython.jit.backend.llsupport import llerrno
- #
- if not isinstance(self.cpu, AbstractLLCPU):
- py.test.skip("not on LLGraph")
- eci = ExternalCompilationInfo(
- separate_module_sources=[r'''
- #include <stdio.h>
- #include <errno.h>
- static long f1(long a, long b, long c, long d,
- long e, long f, long g) {
- long r = errno;
- printf("read saved errno: %ld\n", r);
- r += 100 * (a + 10*b + 100*c + 1000*d +
- 10000*e + 100000*f + 1000000*g);
- return r;
- }
- RPY_EXPORTED
- long test_call_release_gil_readsaved_errno(void) {
- return (long)&f1;
- }
- '''])
- fn_name = 'test_call_release_gil_readsaved_errno'
- getter_ptr = rffi.llexternal(fn_name, [], lltype.Signed,
- compilation_info=eci, _nowrapper=True)
- func1_adr = getter_ptr()
- calldescr = self.cpu._calldescr_dynamic_for_tests([types.slong]*7,
- types.slong)
- #
- for saveerr in [rffi.RFFI_READSAVED_ERRNO,
- rffi.RFFI_ZERO_ERRNO_BEFORE,
- rffi.RFFI_READSAVED_ERRNO | rffi.RFFI_ALT_ERRNO,
- rffi.RFFI_ZERO_ERRNO_BEFORE | rffi.RFFI_ALT_ERRNO,
- ]:
- faildescr = BasicFailDescr(1)
- inputargs = [InputArgInt() for i in range(7)]
- op0 = ResOperation(rop.CALL_RELEASE_GIL_I,
- [ConstInt(saveerr), ConstInt(func1_adr)]
- + inputargs,
- descr=calldescr)
- ops = [
- op0,
- ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr),
- ResOperation(rop.FINISH, [op0], descr=BasicFinalDescr(0))
- ]
- ops[-2].setfailargs([])
- looptoken = JitCellToken()
- self.cpu.compile_loop(inputargs, ops, looptoken)
- #
- llerrno.set_debug_saved_errno(self.cpu, 24)
- llerrno.set_debug_saved_alterrno(self.cpu, 25)
- deadframe = self.cpu.execute_token(looptoken, 9, 8, 7, 6, 5, 4, 3)
- result = self.cpu.get_int_value(deadframe, 0)
- assert llerrno.get_debug_saved_errno(self.cpu) == 24
- assert llerrno.get_debug_saved_alterrno(self.cpu) == 25
- #
- if saveerr & rffi.RFFI_READSAVED_ERRNO:
- if saveerr & rffi.RFFI_ALT_ERRNO:
- assert result == 25 + 345678900
- else:
- assert result == 24 + 345678900
- else:
- assert result == 0 + 345678900
- def test_call_release_gil_save_lasterror(self):
- from rpython.translator.tool.cbuild import ExternalCompilationInfo
- from rpython.rlib.libffi import types
- from rpython.jit.backend.llsupport import llerrno
- #
- if not isinstance(self.cpu, AbstractLLCPU):
- py.test.skip("not on LLGraph")
- if sys.platform != 'win32':
- py.test.skip("Windows test only")
- eci = ExternalCompilationInfo(
- separate_module_sources=['''
- #include <windows.h>
- static long f1(long a, long b, long c, long d,
- long e, long f, long g) {
- SetLastError(42);
- return (a + 10*b + 100*c + 1000*d +
- 10000*e + 100000*f + 1000000*g);
- }
- RPY_EXPORTED
- long test_call_release_gil_save_lasterror(void) {
- return (long)&f1;
- }
- '''])
- fn_name = 'test_call_release_gil_save_lasterror'
- getter_ptr = rffi.llexternal(fn_name, [], lltype.Signed,
- compilation_info=eci, _nowrapper=True)
- func1_adr = getter_ptr()
- calldescr = self.cpu._calldescr_dynamic_for_tests([types.slong]*7,
- types.slong)
- #
- for saveerr in [rffi.RFFI_SAVE_ERRNO, # but not _LASTERROR
- rffi.RFFI_SAVE_ERRNO | rffi.RFFI_ALT_ERRNO,
- rffi.RFFI_SAVE_LASTERROR,
- rffi.RFFI_SAVE_LASTERROR | rffi.RFFI_ALT_ERRNO,
- ]:
- faildescr = BasicFailDescr(1)
- inputargs = [InputArgInt() for i in range(7)]
- ops = [
- ResOperation(rop.CALL_RELEASE_GIL_I,
- [ConstInt(saveerr), ConstInt(func1_adr)]
- + inputargs,
- descr=calldescr),
- ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr),
- ]
- i1 = ops[0]
- ops += [ResOperation(rop.FINISH, [i1], descr=BasicFinalDescr(0))]
- ops[-2].setfailargs([])
- looptoken = JitCellToken()
- self.cpu.compile_loop(inputargs, ops, looptoken)
- #
- llerrno.set_debug_saved_lasterror(self.cpu, 24)
- llerrno.set_debug_saved_altlasterror(self.cpu, 25)
- deadframe = self.cpu.execute_token(looptoken, 9, 8, 7, 6, 5, 4, 3)
- original_result = self.cpu.get_int_value(deadframe, 0)
- result = llerrno.get_debug_saved_lasterror(self.cpu)
- altresult = llerrno.get_debug_saved_altlasterror(self.cpu)
- print 'saveerr =', saveerr, ': got result =', result,
- print 'and altresult =', altresult
- #
- if saveerr & rffi.RFFI_SAVE_LASTERROR:
- # one from the C code, the other not touched
- if saveerr & rffi.RFFI_ALT_ERRNO:
- assert (result, altresult) == (24, 42)
- else:
- assert (result, altresult) == (42, 25)
- else:
- assert (result, altresult) == (24, 25) # not touched
- assert original_result == 3456789
- def test_call_release_gil_readsaved_lasterror(self):
- from rpython.translator.tool.cbuild import ExternalCompilationInfo
- from rpython.rlib.libffi import types
- from rpython.jit.backend.llsupport import llerrno
- #
- if not isinstance(self.cpu, AbstractLLCPU):
- py.test.skip("not on LLGraph")
- if sys.platform != 'win32':
- py.test.skip("Windows test only")
- eci = ExternalCompilationInfo(
- separate_module_sources=[r'''
- #include <windows.h>
- static long f1(long a, long b, long c, long d,
- long e, long f, long g) {
- long r = GetLastError();
- printf("GetLastError() result: %ld\n", r);
- printf("%ld %ld %ld %ld %ld %ld %ld\n", a,b,c,d,e,f,g);
- r += 100 * (a + 10*b + 100*c + 1000*d +
- 10000*e + 100000*f + 1000000*g);
- return r;
- }
- RPY_EXPORTED
- long test_call_release_gil_readsaved_lasterror(void) {
- return (long)&f1;
- }
- '''])
- fn_name = 'test_call_release_gil_readsaved_lasterror'
- getter_ptr = rffi.llexternal(fn_name, [], lltype.Signed,
- compilation_info=eci, _nowrapper=True)
- func1_adr = getter_ptr()
- calldescr = self.cpu._calldescr_dynamic_for_tests([types.slong]*7,
- types.slong)
- #
- for saveerr in [rffi.RFFI_READSAVED_LASTERROR,
- rffi.RFFI_READSAVED_LASTERROR | rffi.RFFI_ALT_ERRNO,
- ]:
- faildescr = BasicFailDescr(1)
- inputargs = [InputArgInt() for i in range(7)]
- ops = [
- ResOperation(rop.CALL_RELEASE_GIL_I,
- [ConstInt(saveerr), ConstInt(func1_adr)]
- + inputargs,
- descr=calldescr),
- ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr),
- ]
- i1 = ops[-2]
- ops += [ResOperation(rop.FINISH, [i1], descr=BasicFinalDescr(0))]
- ops[-2].setfailargs([])
- looptoken = JitCellToken()
- self.cpu.compile_loop(inputargs, ops, looptoken)
- #
- llerrno.set_debug_saved_lasterror(self.cpu, 24)
- llerrno.set_debug_saved_altlasterror(self.cpu, 25)
- deadframe = self.cpu.execute_token(looptoken, 9, 8, 7, 6, 5, 4, 3)
- result = self.cpu.get_int_value(deadframe, 0)
- assert llerrno.get_debug_saved_lasterror(self.cpu) == 24
- assert llerrno.get_debug_saved_altlasterror(self.cpu) == 25
- #
- if saveerr & rffi.RFFI_ALT_ERRNO:
- expected_lasterror = 25
- else:
- expected_lasterror = 24
- assert result == expected_lasterror + 345678900
- def test_call_release_gil_err_all(self):
- from rpython.translator.tool.cbuild import ExternalCompilationInfo
- from rpython.rlib.libffi import types
- from rpython.jit.backend.llsupport import llerrno
- #
- if not isinstance(self.cpu, AbstractLLCPU):
- py.test.skip("not on LLGraph")
- if sys.platform != 'win32':
- eci = ExternalCompilationInfo(
- separate_module_sources=[r'''
- #include <errno.h>
- static long f1(long a, long b, long c, long d,
- long e, long f, long g) {
- long r = errno;
- errno = 42;
- r += 100 * (a + 10*b + 100*c + 1000*d +
- 10000*e + 100000*f + 1000000*g);
- return r;
- }
- RPY_EXPORTED
- long test_call_release_gil_err_all(void) {
- return (long)&f1;
- }
- '''])
- else:
- eci = ExternalCompilationInfo(
- separate_module_sources=[r'''
- #include <windows.h>
- #include <errno.h>
- static long f1(long a, long b, long c, long d,
- long e, long f, long g) {
- long r = errno + 10 * GetLastError();
- errno = 42;
- SetLastError(43);
- r += 100 * (a + 10*b + 100*c + 1000*d +
- 10000*e + 100000*f + 1000000*g);
- return r;
- }
- RPY_EXPORTED
- long test_call_release_gil_err_all(void) {
- return (long)&f1;
- }
- '''])
- fn_name = 'test_call_release_gil_err_all'
- getter_ptr = rffi.llexternal(fn_name, [], lltype.Signed,
- compilation_info=eci, _nowrapper=True)
- func1_adr = getter_ptr()
- calldescr = self.cpu._calldescr_dynamic_for_tests([types.slong]*7,
- types.slong)
- #
- for saveerr in [rffi.RFFI_ERR_ALL,
- rffi.RFFI_ERR_ALL | rffi.RFFI_ALT_ERRNO,
- ]:
- faildescr = BasicFailDescr(1)
- inputargs = [InputArgInt() for i in range(7)]
- op0 = ResOperation(rop.CALL_RELEASE_GIL_I,
- [ConstInt(saveerr), ConstInt(func1_adr)]
- + inputargs,
- descr=calldescr)
- ops = [
- op0,
- ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr),
- ResOperation(rop.FINISH, [op0], descr=BasicFinalDescr(0))
- ]
- ops[-2].setfailargs([])
- looptoken = JitCellToken()
- self.cpu.compile_loop(inputargs, ops, looptoken)
- #
- llerrno.set_debug_saved_errno(self.cpu, 8)
- llerrno.set_debug_saved_alterrno(self.cpu, 5)
- llerrno.set_debug_saved_lasterror(self.cpu, 9)
- llerrno.set_debug_saved_altlasterror(self.cpu, 4)
- deadframe = self.cpu.execute_token(looptoken, 1, 2, 3, 4, 5, 6, 7)
- result = self.cpu.get_int_value(deadframe, 0)
- got_errno = llerrno.get_debug_saved_errno(self.cpu)
- got_alter = llerrno.get_debug_saved_alterrno(self.cpu)
- if saveerr & rffi.RFFI_ALT_ERRNO:
- assert (got_errno, got_alter) == (8, 42)
- else:
- assert (got_errno, got_alter) == (42, 5)
- if sys.platform != 'win32':
- if saveerr & rffi.RFFI_ALT_ERRNO:
- assert result == 765432105
- else:
- assert result == 765432108
- else:
- if saveerr & rffi.RFFI_ALT_ERRNO:
- assert result == 765432145
- else:
- assert result == 765432198
- got_lasterror = llerrno.get_debug_saved_lasterror(self.cpu)
- got_altlaster = llerrno.get_debug_saved_altlasterror(self.cpu)
- if saveerr & rffi.RFFI_ALT_ERRNO:
- assert (got_lasterror, got_altlaster) == (9, 43)
- else:
- assert (got_lasterror, got_altlaster) == (43, 4)
- def test_guard_not_invalidated(self):
- cpu = self.cpu
- faildescr = BasicFailDescr(1)
- finaldescr = BasicFinalDescr(0)
- loop = parse("""
- [i0, i1]
- guard_not_invalidated(descr=faildescr) [i1]
- finish(i0, descr=finaldescr)
- """, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, -42, 9)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 0
- assert self.cpu.get_int_value(deadframe, 0) == -42
- print 'step 1 ok'
- print '-'*79
- # mark as failing
- self.cpu.invalidate_loop(looptoken)
- deadframe = self.cpu.execute_token(looptoken, -42, 9)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail is faildescr
- assert self.cpu.get_int_value(deadframe, 0) == 9
- print 'step 2 ok'
- print '-'*79
- # attach a bridge
- faildescr2 = BasicFailDescr(2)
- finaldescr2 = BasicFinalDescr(3)
- bridge = parse("""
- [i2]
- guard_not_invalidated(descr=faildescr2) []
- finish(i2, descr=finaldescr2)
- """, namespace=locals())
- self.cpu.compile_bridge(faildescr, bridge.inputargs,
- bridge.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, -42, 9)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 3
- assert self.cpu.get_int_value(deadframe, 0) == 9
- print 'step 3 ok'
- print '-'*79
- # mark as failing again
- self.cpu.invalidate_loop(looptoken)
- deadframe = self.cpu.execute_token(looptoken, -42, 9)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail is faildescr2
- print 'step 4 ok'
- print '-'*79
- def test_guard_not_invalidated_and_label(self):
- # test that the guard_not_invalidated reserves enough room before
- # the label. If it doesn't, then in this example after we invalidate
- # the guard, jumping to the label will hit the invalidation code too
- cpu = self.cpu
- faildescr = BasicFailDescr(1)
- labeldescr = TargetToken()
- finaldescr = BasicFinalDescr(3)
- loop = parse("""
- [i0]
- guard_not_invalidated(descr=faildescr) []
- label(i0, descr=labeldescr)
- finish(i0, descr=finaldescr)
- """, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- # mark as failing
- self.cpu.invalidate_loop(looptoken)
- # attach a bridge
- i2 = InputArgInt()
- ops2 = [
- ResOperation(rop.JUMP, [ConstInt(333)], descr=labeldescr),
- ]
- self.cpu.compile_bridge(faildescr, [], ops2, looptoken)
- # run: must not be caught in an infinite loop
- deadframe = self.cpu.execute_token(looptoken, 16)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 3
- assert self.cpu.get_int_value(deadframe, 0) == 333
- # pure do_ / descr features
- def test_do_operations(self):
- cpu = self.cpu
- #
- A = lltype.GcArray(lltype.Char)
- descr_A = cpu.arraydescrof(A)
- a = lltype.malloc(A, 5)
- x = cpu.bh_arraylen_gc(lltype.cast_opaque_ptr(llmemory.GCREF, a),
- descr_A)
- assert x == 5
- #
- a[2] = 'Y'
- x = cpu.bh_getarrayitem_gc_i(
- lltype.cast_opaque_ptr(llmemory.GCREF, a), 2, descr_A)
- assert x == ord('Y')
- #
- B = lltype.GcArray(lltype.Ptr(A))
- descr_B = cpu.arraydescrof(B)
- b = lltype.malloc(B, 4)
- b[3] = a
- x = cpu.bh_getarrayitem_gc_r(
- lltype.cast_opaque_ptr(llmemory.GCREF, b), 3, descr_B)
- assert lltype.cast_opaque_ptr(lltype.Ptr(A), x) == a
- if self.cpu.supports_floats:
- C = lltype.GcArray(lltype.Float)
- c = lltype.malloc(C, 6)
- c[3] = 3.5
- descr_C = cpu.arraydescrof(C)
- x = cpu.bh_getarrayitem_gc_f(
- lltype.cast_opaque_ptr(llmemory.GCREF, c), 3, descr_C)
- assert longlong.getrealfloat(x) == 3.5
- cpu.bh_setarrayitem_gc_f(
- lltype.cast_opaque_ptr(llmemory.GCREF, c), 4,
- longlong.getfloatstorage(4.5), descr_C)
- assert c[4] == 4.5
- s = rstr.mallocstr(6)
- x = cpu.bh_strlen(lltype.cast_opaque_ptr(llmemory.GCREF, s))
- assert x == 6
- #
- s.chars[3] = 'X'
- x = cpu.bh_strgetitem(lltype.cast_opaque_ptr(llmemory.GCREF, s), 3)
- assert x == ord('X')
- #
- S = lltype.GcStruct('S', ('x', lltype.Char), ('y', lltype.Ptr(A)),
- ('z', lltype.Float))
- descrfld_x = cpu.fielddescrof(S, 'x')
- s = lltype.malloc(S)
- s.x = 'Z'
- x = cpu.bh_getfield_gc_i(lltype.cast_opaque_ptr(llmemory.GCREF, s),
- descrfld_x)
- assert x == ord('Z')
- #
- cpu.bh_setfield_gc_i(lltype.cast_opaque_ptr(llmemory.GCREF, s),
- ord('4'), descrfld_x)
- assert s.x == '4'
- #
- descrfld_y = cpu.fielddescrof(S, 'y')
- s.y = a
- x = cpu.bh_getfield_gc_r(lltype.cast_opaque_ptr(llmemory.GCREF, s),
- descrfld_y)
- assert lltype.cast_opaque_ptr(lltype.Ptr(A), x) == a
- #
- s.y = lltype.nullptr(A)
- cpu.bh_setfield_gc_r(lltype.cast_opaque_ptr(llmemory.GCREF, s),
- x, descrfld_y)
- assert s.y == a
- #
- RS = lltype.Struct('S', ('x', lltype.Char)) #, ('y', lltype.Ptr(A)))
- descrfld_rx = cpu.fielddescrof(RS, 'x')
- rs = lltype.malloc(RS, immortal=True)
- rs.x = '?'
- x = cpu.bh_getfield_raw_i(
- heaptracker.adr2int(llmemory.cast_ptr_to_adr(rs)),
- descrfld_rx)
- assert x == ord('?')
- #
- cpu.bh_setfield_raw_i(
- heaptracker.adr2int(llmemory.cast_ptr_to_adr(rs)),
- ord('!'), descrfld_rx)
- assert rs.x == '!'
- #
- if self.cpu.supports_floats:
- descrfld_z = cpu.fielddescrof(S, 'z')
- cpu.bh_setfield_gc_f(
- lltype.cast_opaque_ptr(llmemory.GCREF, s),
- longlong.getfloatstorage(3.5), descrfld_z)
- assert s.z == 3.5
- s.z = 3.2
- x = cpu.bh_getfield_gc_f(
- lltype.cast_opaque_ptr(llmemory.GCREF, s),
- descrfld_z)
- assert longlong.getrealfloat(x) == 3.2
- ### we don't support in the JIT for now GC pointers
- ### stored inside non-GC structs.
- #descrfld_ry = cpu.fielddescrof(RS, 'y')
- #rs.y = a
- #x = cpu.do_getfield_raw(
- # InputArgInt(cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(rs))),
- # descrfld_ry)
- #assert isinstance(x, BoxPtr)
- #assert x.getref(lltype.Ptr(A)) == a
- #
- #rs.y = lltype.nullptr(A)
- #cpu.do_setfield_raw(
- # InputArgInt(cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(rs))), x,
- # descrfld_ry)
- #assert rs.y == a
- #
- descrsize = cpu.sizeof(S)
- x = cpu.bh_new(descrsize)
- lltype.cast_opaque_ptr(lltype.Ptr(S), x) # type check
- #
- X = lltype.GcStruct('X', ('parent', rclass.OBJECT))
- _, T, descrsize2 = self.alloc_instance(X)
- x = cpu.bh_new_with_vtable(descrsize2)
- lltype.cast_opaque_ptr(lltype.Ptr(rclass.OBJECT), x) # type check
- # well...
- #assert x.getref(rclass.OBJECTPTR).typeptr == vtable2
- #
- arraydescr = cpu.arraydescrof(A)
- x = cpu.bh_new_array(7, arraydescr)
- array = lltype.cast_opaque_ptr(lltype.Ptr(A), x)
- assert len(array) == 7
- #
- cpu.bh_setarrayitem_gc_i(x, 5, ord('*'), descr_A)
- assert array[5] == '*'
- #
- cpu.bh_setarrayitem_gc_r(
- lltype.cast_opaque_ptr(llmemory.GCREF, b), 1, x, descr_B)
- assert b[1] == array
- #
- x = cpu.bh_newstr(5)
- str = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), x)
- assert len(str.chars) == 5
- #
- cpu.bh_strsetitem(x, 4, ord('/'))
- assert str.chars[4] == '/'
- def test_sorting_of_fields(self):
- S = lltype.GcStruct('S', ('parent', rclass.OBJECT),
- ('value', lltype.Signed),
- ('chr1', lltype.Char),
- ('chr2', lltype.Char))
- self.alloc_instance(S)
- chr1 = self.cpu.fielddescrof(S, 'chr1').sort_key()
- value = self.cpu.fielddescrof(S, 'value').sort_key()
- chr2 = self.cpu.fielddescrof(S, 'chr2').sort_key()
- assert len(set([value, chr1, chr2])) == 3
- def test_guards_nongc(self):
- x = lltype.malloc(lltype.Struct('x'), flavor='raw')
- v = heaptracker.adr2int(llmemory.cast_ptr_to_adr(x))
- vbox = InputArgInt(v)
- ops = [
- (rop.GUARD_NONNULL, vbox, False),
- (rop.GUARD_ISNULL, vbox, True),
- (rop.GUARD_NONNULL, InputArgInt(0), True),
- (rop.GUARD_ISNULL, InputArgInt(0), False),
- ]
- for opname, arg, res in ops:
- self.execute_operation(opname, [arg], 'void')
- assert self.guard_failed == res
- lltype.free(x, flavor='raw')
- def test_assembler_call(self):
- called = []
- def assembler_helper(deadframe, virtualizable):
- assert self.cpu.get_int_value(deadframe, 0) == 97
- called.append(self.cpu.get_latest_descr(deadframe))
- return 4 + 9
- FUNCPTR = lltype.Ptr(lltype.FuncType([llmemory.GCREF,
- llmemory.GCREF],
- lltype.Signed))
- class FakeJitDriverSD:
- index_of_virtualizable = -1
- _assembler_helper_ptr = llhelper(FUNCPTR, assembler_helper)
- assembler_helper_adr = llmemory.cast_ptr_to_adr(
- _assembler_helper_ptr)
- ops = '''
- [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9]
- i10 = int_add(i0, i1)
- i11 = int_add(i10, i2)
- i12 = int_add(i11, i3)
- i13 = int_add(i12, i4)
- i14 = int_add(i13, i5)
- i15 = int_add(i14, i6)
- i16 = int_add(i15, i7)
- i17 = int_add(i16, i8)
- i18 = int_add(i17, i9)
- finish(i18)'''
- loop = parse(ops)
- looptoken = JitCellToken()
- looptoken.outermost_jitdriver_sd = FakeJitDriverSD()
- finish_descr = loop.operations[-1].getdescr()
- self.cpu.done_with_this_frame_descr_int = BasicFinalDescr()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- ARGS = [lltype.Signed] * 10
- RES = lltype.Signed
- FakeJitDriverSD.portal_calldescr = self.cpu.calldescrof(
- lltype.Ptr(lltype.FuncType(ARGS, RES)), ARGS, RES,
- EffectInfo.MOST_GENERAL)
- args = [i+1 for i in range(10)]
- deadframe = self.cpu.execute_token(looptoken, *args)
- assert self.cpu.get_int_value(deadframe, 0) == 55
- ops = '''
- [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9]
- i10 = int_add(i0, 42)
- i11 = call_assembler_i(i10, i1, i2, i3, i4, i5, i6, i7, i8, i9, descr=looptoken)
- # NOTE: call_assembler_i() is turned into a single-argument version
- # by rewrite.py
- guard_not_forced()[]
- finish(i11)
- '''
- loop = parse(ops, namespace=locals())
- othertoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, othertoken)
- args = [i+1 for i in range(10)]
- deadframe = self.cpu.execute_token(othertoken, *args)
- assert self.cpu.get_int_value(deadframe, 0) == 13
- assert called == [finish_descr]
- # test the fast path, which should not call assembler_helper()
- del called[:]
- self.cpu.done_with_this_frame_descr_int = finish_descr
- othertoken = JitCellToken()
- loop = parse(ops, namespace=locals())
- self.cpu.compile_loop(loop.inputargs, loop.operations, othertoken)
- args = [i+1 for i in range(10)]
- deadframe = self.cpu.execute_token(othertoken, *args)
- assert self.cpu.get_int_value(deadframe, 0) == 97
- assert not called
- def test_assembler_call_propagate_exc(self):
- # WARNING: this test depends on test_memoryerror first passing
- if not isinstance(self.cpu, AbstractLLCPU):
- py.test.skip("llgraph can't fake exceptions well enough, give up")
- excdescr = BasicFailDescr(666)
- self.cpu.propagate_exception_descr = excdescr
- self.cpu.setup_once() # xxx redo it, because we added
- # propagate_exception
- def assembler_helper(deadframe, virtualizable):
- assert self.cpu.get_latest_descr(deadframe) is excdescr
- # let's assume we handled that
- return 3
- FUNCPTR = lltype.Ptr(lltype.FuncType([llmemory.GCREF,
- llmemory.GCREF],
- lltype.Signed))
- class FakeJitDriverSD:
- index_of_virtualizable = -1
- _assembler_helper_ptr = llhelper(FUNCPTR, assembler_helper)
- assembler_helper_adr = llmemory.cast_ptr_to_adr(
- _assembler_helper_ptr)
- ops = '''
- [i0]
- p0 = newunicode(i0)
- finish(p0)'''
- loop = parse(ops)
- looptoken = JitCellToken()
- looptoken.outermost_jitdriver_sd = FakeJitDriverSD()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- ARGS = [lltype.Signed] * 10
- RES = lltype.Signed
- FakeJitDriverSD.portal_calldescr = self.cpu.calldescrof(
- lltype.Ptr(lltype.FuncType(ARGS, RES)), ARGS, RES,
- EffectInfo.MOST_GENERAL)
- ops = '''
- [i0]
- i11 = call_assembler_i(i0, descr=looptoken)
- guard_not_forced()[]
- finish(i11)
- '''
- loop = parse(ops, namespace=locals())
- othertoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, othertoken)
- deadframe = self.cpu.execute_token(othertoken, sys.maxint - 1)
- assert self.cpu.get_int_value(deadframe, 0) == 3
- def test_assembler_call_float(self):
- if not self.cpu.supports_floats:
- py.test.skip("requires floats")
- called = []
- def assembler_helper(deadframe, virtualizable):
- x = self.cpu.get_float_value(deadframe, 0)
- assert longlong.getrealfloat(x) == 1.2 + 3.2
- called.append(self.cpu.get_latest_descr(deadframe))
- print '!' * 30 + 'assembler_helper'
- return 13.5
- FUNCPTR = lltype.Ptr(lltype.FuncType([llmemory.GCREF,
- llmemory.GCREF],
- lltype.Float))
- class FakeJitDriverSD:
- index_of_virtualizable = -1
- _assembler_helper_ptr = llhelper(FUNCPTR, assembler_helper)
- assembler_helper_adr = llmemory.cast_ptr_to_adr(
- _assembler_helper_ptr)
- ARGS = [lltype.Float, lltype.Float]
- RES = lltype.Float
- FakeJitDriverSD.portal_calldescr = self.cpu.calldescrof(
- lltype.Ptr(lltype.FuncType(ARGS, RES)), ARGS, RES,
- EffectInfo.MOST_GENERAL)
- ops = '''
- [f0, f1]
- f2 = float_add(f0, f1)
- finish(f2)'''
- loop = parse(ops)
- finish_descr = loop.operations[-1].getdescr()
- looptoken = JitCellToken()
- looptoken.outermost_jitdriver_sd = FakeJitDriverSD()
- self.cpu.done_with_this_frame_descr_float = BasicFinalDescr()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- args = [longlong.getfloatstorage(1.2),
- longlong.getfloatstorage(2.3)]
- deadframe = self.cpu.execute_token(looptoken, *args)
- x = self.cpu.get_float_value(deadframe, 0)
- assert longlong.getrealfloat(x) == 1.2 + 2.3
- ops = '''
- [f4, f5]
- f3 = call_assembler_f(f4, f5, descr=looptoken)
- guard_not_forced()[]
- finish(f3)
- '''
- loop = parse(ops, namespace=locals())
- othertoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, othertoken)
- args = [longlong.getfloatstorage(1.2),
- longlong.getfloatstorage(3.2)]
- deadframe = self.cpu.execute_token(othertoken, *args)
- x = self.cpu.get_float_value(deadframe, 0)
- assert longlong.getrealfloat(x) == 13.5
- assert called == [finish_descr]
- # test the fast path, which should not call assembler_helper()
- del called[:]
- self.cpu.done_with_this_frame_descr_float = finish_descr
- othertoken = JitCellToken()
- loop = parse(ops, namespace=locals())
- self.cpu.compile_loop(loop.inputargs, loop.operations, othertoken)
- args = [longlong.getfloatstorage(1.2),
- longlong.getfloatstorage(4.2)]
- deadframe = self.cpu.execute_token(othertoken, *args)
- x = self.cpu.get_float_value(deadframe, 0)
- assert longlong.getrealfloat(x) == 1.2 + 4.2
- assert not called
- def test_raw_malloced_getarrayitem(self):
- ARRAY = rffi.CArray(lltype.Signed)
- descr = self.cpu.arraydescrof(ARRAY)
- a = lltype.malloc(ARRAY, 10, flavor='raw')
- a[7] = -4242
- addr = llmemory.cast_ptr_to_adr(a)
- abox = InputArgInt(heaptracker.adr2int(addr))
- r1 = self.execute_operation(rop.GETARRAYITEM_RAW_I, [abox, InputArgInt(7)],
- 'int', descr=descr)
- assert r1 == -4242
- lltype.free(a, flavor='raw')
- def test_raw_malloced_setarrayitem(self):
- ARRAY = rffi.CArray(lltype.Signed)
- descr = self.cpu.arraydescrof(ARRAY)
- a = lltype.malloc(ARRAY, 10, flavor='raw')
- addr = llmemory.cast_ptr_to_adr(a)
- abox = InputArgInt(heaptracker.adr2int(addr))
- self.execute_operation(rop.SETARRAYITEM_RAW, [abox, InputArgInt(5),
- InputArgInt(12345)],
- 'void', descr=descr)
- assert a[5] == 12345
- lltype.free(a, flavor='raw')
- def test_redirect_call_assembler(self):
- if not self.cpu.supports_floats:
- py.test.skip("requires floats")
- called = []
- def assembler_helper(deadframe, virtualizable):
- x = self.cpu.get_float_value(deadframe, 0)
- assert longlong.getrealfloat(x) == 1.25 + 3.25
- called.append(self.cpu.get_latest_descr(deadframe))
- return 13.5
- FUNCPTR = lltype.Ptr(lltype.FuncType([llmemory.GCREF, llmemory.GCREF],
- lltype.Float))
- class FakeJitDriverSD:
- index_of_virtualizable = -1
- _assembler_helper_ptr = llhelper(FUNCPTR, assembler_helper)
- assembler_helper_adr = llmemory.cast_ptr_to_adr(
- _assembler_helper_ptr)
- ARGS = [lltype.Float, lltype.Float]
- RES = lltype.Float
- FakeJitDriverSD.portal_calldescr = self.cpu.calldescrof(
- lltype.Ptr(lltype.FuncType(ARGS, RES)), ARGS, RES,
- EffectInfo.MOST_GENERAL)
- ops = '''
- [f0, f1]
- f2 = float_add(f0, f1)
- finish(f2)'''
- loop = parse(ops)
- looptoken = JitCellToken()
- looptoken.outermost_jitdriver_sd = FakeJitDriverSD()
- self.cpu.done_with_this_frame_descr_float = BasicFinalDescr()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- finish_descr = loop.operations[-1].getdescr()
- args = [longlong.getfloatstorage(1.25),
- longlong.getfloatstorage(2.35)]
- deadframe = self.cpu.execute_token(looptoken, *args)
- x = self.cpu.get_float_value(deadframe, 0)
- assert longlong.getrealfloat(x) == 1.25 + 2.35
- assert not called
- ops = '''
- [f4, f5]
- f3 = call_assembler_f(f4, f5, descr=looptoken)
- guard_not_forced()[]
- finish(f3)
- '''
- loop = parse(ops, namespace=locals())
- othertoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, othertoken)
- # normal call_assembler: goes to looptoken
- args = [longlong.getfloatstorage(1.25),
- longlong.getfloatstorage(3.25)]
- deadframe = self.cpu.execute_token(othertoken, *args)
- x = self.cpu.get_float_value(deadframe, 0)
- assert longlong.getrealfloat(x) == 13.5
- assert called == [finish_descr]
- del called[:]
- # compile a replacement which needs more jitframe stack space
- ops = '''
- [f0, f1]
- f2 = float_sub(f0, f1)
- f3 = float_sub(f0, f1)
- f4 = float_sub(f0, f1)
- f5 = float_sub(f0, f1)
- f6 = float_sub(f0, f1)
- f7 = float_sub(f0, f1)
- f8 = float_sub(f0, f1)
- f9 = float_sub(f0, f1)
- f10 = float_sub(f0, f1)
- f11 = float_sub(f0, f1)
- f12 = float_sub(f0, f1)
- f13 = float_sub(f0, f1)
- f14 = float_sub(f0, f1)
- f15 = float_sub(f0, f1)
- f16 = float_sub(f0, f1)
- f17 = float_sub(f0, f1)
- f18 = float_sub(f0, f1)
- f19 = float_sub(f0, f1)
- i3 = float_eq(f2, f3)
- i4 = float_eq(f2, f4)
- i5 = float_eq(f2, f5)
- i6 = float_eq(f2, f6)
- i7 = float_eq(f2, f7)
- i8 = float_eq(f2, f8)
- i9 = float_eq(f2, f9)
- i10 = float_eq(f2, f10)
- i11 = float_eq(f2, f11)
- i12 = float_eq(f2, f12)
- i13 = float_eq(f2, f13)
- i14 = float_eq(f2, f14)
- i15 = float_eq(f2, f15)
- i16 = float_eq(f2, f16)
- i17 = float_eq(f2, f17)
- i18 = float_eq(f2, f18)
- i19 = float_eq(f2, f19)
- guard_true(i3) []
- guard_true(i4) []
- guard_true(i5) []
- guard_true(i6) []
- guard_true(i7) []
- guard_true(i8) []
- guard_true(i9) []
- guard_true(i10) []
- guard_true(i11) []
- guard_true(i12) []
- guard_true(i13) []
- guard_true(i14) []
- guard_true(i15) []
- guard_true(i16) []
- guard_true(i17) []
- guard_true(i18) []
- guard_true(i19) []
- finish(f2)'''
- loop2 = parse(ops)
- looptoken2 = JitCellToken()
- looptoken2.outermost_jitdriver_sd = FakeJitDriverSD()
- self.cpu.compile_loop(loop2.inputargs, loop2.operations, looptoken2)
- finish_descr2 = loop2.operations[-1].getdescr()
- # check the jitframeinfo
- if isinstance(self.cpu, AbstractLLCPU):
- num1 = looptoken.compiled_loop_token.frame_info.jfi_frame_depth
- num2 = looptoken2.compiled_loop_token.frame_info.jfi_frame_depth
- assert num1 < num2
- # install it
- self.cpu.redirect_call_assembler(looptoken, looptoken2)
- # check that the jitframeinfo was updated
- if isinstance(self.cpu, AbstractLLCPU):
- num1 = looptoken.compiled_loop_token.frame_info.jfi_frame_depth
- num2 = looptoken2.compiled_loop_token.frame_info.jfi_frame_depth
- assert num1 == num2
- # now, our call_assembler should go to looptoken2
- args = [longlong.getfloatstorage(6.0),
- longlong.getfloatstorage(1.5)] # 6.0-1.5 == 1.25+3.25
- deadframe = self.cpu.execute_token(othertoken, *args)
- x = self.cpu.get_float_value(deadframe, 0)
- assert longlong.getrealfloat(x) == 13.5
- assert called == [finish_descr2]
- del called[:]
- # compile a second replacement
- ops = '''
- [f0, f1]
- f2 = float_mul(f0, f1)
- finish(f2)'''
- loop3 = parse(ops)
- looptoken3 = JitCellToken()
- looptoken3.outermost_jitdriver_sd = FakeJitDriverSD()
- self.cpu.compile_loop(loop3.inputargs, loop3.operations, looptoken3)
- finish_descr3 = loop3.operations[-1].getdescr()
- # install it
- self.cpu.redirect_call_assembler(looptoken2, looptoken3)
- # now, our call_assembler should go to looptoken3
- args = [longlong.getfloatstorage(0.5),
- longlong.getfloatstorage(9.0)] # 0.5*9.0 == 1.25+3.25
- deadframe = self.cpu.execute_token(othertoken, *args)
- x = self.cpu.get_float_value(deadframe, 0)
- assert longlong.getrealfloat(x) == 13.5
- assert called == [finish_descr3]
- del called[:]
- def test_short_result_of_getfield_direct(self):
- # Test that a getfield that returns a CHAR, SHORT or INT, signed
- # or unsigned, properly gets zero-extended or sign-extended.
- # Direct bh_xxx test.
- cpu = self.cpu
- for RESTYPE in [rffi.SIGNEDCHAR, rffi.UCHAR,
- rffi.SHORT, rffi.USHORT,
- rffi.INT, rffi.UINT,
- rffi.LONG, rffi.ULONG]:
- S = lltype.GcStruct('S', ('x', RESTYPE))
- descrfld_x = cpu.fielddescrof(S, 'x')
- s = lltype.malloc(S)
- value = intmask(0xFFEEDDCCBBAA9988)
- expected = rffi.cast(lltype.Signed, rffi.cast(RESTYPE, value))
- s.x = rffi.cast(RESTYPE, value)
- x = cpu.bh_getfield_gc_i(lltype.cast_opaque_ptr(llmemory.GCREF, s),
- descrfld_x)
- assert x == expected, (
- "%r: got %r, expected %r" % (RESTYPE, x, expected))
- def test_short_result_of_getfield_compiled(self):
- # Test that a getfield that returns a CHAR, SHORT or INT, signed
- # or unsigned, properly gets zero-extended or sign-extended.
- # Machine code compilation test.
- cpu = self.cpu
- for RESTYPE in [rffi.SIGNEDCHAR, rffi.UCHAR,
- rffi.SHORT, rffi.USHORT,
- rffi.INT, rffi.UINT,
- rffi.LONG, rffi.ULONG]:
- S = lltype.GcStruct('S', ('x', RESTYPE))
- descrfld_x = cpu.fielddescrof(S, 'x')
- s = lltype.malloc(S)
- value = intmask(0xFFEEDDCCBBAA9988)
- expected = rffi.cast(lltype.Signed, rffi.cast(RESTYPE, value))
- s.x = rffi.cast(RESTYPE, value)
- s_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, s)
- res = self.execute_operation(rop.GETFIELD_GC_I,
- [InputArgRef(s_gcref)],
- 'int', descr=descrfld_x)
- assert res == expected, (
- "%r: got %r, expected %r" % (RESTYPE, res, expected))
- def test_short_result_of_getarrayitem_direct(self):
- # Test that a getarrayitem that returns a CHAR, SHORT or INT, signed
- # or unsigned, properly gets zero-extended or sign-extended.
- # Direct bh_xxx test.
- cpu = self.cpu
- for RESTYPE in [rffi.SIGNEDCHAR, rffi.UCHAR,
- rffi.SHORT, rffi.USHORT,
- rffi.INT, rffi.UINT,
- rffi.LONG, rffi.ULONG]:
- A = lltype.GcArray(RESTYPE)
- descrarray = cpu.arraydescrof(A)
- a = lltype.malloc(A, 5)
- value = intmask(0xFFEEDDCCBBAA9988)
- expected = rffi.cast(lltype.Signed, rffi.cast(RESTYPE, value))
- a[3] = rffi.cast(RESTYPE, value)
- x = cpu.bh_getarrayitem_gc_i(
- lltype.cast_opaque_ptr(llmemory.GCREF, a), 3, descrarray)
- assert x == expected, (
- "%r: got %r, expected %r" % (RESTYPE, x, expected))
- def test_short_result_of_getarrayitem_compiled(self):
- # Test that a getarrayitem that returns a CHAR, SHORT or INT, signed
- # or unsigned, properly gets zero-extended or sign-extended.
- # Machine code compilation test.
- cpu = self.cpu
- for RESTYPE in [rffi.SIGNEDCHAR, rffi.UCHAR,
- rffi.SHORT, rffi.USHORT,
- rffi.INT, rffi.UINT,
- rffi.LONG, rffi.ULONG]:
- A = lltype.GcArray(RESTYPE)
- descrarray = cpu.arraydescrof(A)
- a = lltype.malloc(A, 5)
- value = intmask(0xFFEEDDCCBBAA9988)
- expected = rffi.cast(lltype.Signed, rffi.cast(RESTYPE, value))
- a[3] = rffi.cast(RESTYPE, value)
- a_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, a)
- res = self.execute_operation(rop.GETARRAYITEM_GC_I,
- [InputArgRef(a_gcref), InputArgInt(3)],
- 'int', descr=descrarray)
- assert res == expected, (
- "%r: got %r, expected %r" % (RESTYPE, res, expected))
- def test_short_result_of_getarrayitem_raw_direct(self):
- # Test that a getarrayitem that returns a CHAR, SHORT or INT, signed
- # or unsigned, properly gets zero-extended or sign-extended.
- # Direct bh_xxx test.
- cpu = self.cpu
- for RESTYPE in [rffi.SIGNEDCHAR, rffi.UCHAR,
- rffi.SHORT, rffi.USHORT,
- rffi.INT, rffi.UINT,
- rffi.LONG, rffi.ULONG]:
- A = rffi.CArray(RESTYPE)
- descrarray = cpu.arraydescrof(A)
- a = lltype.malloc(A, 5, flavor='raw')
- value = intmask(0xFFEEDDCCBBAA9988)
- expected = rffi.cast(lltype.Signed, rffi.cast(RESTYPE, value))
- a[3] = rffi.cast(RESTYPE, value)
- a_rawint = heaptracker.adr2int(llmemory.cast_ptr_to_adr(a))
- x = cpu.bh_getarrayitem_raw_i(a_rawint, 3, descrarray)
- assert x == expected, (
- "%r: got %r, expected %r" % (RESTYPE, x, expected))
- lltype.free(a, flavor='raw')
- def test_short_result_of_getarrayitem_raw_compiled(self):
- # Test that a getarrayitem that returns a CHAR, SHORT or INT, signed
- # or unsigned, properly gets zero-extended or sign-extended.
- # Machine code compilation test.
- cpu = self.cpu
- for RESTYPE in [rffi.SIGNEDCHAR, rffi.UCHAR,
- rffi.SHORT, rffi.USHORT,
- rffi.INT, rffi.UINT,
- rffi.LONG, rffi.ULONG]:
- A = rffi.CArray(RESTYPE)
- descrarray = cpu.arraydescrof(A)
- a = lltype.malloc(A, 5, flavor='raw')
- value = intmask(0xFFEEDDCCBBAA9988)
- expected = rffi.cast(lltype.Signed, rffi.cast(RESTYPE, value))
- a[3] = rffi.cast(RESTYPE, value)
- a_rawint = heaptracker.adr2int(llmemory.cast_ptr_to_adr(a))
- res = self.execute_operation(rop.GETARRAYITEM_RAW_I,
- [InputArgInt(a_rawint), InputArgInt(3)],
- 'int', descr=descrarray)
- assert res == expected, (
- "%r: got %r, expected %r" % (RESTYPE, res, expected))
- lltype.free(a, flavor='raw')
- def test_short_result_of_call_direct(self):
- # Test that calling a function that returns a CHAR, SHORT or INT,
- # signed or unsigned, properly gets zero-extended or sign-extended.
- from rpython.translator.tool.cbuild import ExternalCompilationInfo
- for RESTYPE in [rffi.SIGNEDCHAR, rffi.UCHAR,
- rffi.SHORT, rffi.USHORT,
- rffi.INT, rffi.UINT,
- rffi.LONG, rffi.ULONG]:
- # Tested with a function that intentionally does not cast the
- # result to RESTYPE, but makes sure that we return the whole
- # value in eax or rax.
- eci = ExternalCompilationInfo(
- separate_module_sources=["""
- RPY_EXPORTED long fn_test_result_of_call(long x)
- {
- return x + 1;
- }
- """])
- f = rffi.llexternal('fn_test_result_of_call', [lltype.Signed],
- RESTYPE, compilation_info=eci, _nowrapper=True)
- value = intmask(0xFFEEDDCCBBAA9988)
- expected = rffi.cast(lltype.Signed, rffi.cast(RESTYPE, value + 1))
- assert intmask(f(value)) == expected
- #
- FUNC = self.FuncType([lltype.Signed], RESTYPE)
- FPTR = self.Ptr(FUNC)
- calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
- x = self.cpu.bh_call_i(self.get_funcbox(self.cpu, f).value,
- [value], None, None, calldescr)
- assert x == expected, (
- "%r: got %r, expected %r" % (RESTYPE, x, expected))
- def test_short_result_of_call_compiled(self):
- # Test that calling a function that returns a CHAR, SHORT or INT,
- # signed or unsigned, properly gets zero-extended or sign-extended.
- from rpython.translator.tool.cbuild import ExternalCompilationInfo
- for RESTYPE in [rffi.SIGNEDCHAR, rffi.UCHAR,
- rffi.SHORT, rffi.USHORT,
- rffi.INT, rffi.UINT,
- rffi.LONG, rffi.ULONG]:
- # Tested with a function that intentionally does not cast the
- # result to RESTYPE, but makes sure that we return the whole
- # value in eax or rax.
- eci = ExternalCompilationInfo(
- separate_module_sources=["""
- RPY_EXPORTED long fn_test_result_of_call(long x)
- {
- return x + 1;
- }
- """])
- f = rffi.llexternal('fn_test_result_of_call', [lltype.Signed],
- RESTYPE, compilation_info=eci, _nowrapper=True)
- value = intmask(0xFFEEDDCCBBAA9988)
- expected = rffi.cast(lltype.Signed, rffi.cast(RESTYPE, value + 1))
- assert intmask(f(value)) == expected
- #
- FUNC = self.FuncType([lltype.Signed], RESTYPE)
- FPTR = self.Ptr(FUNC)
- calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
- funcbox = self.get_funcbox(self.cpu, f)
- res = self.execute_operation(rop.CALL_I, [funcbox, InputArgInt(value)],
- 'int', descr=calldescr)
- assert res == expected, (
- "%r: got %r, expected %r" % (RESTYPE, res, expected))
- def test_supports_longlong(self):
- if IS_64_BIT:
- assert not self.cpu.supports_longlong, (
- "supports_longlong should be False on 64-bit platforms")
- def test_longlong_result_of_call_direct(self):
- if not self.cpu.supports_longlong:
- py.test.skip("longlong test")
- from rpython.translator.tool.cbuild import ExternalCompilationInfo
- from rpython.rlib.rarithmetic import r_longlong
- eci = ExternalCompilationInfo(
- separate_module_sources=["""
- RPY_EXPORTED long long fn_test_result_of_call(long long x)
- {
- return x - 100000000000000;
- }
- """])
- f = rffi.llexternal('fn_test_result_of_call', [lltype.SignedLongLong],
- lltype.SignedLongLong,
- compilation_info=eci, _nowrapper=True)
- value = r_longlong(0x7ff05af3307a3fff)
- expected = r_longlong(0x7ff000001fffffff)
- assert f(value) == expected
- #
- FUNC = self.FuncType([lltype.SignedLongLong], lltype.SignedLongLong)
- FPTR = self.Ptr(FUNC)
- calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
- x = self.cpu.bh_call_f(self.get_funcbox(self.cpu, f).value,
- None, None, [value], calldescr)
- assert x == expected
- def test_longlong_result_of_call_compiled(self):
- if not self.cpu.supports_longlong:
- py.test.skip("test of longlong result")
- from rpython.translator.tool.cbuild import ExternalCompilationInfo
- from rpython.rlib.rarithmetic import r_longlong
- eci = ExternalCompilationInfo(
- separate_module_sources=["""
- RPY_EXPORTED long long fn_test_result_of_call(long long x)
- {
- return x - 100000000000000;
- }
- """])
- f = rffi.llexternal('fn_test_result_of_call', [lltype.SignedLongLong],
- lltype.SignedLongLong,
- compilation_info=eci, _nowrapper=True)
- value = r_longlong(0x7ff05af3307a3fff)
- expected = r_longlong(0x7ff000001fffffff)
- assert f(value) == expected
- #
- FUNC = self.FuncType([lltype.SignedLongLong], lltype.SignedLongLong)
- FPTR = self.Ptr(FUNC)
- calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
- funcbox = self.get_funcbox(self.cpu, f)
- res = self.execute_operation(rop.CALL_F,
- [funcbox, InputArgFloat(value)],
- 'float', descr=calldescr)
- assert res == expected
- def test_singlefloat_result_of_call_direct(self):
- if not self.cpu.supports_singlefloats:
- py.test.skip("singlefloat test")
- from rpython.translator.tool.cbuild import ExternalCompilationInfo
- from rpython.rlib.rarithmetic import r_singlefloat
- eci = ExternalCompilationInfo(
- separate_module_sources=["""
- RPY_EXPORTED float fn_test_result_of_call(float x)
- {
- return x / 2.0f;
- }
- """])
- f = rffi.llexternal('fn_test_result_of_call', [lltype.SingleFloat],
- lltype.SingleFloat,
- compilation_info=eci, _nowrapper=True)
- value = r_singlefloat(-42.5)
- expected = r_singlefloat(-21.25)
- assert f(value) == expected
- #
- FUNC = self.FuncType([lltype.SingleFloat], lltype.SingleFloat)
- FPTR = self.Ptr(FUNC)
- calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
- ivalue = longlong.singlefloat2int(value)
- iexpected = longlong.singlefloat2int(expected)
- x = self.cpu.bh_call_i(self.get_funcbox(self.cpu, f).value,
- [ivalue], None, None, calldescr)
- assert x == iexpected
- def test_singlefloat_result_of_call_compiled(self):
- if not self.cpu.supports_singlefloats:
- py.test.skip("test of singlefloat result")
- from rpython.translator.tool.cbuild import ExternalCompilationInfo
- from rpython.rlib.rarithmetic import r_singlefloat
- eci = ExternalCompilationInfo(
- separate_module_sources=["""
- RPY_EXPORTED float fn_test_result_of_call(float x)
- {
- return x / 2.0f;
- }
- """])
- f = rffi.llexternal('fn_test_result_of_call', [lltype.SingleFloat],
- lltype.SingleFloat,
- compilation_info=eci, _nowrapper=True)
- value = r_singlefloat(-42.5)
- expected = r_singlefloat(-21.25)
- assert f(value) == expected
- #
- FUNC = self.FuncType([lltype.SingleFloat], lltype.SingleFloat)
- FPTR = self.Ptr(FUNC)
- calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
- funcbox = self.get_funcbox(self.cpu, f)
- ivalue = longlong.singlefloat2int(value)
- iexpected = longlong.singlefloat2int(expected)
- res = self.execute_operation(rop.CALL_I, [funcbox, InputArgInt(ivalue)],
- 'int', descr=calldescr)
- assert res == iexpected
- def test_free_loop_and_bridges(self):
- if not isinstance(self.cpu, AbstractLLCPU):
- py.test.skip("not a subclass of llmodel.AbstractLLCPU")
- if hasattr(self.cpu, 'setup_once'):
- self.cpu.setup_once()
- mem0 = self.cpu.asmmemmgr.total_mallocs
- looptoken = self.test_compile_bridge()
- mem1 = self.cpu.asmmemmgr.total_mallocs
- self.cpu.free_loop_and_bridges(looptoken.compiled_loop_token)
- mem2 = self.cpu.asmmemmgr.total_mallocs
- assert mem2 < mem1
- assert mem2 == mem0
- def test_memoryerror(self):
- excdescr = BasicFailDescr(666)
- self.cpu.propagate_exception_descr = excdescr
- self.cpu.setup_once() # xxx redo it, because we added
- # propagate_exception
- i0 = InputArgInt()
- p0 = ResOperation(rop.NEWUNICODE, [i0])
- operations = [
- p0,
- ResOperation(rop.FINISH, [p0], descr=BasicFinalDescr(1))
- ]
- inputargs = [i0]
- looptoken = JitCellToken()
- self.cpu.compile_loop(inputargs, operations, looptoken)
- # overflowing value:
- unisize = self.cpu.gc_ll_descr.unicode_descr.itemsize
- assert unisize in (2, 4)
- deadframe = self.cpu.execute_token(looptoken, sys.maxint // unisize + 1)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == excdescr.identifier
- exc = self.cpu.grab_exc_value(deadframe)
- assert not exc
- def test_math_sqrt(self):
- if not self.cpu.supports_floats:
- py.test.skip("requires floats")
- def math_sqrt(a):
- assert False, 'should not be called'
- from rpython.jit.codewriter.effectinfo import EffectInfo
- effectinfo = EffectInfo([], [], [], [], [], [], EffectInfo.EF_CANNOT_RAISE, EffectInfo.OS_MATH_SQRT)
- FPTR = self.Ptr(self.FuncType([lltype.Float], lltype.Float))
- func_ptr = llhelper(FPTR, math_sqrt)
- FUNC = deref(FPTR)
- funcbox = self.get_funcbox(self.cpu, func_ptr)
- calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, effectinfo)
- testcases = [(4.0, 2.0), (6.25, 2.5)]
- for arg, expected in testcases:
- res = self.execute_operation(rop.CALL_F,
- [funcbox, boxfloat(arg)],
- 'float', descr=calldescr)
- assert longlong.getrealfloat(res) == expected
- def test_check_memory_error(self):
- self.execute_operation(
- rop.CHECK_MEMORY_ERROR, [InputArgInt(12345)], 'void')
- py.test.raises(MissingLatestDescrError, self.execute_operation,
- rop.CHECK_MEMORY_ERROR, [InputArgInt(0)], 'void')
- def test_compile_loop_with_target(self):
- looptoken = JitCellToken()
- targettoken1 = TargetToken()
- targettoken2 = TargetToken()
- faildescr = BasicFailDescr(2)
- faildescr3 = BasicFailDescr(3)
- loop = parse("""
- [i0]
- label(i0, descr=targettoken1)
- i1 = int_add(i0, 1)
- i2 = int_le(i1, 9)
- guard_true(i2, descr=faildescr) [i1]
- label(i1, descr=targettoken2)
- i3 = int_ge(i1, 0)
- guard_true(i3, descr=faildescr3) [i1]
- jump(i1, descr=targettoken1)
- """, namespace=locals())
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, 2)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 2
- res = self.cpu.get_int_value(deadframe, 0)
- assert res == 10
- bridge = parse("""
- [i0]
- i2 = int_sub(i0, 20)
- jump(i2, descr=targettoken2)
- """, namespace=locals())
- self.cpu.compile_bridge(faildescr, bridge.inputargs,
- bridge.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, 2)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 3
- res = self.cpu.get_int_value(deadframe, 0)
- assert res == -10
- def test_int_force_ge_zero(self):
- ops = """
- [i0]
- i1 = int_force_ge_zero(i0) # but forced to be in a register
- finish(i1, descr=descr)
- """
- descr = BasicFinalDescr()
- loop = parse(ops, self.cpu, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- for inp, outp in [(2,2), (-3, 0)]:
- deadframe = self.cpu.execute_token(looptoken, inp)
- assert outp == self.cpu.get_int_value(deadframe, 0)
- def test_int_signext(self):
- numbytes_cases = [1, 2] if IS_32_BIT else [1, 2, 4]
- for spill in ["", "force_spill(i1)"]:
- for numbytes in numbytes_cases:
- print (spill, numbytes)
- ops = """
- [i0]
- i1 = int_sub(i0, 0) # force in register
- %s
- i2 = int_signext(i1, %d)
- finish(i2, descr=descr)
- """ % (spill, numbytes)
- descr = BasicFinalDescr()
- loop = parse(ops, self.cpu, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- test_cases = [random.randrange(-sys.maxint-1, sys.maxint+1)
- for _ in range(100)]
- for test_case in test_cases:
- deadframe = self.cpu.execute_token(looptoken, test_case)
- got = self.cpu.get_int_value(deadframe, 0)
- expected = heaptracker.int_signext(test_case, numbytes)
- assert got == expected
- def test_compile_asmlen(self):
- if not isinstance(self.cpu, AbstractLLCPU):
- py.test.skip("pointless test on non-asm")
- from rpython.jit.backend.tool.viewcode import machine_code_dump, ObjdumpNotFound
- import ctypes
- targettoken = TargetToken()
- ops = """
- [i2]
- i0 = same_as_i(i2) # but forced to be in a register
- label(i0, descr=targettoken)
- i1 = int_add(i0, i0)
- guard_true(i1, descr=faildescr) [i1]
- jump(i1, descr=targettoken)
- """
- faildescr = BasicFailDescr(2)
- loop = parse(ops, self.cpu, namespace=locals())
- bridge_ops = """
- [i0]
- jump(i0, descr=targettoken)
- """
- bridge = parse(bridge_ops, self.cpu, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.assembler.set_debug(False)
- info = self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- bridge_info = self.cpu.compile_bridge(faildescr, bridge.inputargs,
- bridge.operations,
- looptoken)
- self.cpu.assembler.set_debug(True) # always on untranslated
- assert info.asmlen != 0
- cpuname = autodetect()
- # XXX we have to check the precise assembler, otherwise
- # we don't quite know if borders are correct
- def checkops(mc, ops_regexp):
- import re
- words = []
- print '----- checkops -----'
- for line in mc:
- print line.rstrip()
- t = line.split("\t")
- if len(t) <= 2:
- continue
- w = t[2].split()
- if len(w) == 0:
- if '<UNDEFINED>' in line:
- w = ['UNDEFINED']
- else:
- continue
- words.append(w[0] + ';')
- print '[[%s]]' % (w[0],)
- text = ' '.join(words)
- assert re.compile(ops_regexp).match(text)
- data = ctypes.string_at(info.asmaddr, info.asmlen)
- try:
- mc = list(machine_code_dump(data, info.asmaddr, cpuname))
- checkops(mc, self.add_loop_instructions)
- data = ctypes.string_at(bridge_info.asmaddr, bridge_info.asmlen)
- mc = list(machine_code_dump(data, bridge_info.asmaddr, cpuname))
- checkops(mc, self.bridge_loop_instructions)
- except ObjdumpNotFound:
- py.test.skip("requires (g)objdump")
- def test_compile_bridge_with_target(self):
- # This test creates a loopy piece of code in a bridge, and builds another
- # unrelated loop that ends in a jump directly to this loopy bit of code.
- # It catches a case in which we underestimate the needed frame_depth across
- # the cross-loop JUMP, because we estimate it based on the frame_depth stored
- # in the original loop.
- looptoken1 = JitCellToken()
- targettoken1 = TargetToken()
- faildescr1 = BasicFailDescr(2)
- finaldescr1 = BasicFinalDescr(1234)
- loop = parse("""
- [i0]
- i1 = int_le(i0, 1)
- guard_true(i1, descr=faildescr1) [i0]
- finish(i0, descr=finaldescr1)
- """, namespace=locals())
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken1)
- def func(a, b, c, d, e, f, g, h, i):
- assert a + 2 == b
- assert a + 4 == c
- assert a + 6 == d
- assert a + 8 == e
- assert a + 10 == f
- assert a + 12 == g
- assert a + 14 == h
- assert a + 16 == i
- FPTR = self.Ptr(self.FuncType([lltype.Signed]*9, lltype.Void))
- func_ptr = llhelper(FPTR, func)
- cpu = self.cpu
- calldescr = cpu.calldescrof(deref(FPTR), (lltype.Signed,)*9, lltype.Void,
- EffectInfo.MOST_GENERAL)
- faildescr=BasicFailDescr(42)
- loop = parse("""
- [i0]
- label(i0, descr=targettoken1)
- i1 = int_add(i0, 1)
- i2 = int_add(i1, 1)
- i3 = int_add(i2, 1)
- i4 = int_add(i3, 1)
- i5 = int_add(i4, 1)
- i6 = int_add(i5, 1)
- i7 = int_add(i6, 1)
- i8 = int_add(i7, 1)
- i9 = int_add(i8, 1)
- i10 = int_add(i9, 1)
- i11 = int_add(i10, 1)
- i12 = int_add(i11, 1)
- i13 = int_add(i12, 1)
- i14 = int_add(i13, 1)
- i15 = int_add(i14, 1)
- i16 = int_add(i15, 1)
- i17 = int_add(i16, 1)
- i18 = int_add(i17, 1)
- i19 = int_add(i18, 1)
- call_n(ConstClass(func_ptr), i2, i4, i6, i8, i10, i12, i14, i16, i18, descr=calldescr)
- call_n(ConstClass(func_ptr), i2, i4, i6, i8, i10, i12, i14, i16, i18, descr=calldescr)
- i20 = int_lt(i19, 100)
- guard_true(i20, descr=faildescr) []
- jump(i19, descr=targettoken1)
- """, namespace=locals())
- self.cpu.compile_bridge(faildescr1, loop.inputargs,
- loop.operations, looptoken1)
- looptoken2 = JitCellToken()
- inputargs = [InputArgInt()]
- operations3 = [
- ResOperation(rop.JUMP, [ConstInt(0)], descr=targettoken1),
- ]
- self.cpu.compile_loop(inputargs, operations3, looptoken2)
- deadframe = self.cpu.execute_token(looptoken2, -9)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 42
- def test_wrong_guard_nonnull_class(self):
- t_box, T_box, _ = self.alloc_instance(self.T)
- null_box = self.null_instance()
- faildescr = BasicFailDescr(42)
- operations = [
- ResOperation(rop.GUARD_NONNULL_CLASS, [t_box, T_box],
- descr=faildescr),
- ResOperation(rop.FINISH, [], descr=BasicFinalDescr(1))]
- operations[0].setfailargs([])
- looptoken = JitCellToken()
- inputargs = [t_box]
- self.cpu.compile_loop(inputargs, operations, looptoken)
- operations = [
- ResOperation(rop.FINISH, [], descr=BasicFinalDescr(99))
- ]
- self.cpu.compile_bridge(faildescr, [], operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, null_box.getref_base())
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 99
- def test_raw_load_int(self):
- from rpython.rlib import rawstorage
- for T in [rffi.UCHAR, rffi.SIGNEDCHAR,
- rffi.USHORT, rffi.SHORT,
- rffi.UINT, rffi.INT,
- rffi.ULONG, rffi.LONG]:
- ops = """
- [i0, i1]
- i2 = raw_load_i(i0, i1, descr=arraydescr)
- finish(i2)
- """
- arraydescr = self.cpu.arraydescrof(rffi.CArray(T))
- p = rawstorage.alloc_raw_storage(31)
- for i in range(31):
- p[i] = '\xDD'
- value = rffi.cast(T, -0x4243444546474849)
- rawstorage.raw_storage_setitem(p, 16, value)
- got = self.cpu.bh_raw_load_i(rffi.cast(lltype.Signed, p), 16,
- arraydescr)
- assert got == rffi.cast(lltype.Signed, value)
- #
- loop = parse(ops, self.cpu, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken,
- rffi.cast(lltype.Signed, p), 16)
- result = self.cpu.get_int_value(deadframe, 0)
- assert result == rffi.cast(lltype.Signed, value)
- rawstorage.free_raw_storage(p)
- def test_raw_load_float(self):
- if not self.cpu.supports_floats:
- py.test.skip("requires floats")
- from rpython.rlib import rawstorage
- for T in [rffi.DOUBLE]:
- ops = """
- [i0, i1]
- f2 = raw_load_f(i0, i1, descr=arraydescr)
- finish(f2)
- """
- arraydescr = self.cpu.arraydescrof(rffi.CArray(T))
- p = rawstorage.alloc_raw_storage(31)
- for i in range(31):
- p[i] = '\xDD'
- value = rffi.cast(T, 1.12e20)
- rawstorage.raw_storage_setitem(p, 16, value)
- got = self.cpu.bh_raw_load_f(rffi.cast(lltype.Signed, p), 16,
- arraydescr)
- got = longlong.getrealfloat(got)
- assert got == rffi.cast(lltype.Float, value)
- #
- loop = parse(ops, self.cpu, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken,
- rffi.cast(lltype.Signed, p), 16)
- result = self.cpu.get_float_value(deadframe, 0)
- result = longlong.getrealfloat(result)
- assert result == rffi.cast(lltype.Float, value)
- rawstorage.free_raw_storage(p)
- def test_raw_load_singlefloat(self):
- if not self.cpu.supports_singlefloats:
- py.test.skip("requires singlefloats")
- from rpython.rlib import rawstorage
- for T in [rffi.FLOAT]:
- ops = """
- [i0, i1]
- i2 = raw_load_i(i0, i1, descr=arraydescr)
- finish(i2)
- """
- arraydescr = self.cpu.arraydescrof(rffi.CArray(T))
- p = rawstorage.alloc_raw_storage(31)
- for i in range(31):
- p[i] = '\xDD'
- value = rffi.cast(T, 1.12e20)
- rawstorage.raw_storage_setitem(p, 16, value)
- got = self.cpu.bh_raw_load_i(rffi.cast(lltype.Signed, p), 16,
- arraydescr)
- assert got == longlong.singlefloat2int(value)
- #
- loop = parse(ops, self.cpu, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken,
- rffi.cast(lltype.Signed, p), 16)
- result = self.cpu.get_int_value(deadframe, 0)
- assert result == longlong.singlefloat2int(value)
- rawstorage.free_raw_storage(p)
- def test_raw_store_int(self):
- from rpython.rlib import rawstorage
- for T in [rffi.UCHAR, rffi.SIGNEDCHAR,
- rffi.USHORT, rffi.SHORT,
- rffi.UINT, rffi.INT,
- rffi.ULONG, rffi.LONG]:
- arraydescr = self.cpu.arraydescrof(rffi.CArray(T))
- p = rawstorage.alloc_raw_storage(31)
- value = (-0x4243444546474849) & sys.maxint
- self.cpu.bh_raw_store_i(rffi.cast(lltype.Signed, p), 16, value,
- arraydescr)
- result = rawstorage.raw_storage_getitem(T, p, 16)
- assert result == rffi.cast(T, value)
- rawstorage.free_raw_storage(p)
- #
- ops = """
- [i0, i1, i2]
- raw_store(i0, i1, i2, descr=arraydescr)
- finish()
- """
- p = rawstorage.alloc_raw_storage(31)
- for i in range(31):
- p[i] = '\xDD'
- loop = parse(ops, self.cpu, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- self.cpu.execute_token(looptoken,
- rffi.cast(lltype.Signed, p), 16, value)
- result = rawstorage.raw_storage_getitem(T, p, 16)
- assert result == rffi.cast(T, value)
- rawstorage.free_raw_storage(p)
- def test_raw_store_float(self):
- if not self.cpu.supports_floats:
- py.test.skip("requires floats")
- from rpython.rlib import rawstorage
- for T in [rffi.DOUBLE]:
- arraydescr = self.cpu.arraydescrof(rffi.CArray(T))
- p = rawstorage.alloc_raw_storage(31)
- value = 1.23e20
- self.cpu.bh_raw_store_f(rffi.cast(lltype.Signed, p), 16,
- longlong.getfloatstorage(value),
- arraydescr)
- result = rawstorage.raw_storage_getitem(T, p, 16)
- assert result == rffi.cast(T, value)
- rawstorage.free_raw_storage(p)
- #
- ops = """
- [i0, i1, f2]
- raw_store(i0, i1, f2, descr=arraydescr)
- finish()
- """
- p = rawstorage.alloc_raw_storage(31)
- for i in range(31):
- p[i] = '\xDD'
- loop = parse(ops, self.cpu, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- self.cpu.execute_token(looptoken,
- rffi.cast(lltype.Signed, p), 16,
- longlong.getfloatstorage(value))
- result = rawstorage.raw_storage_getitem(T, p, 16)
- assert result == rffi.cast(T, value)
- rawstorage.free_raw_storage(p)
- def test_raw_store_singlefloat(self):
- if not self.cpu.supports_singlefloats:
- py.test.skip("requires singlefloats")
- from rpython.rlib import rawstorage
- for T in [rffi.FLOAT]:
- arraydescr = self.cpu.arraydescrof(rffi.CArray(T))
- p = rawstorage.alloc_raw_storage(31)
- value = rffi.cast(T, 1.23e20)
- self.cpu.bh_raw_store_i(rffi.cast(lltype.Signed, p), 16,
- longlong.singlefloat2int(value),
- arraydescr)
- result = rawstorage.raw_storage_getitem(T, p, 16)
- assert (rffi.cast(lltype.Float, result) ==
- rffi.cast(lltype.Float, value))
- rawstorage.free_raw_storage(p)
- #
- ops = """
- [i0, i1, i2]
- raw_store(i0, i1, i2, descr=arraydescr)
- finish()
- """
- p = rawstorage.alloc_raw_storage(31)
- for i in range(31):
- p[i] = '\xDD'
- loop = parse(ops, self.cpu, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- self.cpu.execute_token(looptoken,
- rffi.cast(lltype.Signed, p), 16,
- longlong.singlefloat2int(value))
- result = rawstorage.raw_storage_getitem(T, p, 16)
- assert (rffi.cast(lltype.Float, result) ==
- rffi.cast(lltype.Float, value))
- rawstorage.free_raw_storage(p)
- def test_forcing_op_with_fail_arg_in_reg(self):
- values = []
- def maybe_force(token, flag):
- deadframe = self.cpu.force(token)
- values.append(self.cpu.get_int_value(deadframe, 0))
- return 42
- FUNC = self.FuncType([llmemory.GCREF, lltype.Signed], lltype.Signed)
- func_ptr = llhelper(lltype.Ptr(FUNC), maybe_force)
- calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
- finaldescr=BasicFinalDescr(0)
- faildescr = BasicFailDescr(23)
- loop = parse("""
- [i0, i1]
- p2 = force_token()
- i3 = call_may_force_i(ConstClass(func_ptr), p2, i1, descr=calldescr)
- guard_not_forced(descr=faildescr) [i3]
- finish(i3, descr=finaldescr)
- """, namespace=locals())
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, 20, 0)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 23
- assert self.cpu.get_int_value(deadframe, 0) == 42
- def test_compile_bridge_while_running(self):
- def func():
- bridge = parse("""
- [i1, i2, px]
- i3 = int_add(i1, i2)
- i4 = int_add(i1, i3)
- i5 = int_add(i1, i4)
- i6 = int_add(i4, i5)
- i7 = int_add(i6, i5)
- i8 = int_add(i5, 1)
- i9 = int_add(i8, 1)
- force_spill(i1)
- force_spill(i2)
- force_spill(i3)
- force_spill(i4)
- force_spill(i5)
- force_spill(i6)
- force_spill(i7)
- force_spill(i8)
- force_spill(i9)
- call_n(ConstClass(func2_ptr), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, descr=calldescr2)
- guard_true(i1, descr=guarddescr) [i1, i2, i3, i4, i5, i6, i7, i8, i9, px]
- finish(i1, descr=finaldescr)
- """, namespace={'finaldescr': finaldescr, 'calldescr2': calldescr2,
- 'guarddescr': guarddescr, 'func2_ptr': func2_ptr})
- self.cpu.compile_bridge(faildescr, bridge.inputargs,
- bridge.operations, looptoken)
- cpu = self.cpu
- finaldescr = BasicFinalDescr(13)
- finaldescr2 = BasicFinalDescr(133)
- guarddescr = BasicFailDescr(8)
- FUNC = self.FuncType([], lltype.Void)
- FPTR = self.Ptr(FUNC)
- func_ptr = llhelper(FPTR, func)
- calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
- def func2(a, b, c, d, e, f, g, h, i, j, k, l):
- pass
- FUNC2 = self.FuncType([lltype.Signed] * 12, lltype.Void)
- FPTR2 = self.Ptr(FUNC2)
- func2_ptr = llhelper(FPTR2, func2)
- calldescr2 = cpu.calldescrof(FUNC2, FUNC2.ARGS, FUNC2.RESULT,
- EffectInfo.MOST_GENERAL)
- faildescr = BasicFailDescr(0)
- looptoken = JitCellToken()
- loop = parse("""
- [i0, i1, i2]
- call_n(ConstClass(func_ptr), descr=calldescr)
- px = force_token()
- guard_true(i0, descr=faildescr) [i1, i2, px]
- finish(i2, descr=finaldescr2)
- """, namespace=locals())
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- frame = self.cpu.execute_token(looptoken, 0, 0, 3)
- assert self.cpu.get_latest_descr(frame) is guarddescr
- if not isinstance(self.cpu, AbstractLLCPU):
- py.test.skip("pointless test on non-asm")
- frame = lltype.cast_opaque_ptr(jitframe.JITFRAMEPTR, frame)
- assert len(frame.jf_frame) == frame.jf_frame_info.jfi_frame_depth
- ref = self.cpu.get_ref_value(frame, 9)
- token = lltype.cast_opaque_ptr(jitframe.JITFRAMEPTR, ref)
- assert token != frame
- token = token.resolve()
- assert token == frame
- def test_compile_bridge_while_running_guard_no_exc(self):
- xtp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
- xtp.subclassrange_min = 1
- xtp.subclassrange_max = 3
- X = lltype.GcStruct('X', ('parent', rclass.OBJECT),
- hints={'vtable': xtp._obj})
- xptr = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(X))
- def raising():
- bridge = parse("""
- [i1, i2]
- px = guard_exception(ConstClass(xtp), descr=faildescr2) [i1, i2]
- i3 = int_add(i1, i2)
- i4 = int_add(i1, i3)
- i5 = int_add(i1, i4)
- i6 = int_add(i4, i5)
- i7 = int_add(i6, i5)
- i8 = int_add(i5, 1)
- i9 = int_add(i8, 1)
- force_spill(i1)
- force_spill(i2)
- force_spill(i3)
- force_spill(i4)
- force_spill(i5)
- force_spill(i6)
- force_spill(i7)
- force_spill(i8)
- force_spill(i9)
- i10 = int_is_true(i9)
- guard_true(i10) [i3, i4, i5, i6, i7, i8, i9]
- finish(i9, descr=finaldescr)
- """, namespace={'finaldescr': BasicFinalDescr(42),
- 'faildescr2': BasicFailDescr(1),
- 'xtp': xtp
- })
- self.cpu.compile_bridge(faildescr, bridge.inputargs,
- bridge.operations, looptoken)
- raise LLException(xtp, xptr)
- faildescr = BasicFailDescr(0)
- FUNC = self.FuncType([], lltype.Void)
- raising_ptr = llhelper(lltype.Ptr(FUNC), raising)
- calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
- EffectInfo.MOST_GENERAL)
- looptoken = JitCellToken()
- loop = parse("""
- [i0, i1, i2]
- call_n(ConstClass(raising_ptr), descr=calldescr)
- guard_no_exception(descr=faildescr) [i1, i2]
- finish(i2, descr=finaldescr2)
- """, namespace={'raising_ptr': raising_ptr,
- 'calldescr': calldescr,
- 'faildescr': faildescr,
- 'finaldescr2': BasicFinalDescr(1)})
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- frame = self.cpu.execute_token(looptoken, 1, 2, 3)
- descr = self.cpu.get_latest_descr(frame)
- assert descr.identifier == 42
- assert not self.cpu.grab_exc_value(frame)
- def test_setarrayitem_raw_short(self):
- # setarrayitem_raw(140737353744432, 0, 30583, descr=<ArrayS 2>)
- A = rffi.CArray(rffi.SHORT)
- arraydescr = self.cpu.arraydescrof(A)
- a = lltype.malloc(A, 2, flavor='raw')
- a[0] = rffi.cast(rffi.SHORT, 666)
- a[1] = rffi.cast(rffi.SHORT, 777)
- addr = llmemory.cast_ptr_to_adr(a)
- a_int = heaptracker.adr2int(addr)
- print 'a_int:', a_int
- self.execute_operation(rop.SETARRAYITEM_RAW,
- [ConstInt(a_int), ConstInt(0), ConstInt(-7654)],
- 'void', descr=arraydescr)
- assert rffi.cast(lltype.Signed, a[0]) == -7654
- assert rffi.cast(lltype.Signed, a[1]) == 777
- lltype.free(a, flavor='raw')
- def test_increment_debug_counter(self):
- foo = lltype.malloc(rffi.CArray(lltype.Signed), 1, flavor='raw')
- foo[0] = 1789200
- self.execute_operation(rop.INCREMENT_DEBUG_COUNTER,
- [ConstInt(rffi.cast(lltype.Signed, foo))],
- 'void')
- assert foo[0] == 1789201
- lltype.free(foo, flavor='raw')
- def test_cast_float_to_singlefloat(self):
- if not self.cpu.supports_singlefloats:
- py.test.skip("requires singlefloats")
- res = self.execute_operation(rop.CAST_FLOAT_TO_SINGLEFLOAT,
- [boxfloat(12.5)], 'int')
- assert res == struct.unpack("I", struct.pack("f", 12.5))[0]
- def test_zero_array(self):
- if not isinstance(self.cpu, AbstractLLCPU):
- py.test.skip("llgraph does not do zero_array")
- PAIR = lltype.Struct('PAIR', ('a', lltype.Signed), ('b', lltype.Signed))
- for OF in [lltype.Signed, rffi.INT, rffi.SHORT, rffi.UCHAR, PAIR]:
- A = lltype.GcArray(OF)
- arraydescr = self.cpu.arraydescrof(A)
- a = lltype.malloc(A, 100)
- addr = llmemory.cast_ptr_to_adr(a)
- a_int = heaptracker.adr2int(addr)
- a_ref = lltype.cast_opaque_ptr(llmemory.GCREF, a)
- for (start, length) in [(0, 100), (49, 49), (1, 98),
- (15, 9), (10, 10), (47, 0),
- (0, 4)]:
- for cls1 in [ConstInt, InputArgInt]:
- for cls2 in [ConstInt, InputArgInt]:
- print 'a_int:', a_int
- print 'of:', OF
- print 'start:', cls1.__name__, start
- print 'length:', cls2.__name__, length
- for i in range(100):
- if OF == PAIR:
- a[i].a = a[i].b = -123456789
- else:
- a[i] = rffi.cast(OF, -123456789)
- startbox = cls1(start)
- lengthbox = cls2(length)
- if cls1 == cls2 and start == length:
- lengthbox = startbox # same box!
- scale = arraydescr.itemsize
- ops = []
- def emit(op):
- ops.append(op)
- helper = GcRewriterAssembler(None, self.cpu)
- helper.emit_op = emit
- offset = 0
- scale_start, s_offset, v_start = \
- helper._emit_mul_if_factor_offset_not_supported(
- startbox, scale, offset)
- if v_start is None:
- v_start = ConstInt(s_offset)
- scale_len, e_offset, v_len = \
- helper._emit_mul_if_factor_offset_not_supported(
- lengthbox, scale, offset)
- if v_len is None:
- v_len = ConstInt(e_offset)
- args = [InputArgRef(a_ref), v_start, v_len,
- ConstInt(scale_start), ConstInt(scale_len)]
- ops.append(ResOperation(rop.ZERO_ARRAY, args,
- descr=arraydescr))
- scalebox = ConstInt(arraydescr.itemsize)
- inputargs, oplist = self._get_operation_list(ops,'void')
- self.execute_operations(inputargs, oplist, 'void')
- assert len(a) == 100
- for i in range(100):
- val = (0 if start <= i < start + length
- else -123456789)
- if OF == PAIR:
- assert a[i].a == a[i].b == val
- else:
- assert a[i] == rffi.cast(OF, val)
- def test_jump_float_constant(self):
- loop = parse("""
- [f0, f1]
- label(f0, f1, descr=targettoken)
- i2 = cast_float_to_int(f1)
- guard_value(i2, 123456, descr=faildescr6) []
- f3 = float_add(f0, -0.5)
- i4 = float_gt(f3, 9.12)
- guard_true(i4, descr=faildescr2) [f1, f3]
- jump(f3, 123456.78912, descr=targettoken)
- """, namespace={'targettoken': TargetToken(),
- 'faildescr2': BasicFailDescr(2),
- 'faildescr6': BasicFailDescr(6)})
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken,
- longlong.getfloatstorage(12.25),
- longlong.getfloatstorage(123456.01))
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 2
- res = longlong.getrealfloat(self.cpu.get_float_value(deadframe, 0))
- assert res == 123456.78912
- res = longlong.getrealfloat(self.cpu.get_float_value(deadframe, 1))
- assert res == 8.75
- def test_passing_guard_gc_type_struct(self):
- if not self.cpu.supports_guard_gc_type:
- py.test.skip("guard_gc_type not available")
- t_box, _, descr = self.alloc_instance(self.T)
- c_typeid = ConstInt(descr.get_type_id())
- self.execute_operation(rop.GUARD_GC_TYPE, [t_box, c_typeid], 'void')
- assert not self.guard_failed
- #
- got_typeid = self.cpu.get_actual_typeid(t_box.getref_base())
- assert got_typeid == c_typeid.getint()
- def test_passing_guard_gc_type_array(self):
- if not self.cpu.supports_guard_gc_type:
- py.test.skip("guard_gc_type not available")
- a_box, A = self.alloc_array_of(rffi.SHORT, 342)
- arraydescr = self.cpu.arraydescrof(A)
- c_typeid = ConstInt(arraydescr.get_type_id())
- self.execute_operation(rop.GUARD_GC_TYPE, [a_box, c_typeid], 'void')
- assert not self.guard_failed
- #
- got_typeid = self.cpu.get_actual_typeid(a_box.getref_base())
- assert got_typeid == c_typeid.getint()
- def test_failing_guard_gc_type(self):
- if not self.cpu.supports_guard_gc_type:
- py.test.skip("guard_gc_type not available")
- t_box, _, tdescr = self.alloc_instance(self.T)
- u_box, _, udescr = self.alloc_instance(self.U)
- a_box, A = self.alloc_array_of(rffi.SHORT, 342)
- adescr = self.cpu.arraydescrof(A)
- c_ttypeid = ConstInt(tdescr.get_type_id())
- c_utypeid = ConstInt(udescr.get_type_id())
- c_atypeid = ConstInt(adescr.get_type_id())
- for opname, args in [(rop.GUARD_GC_TYPE, [t_box, c_utypeid]),
- (rop.GUARD_GC_TYPE, [u_box, c_ttypeid]),
- (rop.GUARD_GC_TYPE, [a_box, c_utypeid]),
- (rop.GUARD_GC_TYPE, [t_box, c_atypeid]),
- ]:
- assert self.execute_operation(opname, args, 'void') == None
- assert self.guard_failed
- #
- got_typeid = self.cpu.get_actual_typeid(args[0].getref_base())
- assert got_typeid != args[1].getint()
- def test_guard_is_object(self):
- if not self.cpu.supports_guard_gc_type:
- py.test.skip("guard_gc_type not available")
- t_box, _, _ = self.alloc_instance(self.T)
- self.execute_operation(rop.GUARD_IS_OBJECT, [t_box], 'void')
- assert not self.guard_failed
- assert self.cpu.check_is_object(t_box.getref_base())
- #
- a_box, _ = self.alloc_array_of(rffi.SHORT, 342)
- self.execute_operation(rop.GUARD_IS_OBJECT, [a_box], 'void')
- assert self.guard_failed
- assert not self.cpu.check_is_object(a_box.getref_base())
- #
- S = lltype.GcStruct('S')
- s = lltype.malloc(S, immortal=True, zero=True)
- s_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, s))
- self.execute_operation(rop.GUARD_IS_OBJECT, [s_box], 'void')
- assert self.guard_failed
- assert not self.cpu.check_is_object(s_box.getref_base())
- def test_guard_subclass(self):
- if not self.cpu.supports_guard_gc_type:
- py.test.skip("guard_gc_type not available")
- xtp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
- xtp.subclassrange_min = 1
- xtp.subclassrange_max = 3
- X = lltype.GcStruct('X', ('parent', rclass.OBJECT),
- hints={'vtable': xtp._obj})
- xptr = lltype.malloc(X)
- xptr.parent.typeptr = xtp
- x_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, xptr))
- X_box = ConstInt(heaptracker.adr2int(llmemory.cast_ptr_to_adr(xtp)))
- ytp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
- ytp.subclassrange_min = 2
- ytp.subclassrange_max = 2
- assert rclass.ll_issubclass(ytp, xtp)
- Y = lltype.GcStruct('Y', ('parent', X),
- hints={'vtable': ytp._obj})
- yptr = lltype.malloc(Y)
- yptr.parent.parent.typeptr = ytp
- y_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, yptr))
- Y_box = ConstInt(heaptracker.adr2int(llmemory.cast_ptr_to_adr(ytp)))
- ztp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
- ztp.subclassrange_min = 4
- ztp.subclassrange_max = 5
- assert not rclass.ll_issubclass(ztp, xtp)
- assert not rclass.ll_issubclass(xtp, ztp)
- Z = lltype.GcStruct('Z', ('parent', rclass.OBJECT),
- hints={'vtable': ztp._obj})
- zptr = lltype.malloc(Z)
- zptr.parent.typeptr = ztp
- z_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, zptr))
- Z_box = ConstInt(heaptracker.adr2int(llmemory.cast_ptr_to_adr(ztp)))
- for num, arg, klass, is_subclass in [
- (1, x_box, X_box, True),
- (2, x_box, Y_box, False),
- (3, x_box, Z_box, False),
- (4, y_box, X_box, True),
- (5, y_box, Y_box, True),
- (6, y_box, Z_box, False),
- (7, z_box, X_box, False),
- (8, z_box, Y_box, False),
- (9, z_box, Z_box, True),
- ]:
- self.execute_operation(rop.GUARD_SUBCLASS, [arg, klass], 'void')
- assert self.guard_failed == (not is_subclass)
- def test_bug_from_optimize_cond_call(self):
- loop = parse("""
- [i0, i1]
- i99 = int_sub(i0, i0)
- force_spill(i99)
- i2 = int_add(i0, i1)
- i3 = int_add(i0, i1)
- i4 = int_add(i0, i1)
- i5 = int_add(i0, i1)
- i6 = int_add(i0, i1)
- i7 = int_add(i0, i1)
- i8 = int_add(i0, i1)
- i9 = int_add(i0, i1)
- i10 = int_add(i0, i1)
- i11 = int_add(i0, i1)
- i12 = int_add(i0, i1)
- i13 = int_add(i0, i1)
- i14 = int_add(i0, i1)
- i15 = int_add(i0, i1)
- i16 = int_add(i0, i1)
- i17 = int_add(i0, i1)
- i18 = int_add(i0, i1)
- i19 = int_add(i0, i1)
- i20 = int_is_true(i99)
- force_spill(i0)
- force_spill(i1)
- force_spill(i2)
- force_spill(i3)
- force_spill(i4)
- force_spill(i5)
- force_spill(i6)
- force_spill(i7)
- force_spill(i8)
- force_spill(i9)
- force_spill(i10)
- force_spill(i11)
- force_spill(i12)
- force_spill(i13)
- force_spill(i14)
- force_spill(i15)
- force_spill(i16)
- force_spill(i17)
- force_spill(i18)
- force_spill(i19)
- finish(i20, descr=finaldescr)
- """, namespace={"finaldescr": BasicFinalDescr(1)})
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken, 40, 2)
- fail = self.cpu.get_latest_descr(deadframe)
- res = self.cpu.get_int_value(deadframe, 0)
- assert res == 0
- def test_load_from_gc_table_many(self):
- # Test that 'load_from_gc_table' handles a table of NUM entries.
- # Done by writing NUM setfield_gc on constants. Each one
- # requires a load_from_gc_table. The value of NUM is choosen
- # so that not all of them fit into the ARM's 4096-bytes offset.
- NUM = 1025
- S = lltype.GcStruct('S', ('x', lltype.Signed))
- fielddescr = self.cpu.fielddescrof(S, 'x')
- table = [lltype.malloc(S) for i in range(NUM)]
- looptoken = JitCellToken()
- targettoken = TargetToken()
- ops = [
- '[]',
- ]
- namespace = {'fielddescr': fielddescr,
- 'finaldescr': BasicFinalDescr(5)}
- for i, s in enumerate(table):
- ops.append('setfield_gc(ConstPtr(ptr%d), %d, descr=fielddescr)'
- % (i, i))
- namespace['ptr%d' % i] = lltype.cast_opaque_ptr(llmemory.GCREF, s)
- ops.append('finish(descr=finaldescr)')
- loop = parse('\n'.join(ops), namespace=namespace)
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
- deadframe = self.cpu.execute_token(looptoken)
- fail = self.cpu.get_latest_descr(deadframe)
- assert fail.identifier == 5
- # check that all setfield_gc() worked
- for i, s in enumerate(table):
- assert s.x == i