/rpython/jit/backend/test/runner_test.py
Python | 5359 lines | 5329 code | 25 blank | 5 comment | 40 complexity | ece127fac68b3b5983688c001d2952ae MD5 | raw file
Possible License(s): Apache-2.0, AGPL-3.0, BSD-3-Clause
Large files files are truncated, but you can click here to view the full file
- 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]:
- …
Large files files are truncated, but you can click here to view the full file