def compile_tmp_callback(cpu, jitdriver_sd, greenboxes, redargtypes, memory_manager=None): """Make a LoopToken that corresponds to assembler code that just calls back the interpreter. Used temporarily: a fully compiled version of the code may end up replacing it. """ jitcell_token = make_jitcell_token(jitdriver_sd) nb_red_args = jitdriver_sd.num_red_args assert len(redargtypes) == nb_red_args inputargs = [] for kind in redargtypes: if kind == history.INT: box = BoxInt() elif kind == history.REF: box = BoxPtr() elif kind == history.FLOAT: box = BoxFloat() else: raise AssertionError inputargs.append(box) k = jitdriver_sd.portal_runner_adr funcbox = history.ConstInt(heaptracker.adr2int(k)) callargs = [funcbox] + greenboxes + inputargs # result_type = jitdriver_sd.result_type if result_type == history.INT: result = BoxInt() elif result_type == history.REF: result = BoxPtr() elif result_type == history.FLOAT: result = BoxFloat() elif result_type == history.VOID: result = None else: assert 0, "bad result_type" if result is not None: finishargs = [result] else: finishargs = [] # jd = jitdriver_sd faildescr = PropagateExceptionDescr() operations = [ ResOperation(rop.CALL, callargs, result, descr=jd.portal_calldescr), ResOperation(rop.GUARD_NO_EXCEPTION, [], None, descr=faildescr), ResOperation(rop.FINISH, finishargs, None, descr=jd.portal_finishtoken) ] operations[1].setfailargs([]) operations = get_deep_immutable_oplist(operations) cpu.compile_loop(inputargs, operations, jitcell_token, log=False) if memory_manager is not None: # for tests memory_manager.keep_loop_alive(jitcell_token) return jitcell_token
def __init__(self, cpu, builder_factory, r, startvars=None): self.cpu = cpu if startvars is None: startvars = [] if cpu.supports_floats: # pick up a single threshold for the whole 'inputargs', so # that some loops have no or mostly no BoxFloat while others # have a lot of them k = r.random() # but make sure there is at least one BoxInt at_least_once = r.randrange(0, pytest.config.option.n_vars) else: k = -1 at_least_once = 0 for i in range(pytest.config.option.n_vars): if r.random() < k and i != at_least_once: startvars.append(BoxFloat(r.random_float_storage())) else: startvars.append(BoxInt(r.random_integer())) allow_delay = True else: allow_delay = False assert len(dict.fromkeys(startvars)) == len(startvars) self.startvars = startvars self.prebuilt_ptr_consts = [] self.r = r self.build_random_loop(cpu, builder_factory, r, startvars, allow_delay)
def do_getarrayitem_gc(self, arraybox, indexbox, arraydescr): itemindex = indexbox.getint() gcref = arraybox.getref_base() ofs, size, ptr, float = self.unpack_arraydescr(arraydescr) # --- start of GC unsafe code (no GC operation!) --- items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), ofs) # if ptr: items = rffi.cast(rffi.CArrayPtr(lltype.Signed), items) pval = self._cast_int_to_gcref(items[itemindex]) # --- end of GC unsafe code --- return BoxPtr(pval) # if float: items = rffi.cast(rffi.CArrayPtr(lltype.Float), items) fval = items[itemindex] # --- end of GC unsafe code --- return BoxFloat(fval) # for TYPE, itemsize in unroll_basic_sizes: if size == itemsize: items = rffi.cast(rffi.CArrayPtr(TYPE), items) val = items[itemindex] # --- end of GC unsafe code --- return BoxInt(rffi.cast(lltype.Signed, val)) else: raise NotImplementedError("size = %d" % size)
def box_for_var(self, elem): try: return self._cache[self.type_system, elem] except KeyError: pass if elem.startswith('i'): # integer box = BoxInt() _box_counter_more_than(elem[1:]) elif elem.startswith('f'): box = BoxFloat() _box_counter_more_than(elem[1:]) elif elem.startswith('p'): # pointer ts = getattr(self.cpu, 'ts', llhelper) box = ts.BoxRef() _box_counter_more_than(elem[1:]) else: for prefix, boxclass in self.boxkinds.iteritems(): if elem.startswith(prefix): box = boxclass() break else: raise ParseError("Unknown variable type: %s" % elem) self._cache[self.type_system, elem] = box box._str = elem return box
def get_token_for_call(self, cpu): if self.loop_token is not None: return self.loop_token args = [BoxInt()] + self.instantiate_arg_classes() if self.get_result_size(cpu.translate_support_code) == 0: result = None result_list = [] else: if self.returns_a_pointer(): result = BoxPtr() elif self.returns_a_float(): result = BoxFloat() else: result = BoxInt() result_list = [result] operations = [ ResOperation(rop.CALL, args, result, self), ResOperation(rop.GUARD_NO_EXCEPTION, [], None, descr=BasicFailDescr()), ResOperation(rop.FINISH, result_list, None, descr=BasicFailDescr())] operations[1].fail_args = [] loop_token = LoopToken() cpu.compile_loop(args, operations, loop_token) self.loop_token = loop_token return loop_token
def get_token_for_call(self, cpu): if self.loop_token is not None: return self.loop_token args = [BoxInt()] + self.instantiate_arg_classes() if self.get_result_size(cpu.translate_support_code) == 0: result = None result_list = [] else: if self.returns_a_pointer(): result = BoxPtr() elif self.returns_a_float(): result = BoxFloat() else: result = BoxInt() result_list = [result] operations = [ ResOperation(rop.CALL, args[:], result, self), ResOperation(rop.GUARD_NO_EXCEPTION, [], None, descr=BasicFailDescr()), ResOperation(rop.FINISH, result_list, None, descr=BasicFailDescr()) ] operations[1].fail_args = [] loop_token = LoopToken() # note: the 'args' that we pass below is not the same object as the # 'args[:]' that was passed above to ResOperation, because we want # the argument to ResOperation to be non-resizable, but the argument # to compile_loop to be resizable. cpu.compile_loop(args, operations, loop_token) self.loop_token = loop_token return loop_token
def new_box(self, fieldofs): if fieldofs.is_pointer_field(): return self.new_ptr_box() elif fieldofs.is_float_field(): return BoxFloat() else: return BoxInt()
def new_box_item(self, arraydescr): if arraydescr.is_array_of_pointers(): return self.new_ptr_box() elif arraydescr.is_array_of_floats(): return BoxFloat() else: return BoxInt()
def do_getfield_gc(cpu, _, structbox, fielddescr): struct = structbox.getref_base() if fielddescr.is_pointer_field(): return BoxPtr(cpu.bh_getfield_gc_r(struct, fielddescr)) elif fielddescr.is_float_field(): return BoxFloat(cpu.bh_getfield_gc_f(struct, fielddescr)) else: return BoxInt(cpu.bh_getfield_gc_i(struct, fielddescr))
def instantiate_arg_classes(self): result = [] for c in self.arg_classes: if c == 'i': box = BoxInt() elif c == 'f': box = BoxFloat() else: box = BoxPtr() result.append(box) return result
def do_getarrayitem_raw(cpu, _, arraybox, indexbox, arraydescr): array = arraybox.getint() index = indexbox.getint() assert not arraydescr.is_array_of_pointers() if arraydescr.is_array_of_floats(): return BoxFloat(cpu.bh_getarrayitem_raw_f(arraydescr, array, index)) else: return BoxInt(cpu.bh_getarrayitem_raw_i(arraydescr, array, index))
def do_read_timestamp(cpu, _): x = read_timestamp() if longlong.is_64_bit: assert is_valid_int(x) # 64-bit return BoxInt(x) else: assert isinstance(x, r_longlong) # 32-bit return BoxFloat(x)
def do_getinteriorfield_gc(cpu, _, arraybox, indexbox, descr): array = arraybox.getref_base() index = indexbox.getint() if descr.is_pointer_field(): return BoxPtr(cpu.bh_getinteriorfield_gc_r(array, index, descr)) elif descr.is_float_field(): return BoxFloat(cpu.bh_getinteriorfield_gc_f(array, index, descr)) else: return BoxInt(cpu.bh_getinteriorfield_gc_i(array, index, descr))
def test_unwrap(): S = lltype.GcStruct('S') p = lltype.malloc(S) po = lltype.cast_opaque_ptr(llmemory.GCREF, p) assert unwrap(lltype.Void, BoxInt(42)) is None assert unwrap(lltype.Signed, BoxInt(42)) == 42 assert unwrap(lltype.Char, BoxInt(42)) == chr(42) assert unwrap(lltype.Float, BoxFloat(42.5)) == 42.5 assert unwrap(lltype.Ptr(S), BoxPtr(po)) == p
def do_getfield_raw(cpu, _, structbox, fielddescr): check_descr(fielddescr) struct = structbox.getint() if fielddescr.is_pointer_field(): return BoxPtr(cpu.bh_getfield_raw_r(struct, fielddescr)) elif fielddescr.is_float_field(): return BoxFloat(cpu.bh_getfield_raw_f(struct, fielddescr)) else: return BoxInt(cpu.bh_getfield_raw_i(struct, fielddescr))
def do_getarrayitem_gc(cpu, _, arraybox, indexbox, arraydescr): array = arraybox.getref_base() index = indexbox.getint() if arraydescr.is_array_of_pointers(): return BoxPtr(cpu.bh_getarrayitem_gc_r(arraydescr, array, index)) elif arraydescr.is_array_of_floats(): return BoxFloat(cpu.bh_getarrayitem_gc_f(arraydescr, array, index)) else: return BoxInt(cpu.bh_getarrayitem_gc_i(arraydescr, array, index))
def test_wrap(): def _is(box1, box2): return (box1.__class__ == box2.__class__ and box1.value == box2.value) p = lltype.malloc(lltype.GcStruct('S')) po = lltype.cast_opaque_ptr(llmemory.GCREF, p) assert _is(wrap(None, 42), BoxInt(42)) assert _is(wrap(None, 42.5), BoxFloat(42.5)) assert _is(wrap(None, p), BoxPtr(po)) assert _is(wrap(None, 42, in_const_box=True), ConstInt(42)) assert _is(wrap(None, 42.5, in_const_box=True), ConstFloat(42.5)) assert _is(wrap(None, p, in_const_box=True), ConstPtr(po))
def get_float_tests(cpu): if not cpu.supports_floats: py.test.skip("requires float support from the backend") for opnum, args, rettype, retvalue in ( list(_float_binary_operations()) + list(_float_comparison_operations()) + list(_float_unary_operations())): boxargs = [] for x in args: if isinstance(x, float): boxargs.append(BoxFloat(x)) else: boxargs.append(BoxInt(x)) yield opnum, boxargs, rettype, retvalue if len(args) > 1: assert len(args) == 2 yield opnum, [boxargs[0], boxargs[1].constbox()], rettype, retvalue yield opnum, [boxargs[0].constbox(), boxargs[1]], rettype, retvalue if (isinstance(args[0], float) and isinstance(args[1], float) and args[0] == args[1]): commonbox = BoxFloat(args[0]) yield opnum, [commonbox, commonbox], rettype, retvalue
def test_different_frame_width(self): class XRegisterManager(RegisterManager): reg_width = 2 fm = TFrameManager() b0 = BoxInt() longevity = {b0: (0, 1)} asm = MockAsm() rm = RegisterManager(longevity, frame_manager=fm, assembler=asm) f0 = BoxFloat() longevity = {f0: (0, 1)} xrm = XRegisterManager(longevity, frame_manager=fm, assembler=asm) xrm.loc(f0) rm.loc(b0) assert fm.frame_depth == 3
def test_wrap(): def _is(box1, box2): return (box1.__class__ == box2.__class__ and box1.value == box2.value) p = lltype.malloc(lltype.GcStruct('S')) po = lltype.cast_opaque_ptr(llmemory.GCREF, p) assert _is(wrap(None, 42), BoxInt(42)) assert _is(wrap(None, 42.5), boxfloat(42.5)) assert _is(wrap(None, p), BoxPtr(po)) assert _is(wrap(None, 42, in_const_box=True), ConstInt(42)) assert _is(wrap(None, 42.5, in_const_box=True), constfloat(42.5)) assert _is(wrap(None, p, in_const_box=True), ConstPtr(po)) if longlong.supports_longlong: import sys from pypy.rlib.rarithmetic import r_longlong, r_ulonglong value = r_longlong(-sys.maxint * 17) assert _is(wrap(None, value), BoxFloat(value)) assert _is(wrap(None, value, in_const_box=True), ConstFloat(value)) value_unsigned = r_ulonglong(-sys.maxint * 17) assert _is(wrap(None, value_unsigned), BoxFloat(value)) sfval = r_singlefloat(42.5) ival = longlong.singlefloat2int(sfval) assert _is(wrap(None, sfval), BoxInt(ival)) assert _is(wrap(None, sfval, in_const_box=True), ConstInt(ival))
def test_different_stack_width(self): class XRegisterManager(RegisterManager): reg_width = 2 sm = TStackManager() b0 = BoxInt() longevity = {b0: (0, 1)} asm = MockAsm() rm = RegisterManager(longevity, stack_manager=sm, assembler=asm) f0 = BoxFloat() longevity = {f0: (0, 1)} xrm = XRegisterManager(longevity, stack_manager=sm, assembler=asm) xrm.loc(f0) rm.loc(b0) assert sm.stack_depth == 3
def test_write_failure_recovery_description(): assembler = Assembler386(FakeCPU()) mc = FakeMC() failargs = [BoxInt(), BoxPtr(), BoxFloat()] * 3 failargs.insert(6, None) failargs.insert(7, None) locs = [ X86FrameManager.frame_pos(0, INT), X86FrameManager.frame_pos(1, REF), X86FrameManager.frame_pos(10, FLOAT), X86FrameManager.frame_pos(100, INT), X86FrameManager.frame_pos(101, REF), X86FrameManager.frame_pos(110, FLOAT), None, None, ebx, esi, xmm2 ] assert len(failargs) == len(locs) assembler.write_failure_recovery_description(mc, failargs, locs) base = 8 + 8 * IS_X86_64 nums = [ Assembler386.DESCR_INT + 4 * (base + 0), Assembler386.DESCR_REF + 4 * (base + 1), Assembler386.DESCR_FLOAT + 4 * (base + 10), Assembler386.DESCR_INT + 4 * (base + 100), Assembler386.DESCR_REF + 4 * (base + 101), Assembler386.DESCR_FLOAT + 4 * (base + 110), Assembler386.CODE_HOLE, Assembler386.CODE_HOLE, Assembler386.DESCR_INT + 4 * ebx.value, Assembler386.DESCR_REF + 4 * esi.value, Assembler386.DESCR_FLOAT + 4 * xmm2.value ] double_byte_nums = [] for num in nums[3:6]: double_byte_nums.append((num & 0x7F) | 0x80) double_byte_nums.append(num >> 7) assert mc.content == (nums[:3] + double_byte_nums + nums[6:] + [assembler.CODE_STOP]) # also test rebuild_faillocs_from_descr(), which should not # reproduce the holes at all bytecode = lltype.malloc(rffi.UCHARP.TO, len(mc.content), flavor='raw', immortal=True) for i in range(len(mc.content)): assert 0 <= mc.content[i] <= 255 bytecode[i] = rffi.cast(rffi.UCHAR, mc.content[i]) bytecode_addr = rffi.cast(lltype.Signed, bytecode) newlocs = assembler.rebuild_faillocs_from_descr(bytecode_addr) assert ([loc.assembler() for loc in newlocs ] == [loc.assembler() for loc in locs if loc is not None])
def do_call(self, args, calldescr): assert isinstance(calldescr, BaseCallDescr) assert len(args) == 1 + len(calldescr.arg_classes) if not we_are_translated(): assert (list( calldescr.arg_classes) == [arg.type for arg in args[1:]]) loop_token = calldescr.get_token_for_call(self) set_future_values(self, args) self.execute_token(loop_token) # Note: if an exception is set, the rest of the code does a bit of # nonsense but nothing wrong (the return value should be ignored) if calldescr.returns_a_pointer(): return BoxPtr(self.get_latest_value_ref(0)) elif calldescr.returns_a_float(): return BoxFloat(self.get_latest_value_float(0)) elif calldescr.get_result_size(self.translate_support_code) > 0: return BoxInt(self.get_latest_value_int(0)) else: return None
def do(cpu, _, *argboxes): newargs = () for argtype in argtypes: if argtype == 'cpu': value = cpu elif argtype == 'd': value = argboxes[-1] assert isinstance(value, AbstractDescr) argboxes = argboxes[:-1] else: argbox = argboxes[0] argboxes = argboxes[1:] if argtype == 'i': value = argbox.getint() elif argtype == 'r': value = argbox.getref_base() elif argtype == 'f': value = argbox.getfloatstorage() newargs = newargs + (value, ) assert not argboxes # result = func(*newargs) # if resulttype == 'i': return BoxInt(result) if resulttype == 'r': return BoxPtr(result) if resulttype == 'f': return BoxFloat(result) return None
def _base_do_getfield(self, gcref, fielddescr): ofs, size, ptr, float = self.unpack_fielddescr(fielddescr) # --- start of GC unsafe code (no GC operation!) --- field = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), ofs) # if ptr: pval = rffi.cast(rffi.CArrayPtr(lltype.Signed), field)[0] pval = self._cast_int_to_gcref(pval) # --- end of GC unsafe code --- return BoxPtr(pval) # if float: fval = rffi.cast(rffi.CArrayPtr(lltype.Float), field)[0] # --- end of GC unsafe code --- return BoxFloat(fval) # for TYPE, itemsize in unroll_basic_sizes: if size == itemsize: val = rffi.cast(rffi.CArrayPtr(TYPE), field)[0] # --- end of GC unsafe code --- val = rffi.cast(lltype.Signed, val) return BoxInt(val) else: raise NotImplementedError("size = %d" % size)
def test_write_failure_recovery_description(): assembler = Assembler386(FakeCPU()) mc = FakeMC() failargs = [BoxInt(), BoxPtr(), BoxFloat()] * 3 failargs.insert(6, None) failargs.insert(7, None) locs = [X86FrameManager.frame_pos(0, 1), X86FrameManager.frame_pos(1, 1), X86FrameManager.frame_pos(10, 2), X86FrameManager.frame_pos(100, 1), X86FrameManager.frame_pos(101, 1), X86FrameManager.frame_pos(110, 2), None, None, ebx, esi, xmm2] assert len(failargs) == len(locs) assembler.write_failure_recovery_description(mc, failargs, locs) nums = [Assembler386.DESCR_INT + 4*(8+0), Assembler386.DESCR_REF + 4*(8+1), Assembler386.DESCR_FLOAT + 4*(8+10), Assembler386.DESCR_INT + 4*(8+100), Assembler386.DESCR_REF + 4*(8+101), Assembler386.DESCR_FLOAT + 4*(8+110), Assembler386.CODE_HOLE, Assembler386.CODE_HOLE, Assembler386.DESCR_INT + 4*ebx.op, Assembler386.DESCR_REF + 4*esi.op, Assembler386.DESCR_FLOAT + 4*xmm2.op] double_byte_nums = [] for num in nums[3:6]: double_byte_nums.append((num & 0x7F) | 0x80) double_byte_nums.append(num >> 7) assert mc.content == (nums[:3] + double_byte_nums + nums[6:] + [assembler.CODE_STOP]) # also test rebuild_faillocs_from_descr(), which should not # reproduce the holes at all bytecode = lltype.malloc(rffi.UCHARP.TO, len(mc.content), flavor='raw') for i in range(len(mc.content)): assert 0 <= mc.content[i] <= 255 bytecode[i] = rffi.cast(rffi.UCHAR, mc.content[i]) bytecode_addr = rffi.cast(lltype.Signed, bytecode) newlocs = assembler.rebuild_faillocs_from_descr(bytecode_addr) assert ([loc.assembler() for loc in newlocs] == [loc.assembler() for loc in locs if loc is not None]) # finally, test make_boxes_from_latest_values(), which should # reproduce the holes expected_classes = [BoxInt, BoxPtr, BoxFloat, BoxInt, BoxPtr, BoxFloat, type(None), type(None), BoxInt, BoxPtr, BoxFloat] ptrvalues = {} S = lltype.GcStruct('S') for i, cls in enumerate(expected_classes): if cls == BoxInt: assembler.fail_boxes_int.setitem(i, 1000 + i) elif cls == BoxPtr: s = lltype.malloc(S) s_ref = lltype.cast_opaque_ptr(llmemory.GCREF, s) ptrvalues[i] = s_ref assembler.fail_boxes_ptr.setitem(i, s_ref) elif cls == BoxFloat: assembler.fail_boxes_float.setitem(i, 42.5 + i) boxes = assembler.make_boxes_from_latest_values(bytecode_addr) assert len(boxes) == len(locs) == len(expected_classes) for i, (box, expected_class) in enumerate(zip(boxes, expected_classes)): assert type(box) is expected_class if expected_class == BoxInt: assert box.value == 1000 + i elif expected_class == BoxPtr: assert box.value == ptrvalues[i] elif expected_class == BoxFloat: assert box.value == 42.5 + i
result = 0 return BoxInt(result) if rettype == REF: try: result = cpu.bh_call_r(func, descr, args_i, args_r, args_f) except Exception, e: metainterp.execute_raised(e) result = NULL return BoxPtr(result) if rettype == FLOAT or rettype == 'L': # *L*ong long try: result = cpu.bh_call_f(func, descr, args_i, args_r, args_f) except Exception, e: metainterp.execute_raised(e) result = longlong.ZEROF return BoxFloat(result) if rettype == VOID: try: cpu.bh_call_v(func, descr, args_i, args_r, args_f) except Exception, e: metainterp.execute_raised(e) return None raise AssertionError("bad rettype") do_call_loopinvariant = do_call do_call_may_force = do_call def do_getarrayitem_gc(cpu, _, arraybox, indexbox, arraydescr): array = arraybox.getref_base()
def test_frame_manager_basic(self): b0, b1 = newboxes(0, 1) fm = TFrameManager() loc0 = fm.loc(b0) assert fm.get_loc_index(loc0) == 0 # assert fm.get(b1) is None loc1 = fm.loc(b1) assert fm.get_loc_index(loc1) == 1 assert fm.get(b1) == loc1 # loc0b = fm.loc(b0) assert loc0b == loc0 # fm.loc(BoxInt()) assert fm.get_frame_depth() == 3 # f0 = BoxFloat() locf0 = fm.loc(f0) assert fm.get_loc_index(locf0) == 4 assert fm.get_frame_depth() == 6 # f1 = BoxFloat() locf1 = fm.loc(f1) assert fm.get_loc_index(locf1) == 6 assert fm.get_frame_depth() == 8 assert fm.used == [True, True, True, False, True, True, True, True] # fm.mark_as_free(b0) assert fm.used == [False, True, True, False, True, True, True, True] fm.mark_as_free(b0) assert fm.used == [False, True, True, False, True, True, True, True] fm.mark_as_free(f1) assert fm.used == [False, True, True, False, True, True, False, False] # fm.reserve_location_in_frame(1) assert fm.get_frame_depth() == 9 assert fm.used == [ False, True, True, False, True, True, False, False, True ] # assert b0 not in fm.bindings fm.set_binding(b0, loc0) assert b0 in fm.bindings assert fm.used == [ True, True, True, False, True, True, False, False, True ] # b3 = BoxInt() assert not fm.try_to_reuse_location(b3, loc0) assert fm.used == [ True, True, True, False, True, True, False, False, True ] # fm.mark_as_free(b0) assert fm.used == [ False, True, True, False, True, True, False, False, True ] assert fm.try_to_reuse_location(b3, loc0) assert fm.used == [ True, True, True, False, True, True, False, False, True ] # fm.mark_as_free(b0) # already free assert fm.used == [ True, True, True, False, True, True, False, False, True ] # fm.mark_as_free(b3) assert fm.used == [ False, True, True, False, True, True, False, False, True ] f3 = BoxFloat() assert not fm.try_to_reuse_location(f3, fm.frame_pos(0, FLOAT)) assert not fm.try_to_reuse_location(f3, fm.frame_pos(1, FLOAT)) assert not fm.try_to_reuse_location(f3, fm.frame_pos(2, FLOAT)) assert not fm.try_to_reuse_location(f3, fm.frame_pos(3, FLOAT)) assert not fm.try_to_reuse_location(f3, fm.frame_pos(4, FLOAT)) assert not fm.try_to_reuse_location(f3, fm.frame_pos(5, FLOAT)) assert fm.used == [ False, True, True, False, True, True, False, False, True ] assert fm.try_to_reuse_location(f3, fm.frame_pos(6, FLOAT)) assert fm.used == [ False, True, True, False, True, True, True, True, True ] # fm.used = [False] assert fm.try_to_reuse_location(BoxFloat(), fm.frame_pos(0, FLOAT)) assert fm.used == [True, True] # fm.used = [True] assert not fm.try_to_reuse_location(BoxFloat(), fm.frame_pos(0, FLOAT)) assert fm.used == [True]
def boxfloat(x): return BoxFloat(longlong.getfloatstorage(x))